Entity proxies.

This commit is contained in:
Dan Katz
2025-05-01 14:22:14 -04:00
parent 90dc2ff8fc
commit d5d35efe79
52 changed files with 650 additions and 290 deletions

View File

@@ -59,19 +59,14 @@ consteval auto template_of(info r) -> info;
consteval auto template_arguments_of(info r) -> vector<info>;
// member queries
consteval auto members_of(info class_type) -> vector<info>;
consteval auto bases_of(info class_type) -> vector<info>;
consteval auto static_data_members_of(info class_type) -> vector<info>;
consteval auto nonstatic_data_members_of(info class_type) -> vector<info>;
consteval auto subobjects_of(info class_type) -> vector<info>;
consteval auto members_of(info class_type, access_context ctx) -> vector<info>;
consteval auto bases_of(info class_type, access_context ctx) -> vector<info>;
consteval auto static_data_members_of(info class_type,
access_context ctx) -> vector<info>;
consteval auto nonstatic_data_members_of(info class_type,
access_context ctx) -> vector<info>;
consteval auto enumerators_of(info enum_type) -> vector<info>;
// public member queries (removal proposed by P3547)
consteval auto get_public_members(info) -> vector<info>;
consteval auto get_public_bases(info) -> vector<info>;
consteval auto get_static_data_members(info) -> vector<info>;
consteval auto get_nonstatic_data_members(info) -> vector<info>;
// substitute
template <reflection_range R = initializer_list<info>>
consteval auto can_substitute(info templ, R &&args) -> bool;
@@ -340,6 +335,9 @@ consteval auto tuple_element(size_t, info) -> info;
consteval auto variant_size(info) -> size_t;
consteval auto variant_alternative(size_t, info) -> info;
// entity proxies (PXYZ)
consteval auto is_entity_proxy(info) -> bool;
// function parameters (P3096)
consteval auto parameters_of(info) -> vector<info>;
consteval auto has_consistent_identifier(info) -> bool;
@@ -486,6 +484,7 @@ enum : unsigned {
__metafn_is_variable,
__metafn_is_type,
__metafn_is_alias,
__metafn_is_entity_proxy,
__metafn_is_complete_type,
__metafn_has_complete_definition,
__metafn_is_enumerable_type,
@@ -948,7 +947,10 @@ consteval auto is_complete_type(info r) -> bool {
return __metafunction(detail::__metafn_is_complete_type, r);
}
#if __has_feature(access_contexts)
// Returns whether the reflected class data member is an enumerator.
consteval auto is_enumerator(info r) -> bool {
return __metafunction(detail::__metafn_is_enumerator, r);
}
class access_context {
consteval access_context(info scope, info naming_class) noexcept
@@ -988,20 +990,16 @@ public:
};
consteval auto is_accessible(info r, access_context ctx) -> bool {
if (!is_class_member(r) && !is_base(r))
// Note: The accessibility of an enumerator may be looked up in a class
// for which it's not a member, since that enumerator could be
if (!is_class_member(r) && !is_base(r) && !is_enumerator(r))
return true;
return __metafunction(detail::__metafn_is_accessible,
r, ctx.scope(), ctx.naming_class());
}
#endif // __has_feature(access_contexts)
#if __has_feature(access_contexts)
consteval auto members_of(info r, access_context ctx) -> vector<info> {
#else
consteval auto members_of(info r) -> vector<info> {
#endif // __has_feature(access_contexts)
using iterator =
__range_of_infos::iterator<__range_of_infos::front_member_of_fn,
__range_of_infos::next_member_of_fn,
@@ -1010,14 +1008,10 @@ consteval auto members_of(info r) -> vector<info> {
auto rng = range{r};
vector<info> v {rng.begin(), rng.end()};
#if __has_feature(access_contexts)
return vector<info>{
from_range,
v | views::filter([=](info r) { return is_accessible(r, ctx); })
};
#else
return v;
#endif // __has_feature(access_contexts)
}
// Returns whether the reflected entity is a namespace.
@@ -1025,11 +1019,7 @@ consteval auto is_namespace(info r) -> bool {
return __metafunction(detail::__metafn_is_namespace, r);
}
#if __has_feature(access_contexts)
consteval auto bases_of(info r, access_context ctx) -> vector<info> {
#else
consteval auto bases_of(info r) -> vector<info> {
#endif // __has_feature(access_contexts)
if (is_namespace(r))
throw "Namespaces cannot have base classes";
@@ -1041,14 +1031,10 @@ consteval auto bases_of(info r) -> vector<info> {
auto rng = range{r};
vector<info> v {rng.begin(), rng.end()};
#if __has_feature(access_contexts)
return vector<info>{
from_range,
v | views::filter([=](info r) { return is_accessible(r, ctx); })
};
#else
return v;
#endif // __has_feature(access_contexts)
}
// Returns whether the reflected entity is a variable.
@@ -1056,38 +1042,22 @@ consteval auto is_variable(info r) -> bool {
return __metafunction(detail::__metafn_is_variable, r);
}
#if __has_feature(access_contexts)
consteval auto static_data_members_of(info r,
access_context ctx) -> vector<info> {
#else
consteval auto static_data_members_of(info r) -> vector<info> {
#endif // has_feature(access_contexts
if (is_namespace(r))
throw "Namespaces cannot have static data members";
#if __has_feature(access_contexts)
return members_of(r, ctx) |
#else
return members_of(r) |
#endif // __has_feature(access_contexts)
views::filter(is_variable) |
ranges::to<vector>();
}
#if __has_feature(access_contexts)
consteval auto nonstatic_data_members_of(info r,
access_context ctx) -> vector<info> {
#else
consteval auto nonstatic_data_members_of(info r) -> vector<info> {
#endif // __has_feature(access_contexts)
if (is_namespace(r))
throw "Namespaces cannot have non-static data members";
#if __has_feature(access_contexts)
return members_of(r, ctx) |
#else
return members_of(r) |
#endif // __has_feature(access_contexts)
views::filter(is_nonstatic_data_member) |
ranges::to<vector>();
}
@@ -1115,26 +1085,6 @@ consteval auto is_public(info r) -> bool {
return __metafunction(detail::__metafn_is_public, r);
}
#if !__has_feature(access_contexts)
consteval auto get_public_members(info r) -> vector<info> {
return members_of(r) | views::filter(is_public) | ranges::to<vector>();
}
consteval auto get_public_bases(info r) -> vector<info> {
return bases_of(r) | views::filter(is_public) | ranges::to<vector>();
}
consteval auto get_public_static_data_members(info r) -> vector<info> {
return static_data_members_of(r) | views::filter(is_public) |
ranges::to<vector>();
}
consteval auto get_public_nonstatic_data_members(info r) -> vector<info> {
return nonstatic_data_members_of(r) | views::filter(is_public) |
ranges::to<vector>();
}
#endif // !__has_feature(access_contexts)
// Returns whether the reflected entity is a protected class member.
consteval auto is_protected(info r) -> bool {
return __metafunction(detail::__metafn_is_protected, r);
@@ -1188,11 +1138,6 @@ consteval auto is_bit_field(info r) -> bool {
return __metafunction(detail::__metafn_is_bit_field, r);
}
// Returns whether the reflected class data member is an enumerator.
consteval auto is_enumerator(info r) -> bool {
return __metafunction(detail::__metafn_is_enumerator, r);
}
// Returns whether the reflected type is const-qualified, or if the reflected
// entity is of such a type.
consteval auto is_const(info r) -> bool {
@@ -1275,16 +1220,23 @@ consteval auto is_type(info r) -> bool {
return __metafunction(detail::__metafn_is_type, r);
}
// Returns true if the reflected entity is an alias.
// Returns true if the reflected entity is a type alias.
consteval auto is_type_alias(info r) -> bool {
return is_type(r) && __metafunction(detail::__metafn_is_alias, r);
}
// Returns true if the reflected entity is an alias.
// Returns true if the reflected entity is a namespace alias.
consteval auto is_namespace_alias(info r) -> bool {
return is_namespace(r) && __metafunction(detail::__metafn_is_alias, r);
}
#if __has_feature(entity_proxy_reflection)
// Returns true if the reflected entity is an entity proxy.
consteval auto is_entity_proxy(info r) -> bool {
return __metafunction(detail::__metafn_is_entity_proxy, r);
}
#endif
// Returns true if the reflected entity is a template.
consteval auto is_template(info r) -> bool {
return __metafunction(detail::__metafn_is_template, r);
@@ -2089,11 +2041,7 @@ namespace detail {
template <class T> struct __wrap_workaround { using type = T; };
consteval auto __workaround_expand_compiler_builtins(info type) -> info {
auto r = substitute(^^__wrap_workaround, {type});
#if __has_feature(access_contexts)
return dealias(members_of(r, access_context::unchecked())[0]);
#else
return dealias(members_of(r)[0]);
#endif
}
} // namespace detail
@@ -2193,8 +2141,6 @@ consteval auto annotate(info entity, info val) -> info {
#endif // __has_feature(annotation_attributes)
#if __has_feature(access_contexts)
consteval auto has_inaccessible_nonstatic_data_members(
info r,
access_context ctx) -> bool {
@@ -2208,8 +2154,6 @@ consteval auto has_inaccessible_bases(info r, access_context ctx) -> bool {
[=](info b) { return is_accessible(b, ctx); });
}
#endif // __has_feature(access_contexts)
// ===================================================
// Other bespoke functions (not proposed at this time)
// ===================================================
@@ -2310,7 +2254,6 @@ consteval auto define_class(info class_type, R &&members) -> info {
return define_aggregate(class_type, members);
}
#if __has_feature(access_contexts)
[[deprecated("P3547 requires an 'access_context' argument "
"(compile with '-fno-access-contexts' to disable this warning)")]]
consteval auto members_of(info r) -> vector<info> {
@@ -2340,8 +2283,6 @@ consteval auto has_complete_definition(info r) -> bool {
return __metafunction(detail::__metafn_has_complete_definition, r);
}
#endif // __has_feature(access_contexts)
_LIBCPP_END_NAMESPACE_REFLECTION_V2
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -2692,12 +2633,8 @@ consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
string_t result = render<type_of(R)>() + string_constant("{");
size_t Idx = 0;
#if __has_feature(access_contexts)
[:expand(nonstatic_data_members_of(type_of(R),
access_context::unchecked())):] >>
#else
[:expand(nonstatic_data_members_of(type_of(R))):] >>
#endif
[&]<auto Mem> {
if (Idx++ > 0) result += string_constant(", ");
result += tprint_impl::render<reflect_value([:R:].[:Mem:])>();

View File

@@ -23,6 +23,7 @@
#include <print>
constexpr auto ctx = std::meta::access_context::unchecked();
// =========================
// completion_with_no_fields
@@ -43,9 +44,9 @@ consteval {
static_assert(is_complete_type(^^S));
static_assert(is_complete_type(^^C));
static_assert(is_complete_type(^^U));
static_assert(nonstatic_data_members_of(^^S).size() == 0);
static_assert(nonstatic_data_members_of(^^C).size() == 0);
static_assert(nonstatic_data_members_of(^^U).size() == 0);
static_assert(nonstatic_data_members_of(^^S, ctx).size() == 0);
static_assert(nonstatic_data_members_of(^^C, ctx).size() == 0);
static_assert(nonstatic_data_members_of(^^U, ctx).size() == 0);
S s;
C c;
@@ -69,17 +70,18 @@ consteval {
}
static_assert(is_complete_type(^^S));
// unnamed bitfields are not nonstatic data members.
static_assert(nonstatic_data_members_of(^^S).size() == 3);
static_assert(nonstatic_data_members_of(^^S, ctx).size() == 3);
static_assert(alignment_of(^^S::count) == 16);
static_assert(bit_size_of(nonstatic_data_members_of(^^S)[2]) == 5);
static_assert((members_of(^^S) | std::views::filter(std::meta::is_bit_field) |
static_assert(bit_size_of(nonstatic_data_members_of(^^S, ctx)[2]) == 5);
static_assert((members_of(^^S, ctx) |
std::views::filter(std::meta::is_bit_field) |
std::views::transform(std::meta::bit_size_of) |
std::ranges::to<std::vector>()) == std::vector<size_t> {0, 5});
constexpr S s = {14, true, 11};
static_assert(s.count == 14);
static_assert(s.flag);
static_assert(s.[:nonstatic_data_members_of(^^S)[2]:] == 11);
static_assert(s.[:nonstatic_data_members_of(^^S, ctx)[2]:] == 11);
struct Empty {};
struct WithEmpty;
@@ -105,9 +107,9 @@ consteval {
});
}
static_assert(is_complete_type(^^C));
static_assert(nonstatic_data_members_of(^^C).size() == 2);
static_assert(nonstatic_data_members_of(^^C, ctx).size() == 2);
static_assert(
(members_of(^^C) |
(members_of(^^C, ctx) |
std::views::filter(std::meta::is_nonstatic_data_member) |
std::views::filter(std::meta::is_public) |
std::ranges::to<std::vector>()).size() == 2);
@@ -130,9 +132,9 @@ consteval {
}
static_assert(is_complete_type(^^U));
static_assert(size_of(^^U) == size_of(^^U::count));
static_assert(nonstatic_data_members_of(^^U).size() == 2);
static_assert(nonstatic_data_members_of(^^U, ctx).size() == 2);
static_assert(
(members_of(^^U) |
(members_of(^^U, ctx) |
std::views::filter(std::meta::is_nonstatic_data_member) |
std::ranges::to<std::vector>()).size() == 2);
@@ -164,11 +166,11 @@ consteval {
});
}
static_assert(nonstatic_data_members_of(^^S<0>).size() == 0);
static_assert(nonstatic_data_members_of(^^S<1>).size() == 1);
static_assert(nonstatic_data_members_of(^^S<0>, ctx).size() == 0);
static_assert(nonstatic_data_members_of(^^S<1>, ctx).size() == 1);
static_assert(type_of(^^S<1>::mem) == ^^int);
static_assert(nonstatic_data_members_of(^^S<2>).size() == 0);
static_assert(nonstatic_data_members_of(^^S<3>).size() == 1);
static_assert(nonstatic_data_members_of(^^S<2>, ctx).size() == 0);
static_assert(nonstatic_data_members_of(^^S<3>, ctx).size() == 1);
static_assert(type_of(^^S<3>::mem) == ^^bool);
static_assert(!is_complete_type(^^S<4>));
} // namespace template_specialization_completion
@@ -190,7 +192,7 @@ consteval {
data_member_spec(^^int, {.name="count"})>();
}
static_assert(is_complete_type(^^S));
static_assert(nonstatic_data_members_of(^^S).size() == 2);
static_assert(nonstatic_data_members_of(^^S, ctx).size() == 2);
S s;
} // namespace completion_of_dependent_type
@@ -261,7 +263,7 @@ consteval {
static_assert(type_of(^^foo::i) == ^^int);
static_assert(type_of(^^foo::b) == ^^bool);
static_assert(nonstatic_data_members_of(^^foo).size() == 2);
static_assert(nonstatic_data_members_of(^^foo, ctx).size() == 2);
} // namespace with_non_contiguous_range
// =============================
@@ -277,9 +279,10 @@ consteval {
data_member_spec(^^int, {.name=u8identifier_of(^^Kühl)})
});
}
static_assert(u8identifier_of(nonstatic_data_members_of(^^Cls1)[0]) ==
static_assert(u8identifier_of(nonstatic_data_members_of(^^Cls1, ctx)[0]) ==
u8"Kühl");
static_assert(identifier_of(nonstatic_data_members_of(^^Cls1)[0]) == "Kühl");
static_assert(identifier_of(nonstatic_data_members_of(^^Cls1, ctx)[0]) ==
"Kühl");
} // namespace utf8_identifier_of_roundtrip
// ===========================

View File

@@ -21,6 +21,9 @@
#include <print>
constexpr auto ctx = std::meta::access_context::unchecked();
// ===========
// well_formed
// ===========
@@ -185,7 +188,8 @@ struct S1 {
namespace speculative_and_trial_evaluations {
struct S1;
consteval auto fn() {
return members_of(define_aggregate(^^S1, {})).empty() ? new int : nullptr;
return members_of(define_aggregate(^^S1, {}), ctx).empty() ? new int :
nullptr;
};
consteval void fn2() {

View File

@@ -18,6 +18,9 @@
#include <experimental/meta>
#include <tuple>
constexpr auto ctx = std::meta::access_context::current();
struct type {};
using alias = type;
@@ -558,8 +561,8 @@ static_assert(is_complete_type(^^IncompleteTClsAlias<int>));
struct Base {};
struct Derived : Base {};
static_assert(!is_base(^^Base));
static_assert(!is_type(bases_of(^^Derived)[0]));
static_assert(is_base(bases_of(^^Derived)[0]));
static_assert(!is_type(bases_of(^^Derived, ctx)[0]));
static_assert(is_base(bases_of(^^Derived, ctx)[0]));
// =================================================
// test_is_structured_binding_and_related_edge_cases
@@ -630,29 +633,29 @@ struct S3 { S3(); };
S3::S3() {}
static_assert(
(members_of(^^S1) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_provided) |
std::ranges::to<std::vector>()).size() == 0);
(members_of(^^S1, ctx) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_provided) |
std::ranges::to<std::vector>()).size() == 0);
static_assert(
(members_of(^^S1) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_declared) |
std::ranges::to<std::vector>()).size() == 0);
(members_of(^^S1, ctx) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_declared) |
std::ranges::to<std::vector>()).size() == 0);
static_assert(
(members_of(^^S2) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_provided) |
std::ranges::to<std::vector>()).size() == 0);
(members_of(^^S2, ctx) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_provided) |
std::ranges::to<std::vector>()).size() == 0);
static_assert(
(members_of(^^S2) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_declared) |
std::ranges::to<std::vector>()).size() == 2);
(members_of(^^S2, ctx) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_declared) |
std::ranges::to<std::vector>()).size() == 2);
static_assert(
(members_of(^^S3) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_provided) |
std::ranges::to<std::vector>()).size() == 1);
(members_of(^^S3, ctx) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_provided) |
std::ranges::to<std::vector>()).size() == 1);
static_assert(
(members_of(^^S3) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_declared) |
std::ranges::to<std::vector>()).size() == 1);
(members_of(^^S3, ctx) | std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_declared) |
std::ranges::to<std::vector>()).size() == 1);
} // namespace test_is_user_provided_and_declared

View File

@@ -0,0 +1,88 @@
//===----------------------------------------------------------------------===//
//
// Copyright 2024 Bloomberg Finance L.P.
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
// ADDITIONAL_COMPILE_FLAGS: -freflection
// ADDITIONAL_COMPILE_FLAGS: -fentity-proxy-reflection
// ADDITIONAL_COMPILE_FLAGS: -fannotation-attributes
// <experimental/reflection>
//
// [reflection]
#include <experimental/meta>
constexpr auto ctx = std::meta::access_context::current();
constexpr auto unchecked = std::meta::access_context::unchecked();
struct Base {};
enum Enum { Red };
struct A {
int m;
struct Inner : Base { int m; };
using Alias = std::vector<int>;
};
struct B : private A { using A::m; using A::Inner; using A::Alias; };
struct C { template <typename> struct TCls {}; struct Inner {}; int m; };
struct D : C { using C::TCls; using C::Inner; private: using C::m; };
struct E { using Enum::Red; };
namespace InnerNS { using Enum::Red; }
struct F { int m; int n; };
struct G : F { [[=32]] using F::m; public: using F::n; };
struct H : G { using G::n; };
static_assert(is_accessible(^^A::Inner, ctx));
static_assert(!is_accessible(^^A::Inner, ctx.via(^^B)));
static_assert(is_accessible(^^B::Inner, ctx));
static_assert(is_entity_proxy(^^B::Inner));
static_assert(!is_entity_proxy(^^A::Inner));
static_assert(nonstatic_data_members_of(dealias(^^B::Inner), ctx).size() == 1);
static_assert(bases_of(dealias(^^B::Inner), ctx).size() == 1);
static_assert(template_arguments_of(dealias(^^B::Alias)) ==
std::vector {^^int, ^^std::allocator<int>});
static_assert(identifier_of(^^B::Alias) == "Alias");
static_assert(source_location_of(^^B::Alias).line() == 34);
static_assert(type_of(dealias(^^B::m)) == ^^int);
static_assert(parent_of(^^B::m) == ^^B);
static_assert(dealias(^^B::Alias) == ^^std::vector<int>);
static_assert(template_of(dealias(^^B::Alias)) == ^^std::vector);
static_assert(has_template_arguments(dealias(^^B::Alias)));
static_assert(!has_template_arguments(^^B::Alias));
static_assert(substitute(dealias(^^D::TCls), {^^D::Inner}) ==
^^C::TCls<C::Inner>);
static_assert(identifier_of(members_of(^^D, unchecked)[2]) == "m");
static_assert(is_private(members_of(^^D, unchecked)[2]));
static_assert(!is_class_member(^^Enum::Red));
static_assert(is_class_member(^^E::Red));
static_assert(is_entity_proxy(^^E::Red));
static_assert(dealias(^^E::Red) == ^^Enum::Red);
static_assert(!is_namespace_member(^^Enum::Red));
static_assert(is_namespace_member(^^InnerNS::Red));
static_assert(extract<int>(annotations_of(^^G::m)[0]) == 32);
static_assert(!is_access_specified(^^G::m));
static_assert(is_access_specified(^^G::n));
static_assert(dealias(^^H::n) == ^^F::n);
int main() { }

View File

@@ -63,8 +63,9 @@ export struct Base {
static constexpr int K = 12;
};
export struct Child : private Empty, Base {};
export constexpr auto rBase1 = bases_of(^^Child)[0];
export constexpr auto rBase2 = bases_of(^^Child)[1];
constexpr auto ctx = std::meta::access_context::unchecked();
export constexpr auto rBase1 = bases_of(^^Child, ctx)[0];
export constexpr auto rBase2 = bases_of(^^Child, ctx)[1];
// =================================
// Reflections of data members specs

View File

@@ -9,7 +9,7 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
// ADDITIONAL_COMPILE_FLAGS: -freflection -faccess-contexts
// ADDITIONAL_COMPILE_FLAGS: -freflection
// <experimental/reflection>
//

View File

@@ -19,6 +19,8 @@
#include <experimental/meta>
constexpr auto ctx = std::meta::access_context::unchecked();
// ==========================
// class_or_namespace_members
// ==========================
@@ -214,8 +216,8 @@ struct B1 {};
struct B2 {};
struct D : B1, virtual B2 { };
static_assert(!is_virtual(bases_of(^^D)[0]));
static_assert(is_virtual(bases_of(^^D)[1]));
static_assert(!is_virtual(bases_of(^^D, ctx)[0]));
static_assert(is_virtual(bases_of(^^D, ctx)[1]));
static_assert(!is_virtual(^^B1));
static_assert(!is_virtual(^^B2));
@@ -241,12 +243,14 @@ struct S {
template <typename T> void TMemFn();
struct Inner {};
};
static_assert((members_of(^^S) | std::views::filter(std::meta::is_constructor) |
std::ranges::to<std::vector>()).size() == 4);
static_assert((members_of(^^S) | std::views::filter(std::meta::is_destructor) |
std::ranges::to<std::vector>()).size() == 1);
static_assert((members_of(^^S, ctx) |
std::views::filter(std::meta::is_constructor) |
std::ranges::to<std::vector>()).size() == 4);
static_assert((members_of(^^S, ctx) |
std::views::filter(std::meta::is_destructor) |
std::ranges::to<std::vector>()).size() == 1);
static_assert(
(members_of(^^S) |
(members_of(^^S, ctx) |
std::views::filter(std::meta::is_special_member_function) |
std::ranges::to<std::vector>()).size() == 6);
@@ -350,32 +354,32 @@ static_assert(!is_explicit(^^S::mem));
static_assert(!is_explicit(^^S::memfn));
static_assert(!is_explicit(^^S::TMemFn));
static_assert(
!is_explicit((members_of(^^S) |
!is_explicit((members_of(^^S, ctx) |
std::views::filter(std::meta::is_constructor) |
std::ranges::to<std::vector>())[0]));
static_assert(
!is_explicit((members_of(^^S) |
!is_explicit((members_of(^^S, ctx) |
std::views::filter(std::meta::is_constructor_template) |
std::ranges::to<std::vector>())[0]));
static_assert(
is_explicit((members_of(^^S) |
is_explicit((members_of(^^S, ctx) |
std::views::filter(std::meta::is_constructor) |
std::ranges::to<std::vector>())[1]));
static_assert(!is_explicit(^^S::operator int));
static_assert(
!is_explicit((members_of(^^S) |
!is_explicit((members_of(^^S, ctx) |
std::views::filter(std::meta::is_template) |
std::ranges::to<std::vector>())[3]));
static_assert(is_explicit(^^S::operator bool));
// P2996R3 removes support for checking 'explicit' on templates.
static_assert(
!is_explicit((members_of(^^S) |
!is_explicit((members_of(^^S, ctx) |
std::views::filter(std::meta::is_constructor) |
std::ranges::to<std::vector>())[3]));
static_assert(
!is_explicit((members_of(^^S) |
!is_explicit((members_of(^^S, ctx) |
std::views::filter(std::meta::is_template) |
std::ranges::to<std::vector>())[4]));
@@ -768,27 +772,30 @@ struct S {
};
static_assert(
(members_of(^^S) | std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_default_constructor) |
std::ranges::to<std::vector>()) ==
(members_of(^^S, ctx) |
std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_default_constructor) |
std::ranges::to<std::vector>()) ==
std::vector {true, true,
false, false, false, false, false,
false, false, false, false, false,
false});
static_assert(
(members_of(^^S) | std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_copy_constructor) |
std::ranges::to<std::vector>()) ==
(members_of(^^S, ctx) |
std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_copy_constructor) |
std::ranges::to<std::vector>()) ==
std::vector {false, false,
true, true, true, true, true,
false, false, false, false, false,
false});
static_assert(
(members_of(^^S) | std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_move_constructor) |
std::ranges::to<std::vector>()) ==
(members_of(^^S, ctx) |
std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_move_constructor) |
std::ranges::to<std::vector>()) ==
std::vector {false, false,
false, false, false, false, false,
true, true, true, true, true,
@@ -818,27 +825,29 @@ struct S {
};
static_assert(
(members_of(^^S) | std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_assignment) |
std::ranges::to<std::vector>()) ==
(members_of(^^S, ctx) | std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_assignment) |
std::ranges::to<std::vector>()) ==
std::vector {true, true, true, true,
true, true, true, true,
true,
false});
static_assert(
(members_of(^^S) | std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_copy_assignment) |
std::ranges::to<std::vector>()) ==
(members_of(^^S, ctx) |
std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_copy_assignment) |
std::ranges::to<std::vector>()) ==
std::vector {true, true, true, true,
false, false, false, false,
false,
false});
static_assert(
(members_of(^^S) | std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_move_assignment) |
std::ranges::to<std::vector>()) ==
(members_of(^^S, ctx) |
std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::is_move_assignment) |
std::ranges::to<std::vector>()) ==
std::vector {false, false, false, false,
true, true, true, true,
false,
@@ -858,7 +867,7 @@ struct S {
};
static_assert(
(nonstatic_data_members_of(^^S) |
(nonstatic_data_members_of(^^S, ctx) |
std::views::transform(std::meta::has_default_member_initializer) |
std::ranges::to<std::vector>()) == std::vector {false, true, true});
@@ -957,7 +966,7 @@ int operator""_b();
constexpr auto conversion_template =
(members_of(^^T) | std::views::filter(std::meta::is_template)).front();
(members_of(^^T, ctx) | std::views::filter(std::meta::is_template)).front();
static_assert(is_operator_function(^^S::operator+));
static_assert(is_operator_function(^^operator&&));

View File

@@ -10,7 +10,6 @@
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
// ADDITIONAL_COMPILE_FLAGS: -freflection
// ADDITIONAL_COMPILE_FLAGS: -faccess-contexts
// <experimental/reflection>
//

View File

@@ -9,7 +9,7 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
// ADDITIONAL_COMPILE_FLAGS: -freflection -faccess-contexts
// ADDITIONAL_COMPILE_FLAGS: -freflection
// <experimental/reflection>
//

View File

@@ -10,7 +10,7 @@
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
// ADDITIONAL_COMPILE_FLAGS: -fblocks
// ADDITIONAL_COMPILE_FLAGS: -freflection -faccess-contexts
// ADDITIONAL_COMPILE_FLAGS: -freflection
// ADDITIONAL_COMPILE_FLAGS: -fexpansion-statements
// ADDITIONAL_COMPILE_FLAGS: -Wno-inconsistent-missing-override

View File

@@ -19,6 +19,8 @@
#include <experimental/meta>
constexpr auto ctx = std::meta::access_context::unchecked();
static_assert(u8display_string_of(^^::) == u8"(global-namespace)");
static_assert(display_string_of(^^::) == "(global-namespace)");
static_assert(!has_identifier(^^::));
@@ -148,7 +150,7 @@ struct Cls : Base {
enum class EnumCls { B };
};
static_assert(identifier_of(^^Cls) == "Cls");
static_assert(!has_identifier(bases_of(^^Cls)[0]));
static_assert(!has_identifier(bases_of(^^Cls, ctx)[0]));
static_assert(identifier_of(^^Cls::Alias) == "Alias");
static_assert(has_identifier(^^Cls::Alias));
static_assert(identifier_of(^^Cls::mem) == "mem");
@@ -157,18 +159,18 @@ static_assert(identifier_of(^^Cls::sfn) == "sfn");
static_assert(identifier_of(^^Cls::Inner) == "Inner");
static_assert(
!has_identifier((members_of(^^Cls) |
!has_identifier((members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_constructor)).front()));
static_assert(
!has_identifier((members_of(^^Cls) |
!has_identifier((members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_constructor_template)).front()));
static_assert(
!has_identifier((members_of(^^Cls) |
!has_identifier((members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_destructor)).front()));
static_assert(!has_identifier(^^Cls::operator bool));
static_assert(
!has_identifier(
(members_of(^^Cls) |
(members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_template) |
std::ranges::to<std::vector>())[5]));
static_assert(identifier_of(^^Cls::TInner) == "TInner");
@@ -180,34 +182,34 @@ static_assert(identifier_of(^^Cls::Enum::B) == "B");
static_assert(identifier_of(^^Cls::EnumCls) == "EnumCls");
static_assert(identifier_of(^^Cls::EnumCls::B) == "B");
static_assert(display_string_of(^^Cls) == "Cls");
static_assert(display_string_of(bases_of(^^Cls)[0]) == "Base");
static_assert(display_string_of(bases_of(^^Cls, ctx)[0]) == "Base");
static_assert(display_string_of(^^Cls::Alias) == "Alias");
static_assert(display_string_of(^^Cls::mem) == "mem");
static_assert(display_string_of(^^Cls::memfn) == "memfn");
static_assert(display_string_of(^^Cls::sfn) == "sfn");
static_assert(display_string_of(^^Cls::Inner) == "Inner");
static_assert(
(members_of(^^Cls) |
(members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_provided) |
std::views::transform(std::meta::display_string_of) |
std::ranges::to<std::vector>()) ==
std::vector<std::string_view>{"Cls"});
static_assert(
(members_of(^^Cls) |
(members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_constructor_template) |
std::views::transform(std::meta::display_string_of) |
std::ranges::to<std::vector>()) ==
std::vector<std::string_view>{"Cls"});
static_assert(
(members_of(^^Cls) |
(members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_destructor) |
std::views::transform(std::meta::display_string_of) |
std::ranges::to<std::vector>()) ==
std::vector<std::string_view>{"~Cls"});
static_assert(display_string_of(^^Cls::operator bool) == "operator bool");
static_assert(
(members_of(^^Cls) |
(members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_template) |
std::views::transform(std::meta::display_string_of) |
std::ranges::to<std::vector>())[5] ==

View File

@@ -37,8 +37,9 @@ consteval {
make_named_tuple(^^R, {{^^int, "x"}, {^^double, "y"}});
}
static_assert(type_of(nonstatic_data_members_of(^^R)[0]) == ^^int);
static_assert(type_of(nonstatic_data_members_of(^^R)[1]) == ^^double);
constexpr auto ctx = std::meta::access_context::unchecked();
static_assert(type_of(nonstatic_data_members_of(^^R, ctx)[0]) == ^^int);
static_assert(type_of(nonstatic_data_members_of(^^R, ctx)[1]) == ^^double);
int main() {
[[maybe_unused]] auto r = R{.x=1, .y=2.0};

View File

@@ -58,10 +58,10 @@ consteval std::meta::info enrich(std::meta::info r) {
// the first constructor. The copy/move constructors are added at the }, so
// will be the last ones in the list.
std::array ctors = {
(members_of(^^Choices) |
(members_of(^^Choices, std::meta::access_context::current()) |
std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_provided)).front()...,
(members_of(^^unmatched) |
(members_of(^^unmatched, std::meta::access_context::current()) |
std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_provided)).front()
};

View File

@@ -32,8 +32,9 @@ struct member_descriptor
// returns std::array<member_descriptor, N>
template <typename S>
consteval auto get_layout() {
auto members = nonstatic_data_members_of(^^S);
constexpr size_t sz = nonstatic_data_members_of(^^S).size();
constexpr auto ctx = std::meta::access_context::current();
auto members = nonstatic_data_members_of(^^S, ctx);
constexpr size_t sz = nonstatic_data_members_of(^^S, ctx).size();
std::array<member_descriptor, sz> layout;
for (int i = 0; i < members.size(); ++i) {
layout[i] = {

View File

@@ -61,8 +61,9 @@ consteval {
make_named_tuple(^^R, pair<int, "x">{}, pair<double, "y">{});
}
static_assert(type_of(nonstatic_data_members_of(^^R)[0]) == ^^int);
static_assert(type_of(nonstatic_data_members_of(^^R)[1]) == ^^double);
constexpr auto ctx = std::meta::access_context::current();
static_assert(type_of(nonstatic_data_members_of(^^R, ctx)[0]) == ^^int);
static_assert(type_of(nonstatic_data_members_of(^^R, ctx)[1]) == ^^double);
int main() {
[[maybe_unused]] auto r = R{.x=1, .y=2.0};

View File

@@ -9,7 +9,7 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
// ADDITIONAL_COMPILE_FLAGS: -freflection -faccess-contexts
// ADDITIONAL_COMPILE_FLAGS: -freflection
// ADDITIONAL_COMPILE_FLAGS: -fexpansion-statements
// ADDITIONAL_COMPILE_FLAGS: -Wno-inconsistent-missing-override

View File

@@ -10,7 +10,6 @@
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
// ADDITIONAL_COMPILE_FLAGS: -freflection -fexpansion-statements
// ADDITIONAL_COMPILE_FLAGS: -faccess-contexts
// ADDITIONAL_COMPILE_FLAGS: -Wno-inconsistent-missing-override
// <experimental/reflection>

View File

@@ -21,7 +21,8 @@
struct S { unsigned i:2, j:6; };
consteval auto member_number(int n) {
return std::meta::nonstatic_data_members_of(^^S)[n];
constexpr auto ctx = std::meta::access_context::current();
return std::meta::nonstatic_data_members_of(^^S, ctx)[n];
}
int main() {

View File

@@ -21,7 +21,8 @@
struct S { unsigned i:2, j:6; };
consteval auto member_named(std::string_view name) {
for (std::meta::info field : nonstatic_data_members_of(^^S)) {
constexpr auto ctx = std::meta::access_context::current();
for (std::meta::info field : nonstatic_data_members_of(^^S, ctx)) {
if (identifier_of(field) == name) return field;
}
std::unreachable();

View File

@@ -38,7 +38,8 @@ template<typename... Ts> struct Tuple {
};
consteval std::meta::info get_nth_field(std::meta::info r, std::size_t n) {
return nonstatic_data_members_of(r)[n];
constexpr auto ctx = std::meta::access_context::current();
return nonstatic_data_members_of(r, ctx)[n];
}
template<std::size_t I, typename... Ts>

View File

@@ -29,7 +29,9 @@ struct struct_of_arrays_impl {
struct impl;
consteval {
std::vector<std::meta::info> old_members = nonstatic_data_members_of(^^T);
constexpr auto ctx = std::meta::access_context::current();
std::vector<std::meta::info> old_members = nonstatic_data_members_of(^^T,
ctx);
std::vector<std::meta::info> new_members = {};
for (std::meta::info member : old_members) {
auto array_type = substitute(^^std::array, {

View File

@@ -32,8 +32,9 @@ consteval auto struct_to_tuple_type(std::meta::info type) -> std::meta::info {
return substitute(^^std::remove_cvref_t, {r});
};
constexpr auto ctx = std::meta::access_context::current();
return substitute(^^std::tuple,
nonstatic_data_members_of(type)
nonstatic_data_members_of(type, ctx)
| std::views::transform(std::meta::type_of)
| std::views::transform(remove_cvref)
| std::ranges::to<std::vector>());
@@ -49,7 +50,8 @@ consteval auto get_struct_to_tuple_helper() {
using To = [: struct_to_tuple_type(^^From) :];
std::vector args = {^^To, ^^From};
for (auto mem : nonstatic_data_members_of(^^From)) {
constexpr auto ctx = std::meta::access_context::current();
for (auto mem : nonstatic_data_members_of(^^From, ctx)) {
args.push_back(reflect_value(mem));
}

View File

@@ -10,7 +10,6 @@
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
// ADDITIONAL_COMPILE_FLAGS: -freflection -fexpansion-statements
// ADDITIONAL_COMPILE_FLAGS: -faccess-contexts
// ADDITIONAL_COMPILE_FLAGS: -Wno-inconsistent-missing-override
// <experimental/reflection>

View File

@@ -19,6 +19,8 @@
#include <experimental/meta>
constexpr auto ctx = std::meta::access_context::unchecked();
// =================
// with_no_arguments
// =================
@@ -84,7 +86,8 @@ struct Cls {
};
constexpr auto ctor =
(members_of(^^Cls) | std::views::filter(std::meta::is_constructor)).front();
(members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_constructor)).front();
static_assert(parameters_of(ctor).size() == 1);
static_assert(type_of(parameters_of(ctor)[0]) == ^^int);
static_assert(identifier_of(parameters_of(ctor)[0]) == "a");
@@ -94,7 +97,8 @@ static_assert(!is_explicit_object_parameter(parameters_of(ctor)[0]));
static_assert(!has_ellipsis_parameter(ctor));
constexpr auto dtor =
(members_of(^^Cls) | std::views::filter(std::meta::is_destructor)).front();
(members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_destructor)).front();
static_assert(parameters_of(dtor).size() == 0);
static_assert(!has_ellipsis_parameter(dtor));

View File

@@ -21,6 +21,8 @@
#include <array>
constexpr auto ctx = std::meta::access_context::unchecked();
// ===============
// basic_functions
// ===============
@@ -175,12 +177,12 @@ struct Cls {
};
constexpr auto ctor =
(members_of(^^Cls) |
(members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_constructor) |
std::views::filter(std::meta::is_user_provided)).front();
constexpr auto ctor_template =
(members_of(^^Cls) |
(members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_constructor_template)).front();
// Non-template constructor.

View File

@@ -18,6 +18,8 @@
#include <experimental/meta>
constexpr auto ctx = std::meta::access_context::current();
// ============
// find_type_of
// ============
@@ -104,7 +106,7 @@ static_assert(parent_of(^^Cls::mem) == ^^Cls);
static_assert(parent_of(^^Cls::memfn) == ^^Cls);
static_assert(parent_of(^^Cls::sfn) == ^^Cls);
static_assert(parent_of(^^Cls::Alias) == ^^Cls);
static_assert(parent_of(bases_of(^^Cls)[0]) == ^^Cls);
static_assert(parent_of(bases_of(^^Cls, ctx)[0]) == ^^Cls);
static_assert(parent_of(^^Cls::TSMem) == ^^Cls);
static_assert(parent_of(^^Cls::TSMem<int>) == ^^Cls);

View File

@@ -39,8 +39,9 @@ void foo(int param) {
static_assert(source_location_of(^^S).function_name() == FnName);
struct C : S {};
static_assert(source_location_of(bases_of(^^C)[0]).line() ==
std::source_location::current().line() - 2);
constexpr auto ctx = std::meta::access_context::current();
static_assert(source_location_of(bases_of(^^C, ctx)[0]).line() ==
std::source_location::current().line() - 3);
// Check that it works with aliases.
using intAlias = int;

View File

@@ -19,6 +19,8 @@
#include <experimental/meta>
constexpr auto ctx = std::meta::access_context::unchecked();
// =============
// static_arrays
// =============
@@ -42,7 +44,8 @@ static_assert(objs.size() == 3);
static_assert(objs[0].k == 5 && objs[1].k == 7 && objs[2].k == 9);
constexpr auto infos = std::define_static_array(
nonstatic_data_members_of(^^Cls));
nonstatic_data_members_of(^^Cls,
ctx));
static_assert(infos.size() == 1);
static_assert(infos[0] == ^^Cls::k);
} // namespace static_arrays

View File

@@ -24,6 +24,9 @@
#include <utility>
#include <vector>
constexpr auto ctx = std::meta::access_context::unchecked();
template <int K>
constexpr std::meta::info RVal = std::meta::reflect_value(K);
@@ -369,7 +372,8 @@ namespace with_reflection_of_declaration {
template <int V> constexpr int Plus1 = V + 1;
struct S { static constexpr int val = 4; };
static_assert([:substitute(^^Plus1, {static_data_members_of(^^S)[0]}):] == 5);
static_assert([:substitute(^^Plus1,
{static_data_members_of(^^S, ctx)[0]}):] == 5);
} // namespace with_reflection_of_declaration
// ==========================
@@ -455,7 +459,7 @@ namespace non_type_ref_regression_test {
class Cls { static constexpr int priv = 11; };
template <auto &V> static constexpr auto &Value = V;
static_assert([:substitute(^^Value, {members_of(^^Cls)[0]}):] == 11);
static_assert([:substitute(^^Value, {members_of(^^Cls, ctx)[0]}):] == 11);
} // namespace non_type_ref_regression_test
int main() { }

View File

@@ -18,6 +18,8 @@
#include <experimental/meta>
constexpr auto ctx = std::meta::access_context::unchecked();
template <typename P1, auto P2, template <typename...> class P3>
struct TCls {
template <typename> struct TInnerCls {};
@@ -327,9 +329,9 @@ template <auto R> void fn() { }
void fn() {
class S { S(); ~S(); };
fn<(members_of(^^S) |
fn<(members_of(^^S, ctx) |
std::views::filter(std::meta::is_constructor)).front()>();
fn<(members_of(^^S) |
fn<(members_of(^^S, ctx) |
std::views::filter(std::meta::is_destructor)).front()>();
}
} // namespace bb_clang_p2996_issue_54_regression_test

View File

@@ -144,7 +144,8 @@ static_assert(CheckValueIs<42>([]() {
static_assert(
CheckValueIs<3>(
static_data_members_of(substitute(^^TCls,
{std::meta::reflect_value(3)}))[0]));
{std::meta::reflect_value(3)}),
std::meta::access_context::unchecked())[0]));
} // namespace extract_results
// =========