diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index 2010474b80c..549676f3cb5 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -6007,6 +6007,415 @@ eval_is_accessible (location_t loc, const constexpr_ctx *ctx, tree r, return boolean_true_node; } +/* Returns true if R is C-members-of-representable from + current point P. */ + +static bool +members_of_representable_p (tree c, tree r) +{ + if (TREE_CODE (r) == CONST_DECL) + return false; + if (LAMBDA_TYPE_P (c) && !LAMBDA_FUNCTION_P (r)) + return false; + if (TYPE_P (r)) + { + if (CP_DECL_CONTEXT (TYPE_NAME (r)) != c) + return false; + if (LAMBDA_TYPE_P (r)) + return false; + if (OVERLOAD_TYPE_P (r)) + return true; + if (typedef_variant_p (r)) + return true; + } + else if (DECL_P (r)) + { + if (CP_DECL_CONTEXT (r) != c) + return false; + if (DECL_CLASS_TEMPLATE_P (r) + || DECL_FUNCTION_TEMPLATE_P (r) + || variable_template_p (r) + || DECL_ALIAS_TEMPLATE_P (r) + || concept_definition_p (r) + || TREE_CODE (r) == FIELD_DECL + || TREE_CODE (r) == NAMESPACE_DECL) + return true; + if (VAR_P (r) && !undeduced_auto_decl (r)) + return true; + if (TREE_CODE (r) == FUNCTION_DECL) + { + if (undeduced_auto_decl (r)) + return false; + // TODO: check if constraints are satisfied. + return true; + } + } + return false; +} + +/* Callback for vector qsort to compare members by ascending DECL_UID. */ + +static int +members_cmp (const void *a, const void *b) +{ + const constructor_elt *ea = (const constructor_elt *) a; + const constructor_elt *eb = (const constructor_elt *) b; + tree vala = REFLECT_EXPR_HANDLE (ea->value); + tree valb = REFLECT_EXPR_HANDLE (eb->value); + if (TYPE_P (vala)) + vala = TYPE_NAME (vala); + if (TYPE_P (valb)) + valb = TYPE_NAME (valb); + if (DECL_UID (vala) < DECL_UID (valb)) + return -1; + if (DECL_UID (vala) > DECL_UID (valb)) + return 1; + gcc_assert (ea == eb); + return 0; +} + +/* Enumerate members of namespace NS for eval_members_of. */ + +static vec * +namespace_members_of (location_t loc, tree ns) +{ + vec *elts = nullptr; + for (tree b : *DECL_NAMESPACE_BINDINGS (ns)) + { + tree m = b; + if (VAR_P (b) && DECL_ANON_UNION_VAR_P (b)) + continue; + if (TREE_CODE (b) == TYPE_DECL) + m = TREE_TYPE (b); + if (!members_of_representable_p (ns, m)) + continue; + if (DECL_DECOMPOSITION_P (m) && !DECL_DECOMP_IS_BASE (m)) + continue; + /* I don't see much point in calling eval_is_accessible here, + won't it always return true? */ + CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, + get_reflection_raw (loc, m)); + } + if (elts) + elts->qsort (members_cmp); + return elts; +} + +/* Enumerate members of class R for eval_*members_of. KIND is + 0 for members_of, 1 for static_members_of, 2 for + nonstatic_members_of and 3 for has_inaccessible_nonstatic_data_members. + For KIND 3 don't append any elts except for the first one for + which is_accessible returned false. */ + +static vec * +class_members_of (location_t loc, const constexpr_ctx *ctx, tree r, + tree actx, tree call, bool *non_constant_p, + tree *jump_target, int kind) +{ + if (kind == 0) + { + if (modules_p ()) + lazy_load_pendings (TYPE_NAME (r)); + if (CLASSTYPE_LAZY_DEFAULT_CTOR (r)) + lazily_declare_fn (sfk_constructor, r); + if (CLASSTYPE_LAZY_COPY_CTOR (r)) + lazily_declare_fn (sfk_copy_constructor, r); + if (CLASSTYPE_LAZY_MOVE_CTOR (r)) + lazily_declare_fn (sfk_move_constructor, r); + if (CLASSTYPE_LAZY_DESTRUCTOR (r)) + lazily_declare_fn (sfk_destructor, r); + if (CLASSTYPE_LAZY_COPY_ASSIGN (r)) + lazily_declare_fn (sfk_copy_assignment, r); + if (CLASSTYPE_LAZY_MOVE_ASSIGN (r)) + lazily_declare_fn (sfk_move_assignment, r); + } + auto_vec implicitly_declared; + vec *elts = nullptr; + for (tree field = TYPE_FIELDS (r); field; field = DECL_CHAIN (field)) + { + tree m = field; + if (TREE_CODE (field) == FIELD_DECL && DECL_ARTIFICIAL (field)) + continue; /* Ignore bases. */ + else if (DECL_SELF_REFERENCE_P (field)) + continue; + else if (TREE_CODE (field) == TYPE_DECL) + m = TREE_TYPE (field); + else if (TREE_CODE (field) == FUNCTION_DECL) + { + /* Ignore cloned cdtors. */ + if (DECL_COMPLETE_CONSTRUCTOR_P (field) + || DECL_BASE_CONSTRUCTOR_P (field) + || DECL_COMPLETE_DESTRUCTOR_P (field) + || DECL_BASE_DESTRUCTOR_P (field) + || DECL_DELETING_DESTRUCTOR_P (field)) + continue; + } + if (members_of_representable_p (r, m)) + { + if (kind == 1 + && eval_is_variable (m, REFLECT_UNDEF) != boolean_true_node) + continue; /* For static_data_members_of only include + is_variable. */ + else if ((kind == 2 || kind == 3) + && eval_is_nonstatic_data_member (m) != boolean_true_node) + continue; /* For nonstatic_data_members_of only include + is_nonstatic_data_member. */ + tree a = eval_is_accessible (loc, ctx, m, actx, call, non_constant_p, + jump_target); + if (*jump_target || *non_constant_p) + return nullptr; + if (a == boolean_false_node) + { + if (kind == 3 && elts == nullptr) + CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, boolean_true_node); + continue; + } + gcc_assert (a == boolean_true_node); + if (kind == 0 + && TREE_CODE (m) == FUNCTION_DECL + && DECL_ARTIFICIAL (m)) + { + /* Implicitly-declared special members appear after any user + declared members */ + implicitly_declared.safe_push (m); + continue; + } + else if (kind == 3) + continue; + CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, + get_reflection_raw (loc, m)); + } + } + /* TYPE_DECLs in TYPE_FIELDS come after other decls, so for members_of + the declaration order is not preserved. */ + if (kind == 0 && elts) + elts->qsort (members_cmp); + if (kind == 0 && !implicitly_declared.is_empty ()) + { + gcc_assert (implicitly_declared.length () <= 6); + for (tree m : implicitly_declared) + if (default_ctor_p (m)) + { + CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, + get_reflection_raw (loc, m)); + break; + } + for (tree m : implicitly_declared) + if (DECL_COPY_CONSTRUCTOR_P (m)) + { + CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, + get_reflection_raw (loc, m)); + break; + } + for (tree m : implicitly_declared) + if (special_function_p (m) == sfk_copy_assignment) + { + CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, + get_reflection_raw (loc, m)); + break; + } + for (tree m : implicitly_declared) + if (DECL_MOVE_CONSTRUCTOR_P (m)) + { + CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, + get_reflection_raw (loc, m)); + break; + } + for (tree m : implicitly_declared) + if (special_function_p (m) == sfk_move_assignment) + { + CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, + get_reflection_raw (loc, m)); + break; + } + for (tree m : implicitly_declared) + if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (m)) + { + CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, + get_reflection_raw (loc, m)); + break; + } + } + return elts; +} + +/* Implement std::meta::members_of. + A declaration D members-of-precedes a point P if D precedes either P or the + point immediately following the class-specifier of the outermost class for + which P is in a complete-class context. + A declaration D of a member M of a class or namespace Q is + Q-members-of-eligible if + -- the host scope of D is the class scope or namespace scope associated + with Q, + -- D is not a friend declaration, + -- M is not a closure type, + -- M is not a specialization of a template, + -- if Q is a class that is not a closure type, then M is a direct member of + Q that is not a variant member of a nested anonymous union of Q, and + -- if Q is a closure type, then M is a function call operator or function + call operator template. + It is implementation-defined whether declarations of other members of a + closure type Q are Q-members-of-eligible. + A member M of a class or namespace Q is Q-members-of-representable from a + point P if a Q-members-of-eligible declaration of M members-of-precedes P, + and M is + -- a class or enumeration type + -- a type alias + -- a class template, function template, variable template, alias template, + or concept, + -- a variable or reference V for which the type of V does not contain an + undeduced placeholder type, + -- a function F for which + -- the type of F does not contain an undeduced placeholder type, + -- the constraints (if any) of F are satisfied, and + -- if F is a prospective destructor, F is the selected destructor, + -- a non-static data member, + -- a namespace, or + -- a namespace alias. + Returns: A vector containing reflections of all members M of the entity Q + represented by dealias(r) for which + -- M is Q-members-of-representable from some point in the evaluation + context and + -- is_accessible(^^M, ctx) is true. + If dealias(r) represents a class C, then the vector also contains + reflections representing all unnamed bit-fields B whose declarations + inhabit the class scope corresponding to C for which + is_accessible(^^B, ctx) is true. + Reflections of class members and unnamed bit-fields that are declared + appear in the order in which they are declared. + Throws: meta::exception unless dealias(r) is a reflection representing + either a class type that is complete from some point in the evaluation + context or a namespace. */ + +static tree +eval_members_of (location_t loc, const constexpr_ctx *ctx, tree r, + tree actx, tree call, bool *non_constant_p, + tree *jump_target) +{ + if (TYPE_P (r) && typedef_variant_p (r)) + r = strip_typedefs (r); + else if (TREE_CODE (r) == NAMESPACE_DECL) + r = ORIGINAL_NAMESPACE (r); + vec *elts; + if (TREE_CODE (r) == NAMESPACE_DECL) + elts = namespace_members_of (loc, r); + else if (CLASS_TYPE_P (r) && COMPLETE_TYPE_P (r)) + { + elts = class_members_of (loc, ctx, r, actx, call, non_constant_p, + jump_target, 0); + if (*jump_target) + return NULL_TREE; + else if (*non_constant_p) + return call; + } + else + return throw_exception (loc, ctx, + N_("neither complete class type nor namespace"), + r, jump_target); + return get_vector_of_info_elts (elts); +} + +/* Implement std::meta::static_data_members_of. + Returns: A vector containing each element e of members_of(type, ctx) such + that is_variable(e) is true, preserving their order. + Throws: meta::exception unless dealias(type) represents a class type that + is complete from some point in the evaluation context. */ + +static tree +eval_static_data_members_of (location_t loc, const constexpr_ctx *ctx, tree r, + tree actx, tree call, bool *non_constant_p, + tree *jump_target) +{ + if (TYPE_P (r) && typedef_variant_p (r)) + r = strip_typedefs (r); + vec *elts = nullptr; + if (CLASS_TYPE_P (r) && COMPLETE_TYPE_P (r)) + { + elts = class_members_of (loc, ctx, r, actx, call, non_constant_p, + jump_target, 1); + if (*jump_target) + return NULL_TREE; + else if (*non_constant_p) + return call; + } + else + return throw_exception (loc, ctx, + N_("not a complete class type"), + r, jump_target); + return get_vector_of_info_elts (elts); +} + +/* Implement std::meta::nonstatic_data_members_of. + Returns: A vector containing each element e of members_of(type, ctx) such + that is_nonstatic_data_member(e) is true, preserving their order. + Throws: meta::exception unless dealias(type) represents a class type that + is complete from some point in the evaluation context. */ + +static tree +eval_nonstatic_data_members_of (location_t loc, const constexpr_ctx *ctx, + tree r, tree actx, tree call, + bool *non_constant_p, tree *jump_target) +{ + if (TYPE_P (r) && typedef_variant_p (r)) + r = strip_typedefs (r); + vec *elts = nullptr; + if (CLASS_TYPE_P (r) && COMPLETE_TYPE_P (r)) + { + elts = class_members_of (loc, ctx, r, actx, call, non_constant_p, + jump_target, 2); + if (*jump_target) + return NULL_TREE; + else if (*non_constant_p) + return call; + } + else + return throw_exception (loc, ctx, + N_("not a complete class type"), + r, jump_target); + return get_vector_of_info_elts (elts); +} + +/* Implement std::meta::has_inaccessible_nonstatic_data_members. + Returns: true if is_accessible(R, ctx) is false for any R in + nonstatic_data_members_of(r, access_context::unchecked()). + Otherwise, false. + Throws: meta::exception unless + -- nonstatic_data_members_of(r, access_context::unchecked()) is a constant + subexpression and + -- r does not represent a closure type. */ + +static tree +eval_has_inaccessible_nonstatic_data_members (location_t loc, + const constexpr_ctx *ctx, + tree r, tree actx, tree call, + bool *non_constant_p, + tree *jump_target) +{ + if (TYPE_P (r) && typedef_variant_p (r)) + r = strip_typedefs (r); + vec *elts = nullptr; + if (CLASS_TYPE_P (r) && COMPLETE_TYPE_P (r)) + { + if (LAMBDA_TYPE_P (r)) + return throw_exception (loc, ctx, N_("closure type"), r, + jump_target); + elts = class_members_of (loc, ctx, r, actx, call, non_constant_p, + jump_target, 3); + if (*jump_target) + return NULL_TREE; + else if (*non_constant_p) + return call; + } + else + return throw_exception (loc, ctx, + N_("not a complete class type"), + r, jump_target); + if (elts == nullptr) + return boolean_false_node; + else + return boolean_true_node; +} + /* Expand a call to a metafunction FUN. CALL is the CALL_EXPR. JUMP_TARGET is set if we are throwing std::meta::exception. */ @@ -6600,6 +7009,21 @@ process_metafunction (const constexpr_ctx *ctx, tree fun, tree call, return eval_has_thread_storage_duration (h, kind); if (!strcmp (ident, "automatic_storage_duration")) return eval_has_automatic_storage_duration (h, kind); + if (!strcmp (ident, "inaccessible_nonstatic_data_members")) + { + tree actx = get_nth_callarg (call, 1); + actx = cxx_eval_constant_expression (ctx, actx, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + if (*non_constant_p) + return call; + return eval_has_inaccessible_nonstatic_data_members (loc, ctx, h, + actx, call, + non_constant_p, + jump_target); + } goto not_found; } @@ -6819,6 +7243,28 @@ process_metafunction (const constexpr_ctx *ctx, tree fun, tree call, return call; return eval_define_aggregate (loc, ctx, h, hvec, call, non_constant_p); } + if (id_equal (name, "members_of") + || id_equal (name, "static_data_members_of") + || id_equal (name, "nonstatic_data_members_of")) + { + tree actx = get_nth_callarg (call, 1); + actx = cxx_eval_constant_expression (ctx, actx, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + if (*non_constant_p) + return call; + if (id_equal (name, "members_of")) + return eval_members_of (loc, ctx, h, actx, call, non_constant_p, + jump_target); + else if (id_equal (name, "static_data_members_of")) + return eval_static_data_members_of (loc, ctx, h, actx, call, + non_constant_p, jump_target); + else if (id_equal (name, "nonstatic_data_members_of")) + return eval_nonstatic_data_members_of (loc, ctx, h, actx, call, + non_constant_p, jump_target); + } not_found: sorry ("%qE", name); diff --git a/gcc/testsuite/g++.dg/reflect/members_of1.C b/gcc/testsuite/g++.dg/reflect/members_of1.C new file mode 100644 index 00000000000..4a0fc764bc0 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/members_of1.C @@ -0,0 +1,459 @@ +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } +// Test std::meta::{,{,non}static_data_}members_of and +// has_inaccessible_nonstatic_data_members. + +#include +#include + +using namespace std::meta; +using std::views::filter; +using std::ranges::to; +using std::vector; +using std::string_view; + +consteval bool +check_special_members (const vector &vec, int cnt, bool dct, bool cct, bool cas, bool mct, bool mas, bool dt) +{ + if ((vec | filter (is_special_member_function) | filter (is_defaulted) | to ()).size () != cnt) + throw 1; + if ((vec | filter (is_default_constructor) | to ()).size () != dct) + throw 2; + if ((vec | filter (is_copy_constructor) | to ()).size () != cct) + throw 3; + if ((vec | filter (is_copy_assignment) | to ()).size () != cas) + throw 4; + if ((vec | filter (is_move_constructor) | to ()).size () != mct) + throw 5; + if ((vec | filter (is_move_assignment) | to ()).size () != mas) + throw 6; + if ((vec | filter (is_destructor) | to ()).size () != dt) + throw 7; + return true; +} + +namespace N1 { + struct A { + int a; + static int b; + enum E { E0 }; + using c = int; + typedef long d; + consteval { + } + }; + int A::b = 24; + consteval { + } +} +namespace N2 { + struct B {}; + struct C { int : 5; }; + struct D { D (int = 42); int d; }; + struct E { E (int); int e; }; + struct F { int f; F (const F &); }; + struct G { G &operator = (const G &); int g; }; + struct H { int h; H (H &&); }; + struct I { I &operator = (I &&); int i; }; + struct J { ~J (); }; + struct K { + int a; + static int b; + enum E { E0 }; + using c = int; + typedef long d; + template + struct A {}; + template + static consteval bool foo (const T &) { return true; } + template + static constexpr int e = N; + template + using f = const T &; + void bar () {} + auto baz (); + int g : 3; + long : 2; + int : 0; + consteval { + A z = {}; + static_assert (e <42> == 42); + f w = 42; + } + protected: + int Xa; + static int Xb; + enum XE { XE0 }; + using Xc = int; + typedef long Xd; + template + struct XA {}; + template + static consteval bool Xfoo (const T &) { return true; } + template + static constexpr int Xe = N; + template + using Xf = const T &; + void Xbar () {} + auto Xbaz (); + int Xg : 5; + long : 4; + int : 0; + private: + int Ya; + static int Yb; + enum YE { YE0 }; + using Yc = int; + typedef long Yd; + template + struct YA {}; + template + static consteval bool Yfoo (const T &) { return true; } + template + static constexpr int Ye = N; + template + using Yf = const T &; + void Ybar () {} + auto Ybaz (); + int Yg : 7; + long : 6; + int : 0; + public: + static constexpr info rXa = ^^Xa; + static constexpr info rXb = ^^Xb; + static constexpr info rXE = ^^XE; + static constexpr info rXg = ^^Xg; + static constexpr info rYa = ^^Ya; + static constexpr info rYb = ^^Yb; + static constexpr info rYE = ^^YE; + static constexpr info rYg = ^^Yg; + }; + namespace W {} + namespace X = W; + namespace W {} + namespace W {} + inline namespace Y { int a; } + template + concept Z = requires { true; }; +} +static_assert (N2::K::foo (42) && N2::K::foo (42UL)); + +constexpr access_context gctx = access_context::current (); +constexpr access_context uctx = access_context::unchecked (); + +static_assert (members_of (^^N1::A, gctx).size () == 11); +static_assert (members_of (^^N1::A, gctx)[0] == ^^N1::A::a); +static_assert (members_of (^^N1::A, gctx)[1] == ^^N1::A::b); +static_assert (members_of (^^N1::A, gctx)[2] == ^^N1::A::E); +static_assert (members_of (^^N1::A, gctx)[3] == ^^N1::A::c); +static_assert (members_of (^^N1::A, gctx)[4] == ^^N1::A::d); +static_assert (check_special_members (members_of (^^N1::A, gctx), 6, true, true, true, true, true, true)); +static_assert (static_data_members_of (^^N1::A, gctx).size () == 1); +static_assert (static_data_members_of (^^N1::A, gctx)[0] == ^^N1::A::b); +static_assert (nonstatic_data_members_of (^^N1::A, gctx).size () == 1); +static_assert (nonstatic_data_members_of (^^N1::A, gctx)[0] == ^^N1::A::a); +static_assert (!has_inaccessible_nonstatic_data_members (^^N1::A, gctx)); + +static_assert (members_of (^^N1, gctx).size () == 1); +static_assert (members_of (^^N1, gctx)[0] == ^^N1::A); + +static_assert (members_of (^^N2::B, gctx).size () == 6); +static_assert (check_special_members (members_of (^^N2::B, gctx), 6, true, true, true, true, true, true)); +static_assert (static_data_members_of (^^N2::B, gctx).size () == 0); +static_assert (nonstatic_data_members_of (^^N2::B, gctx).size () == 0); +static_assert (!has_inaccessible_nonstatic_data_members (^^N2::B, gctx)); + +static_assert (members_of (^^N2::C, gctx).size () == 7); +static_assert (is_bit_field (members_of (^^N2::C, gctx)[0])); +static_assert (!has_identifier (members_of (^^N2::C, gctx)[0])); +static_assert (bit_size_of (members_of (^^N2::C, gctx)[0]) == 5); +static_assert (type_of (members_of (^^N2::C, gctx)[0]) == ^^int); +static_assert (check_special_members (members_of (^^N2::C, gctx), 6, true, true, true, true, true, true)); +static_assert (static_data_members_of (^^N2::C, gctx).size () == 0); +static_assert (nonstatic_data_members_of (^^N2::C, gctx).size () == 0); +static_assert (!has_inaccessible_nonstatic_data_members (^^N2::C, gctx)); + +static_assert (members_of (^^N2::D, gctx).size () == 7); +static_assert (is_default_constructor (members_of (^^N2::D, gctx)[0])); +static_assert (members_of (^^N2::D, gctx)[1] == ^^N2::D::d); +static_assert (check_special_members (members_of (^^N2::D, gctx), 5, true, true, true, true, true, true)); +static_assert (static_data_members_of (^^N2::D, gctx).size () == 0); +static_assert (nonstatic_data_members_of (^^N2::D, gctx).size () == 1); +static_assert (nonstatic_data_members_of (^^N2::D, gctx)[0] == ^^N2::D::d); +static_assert (!has_inaccessible_nonstatic_data_members (^^N2::D, gctx)); + +static_assert (members_of (^^N2::E, gctx).size () == 7); +static_assert (is_constructor (members_of (^^N2::E, gctx)[0])); +static_assert (members_of (^^N2::E, gctx)[1] == ^^N2::E::e); +static_assert (check_special_members (members_of (^^N2::E, gctx), 5, false, true, true, true, true, true)); +static_assert (static_data_members_of (^^N2::E, gctx).size () == 0); +static_assert (nonstatic_data_members_of (^^N2::E, gctx).size () == 1); +static_assert (nonstatic_data_members_of (^^N2::E, gctx)[0] == ^^N2::E::e); +static_assert (!has_inaccessible_nonstatic_data_members (^^N2::E, gctx)); + +static_assert (members_of (^^N2::F, gctx).size () == 4); +static_assert (members_of (^^N2::F, gctx)[0] == ^^N2::F::f); +static_assert (is_copy_constructor (members_of (^^N2::F, gctx)[1])); +static_assert (check_special_members (members_of (^^N2::F, gctx), 2, false, true, true, false, false, true)); +static_assert (static_data_members_of (^^N2::F, gctx).size () == 0); +static_assert (nonstatic_data_members_of (^^N2::F, gctx).size () == 1); +static_assert (nonstatic_data_members_of (^^N2::F, gctx)[0] == ^^N2::F::f); +static_assert (!has_inaccessible_nonstatic_data_members (^^N2::F, gctx)); + +static_assert (members_of (^^N2::G, gctx).size () == 5); +static_assert (is_copy_assignment (members_of (^^N2::G, gctx)[0])); +static_assert (members_of (^^N2::G, gctx)[1] == ^^N2::G::g); +static_assert (check_special_members (members_of (^^N2::G, gctx), 3, true, true, true, false, false, true)); +static_assert (static_data_members_of (^^N2::G, gctx).size () == 0); +static_assert (nonstatic_data_members_of (^^N2::G, gctx).size () == 1); +static_assert (nonstatic_data_members_of (^^N2::G, gctx)[0] == ^^N2::G::g); +static_assert (!has_inaccessible_nonstatic_data_members (^^N2::G, gctx)); + +static_assert (members_of (^^N2::H, gctx).size () == 5); +static_assert (members_of (^^N2::H, gctx)[0] == ^^N2::H::h); +static_assert (is_move_constructor (members_of (^^N2::H, gctx)[1])); +static_assert (check_special_members (members_of (^^N2::H, gctx), 3, false, true, true, true, false, true)); +static_assert (static_data_members_of (^^N2::H, gctx).size () == 0); +static_assert (nonstatic_data_members_of (^^N2::H, gctx).size () == 1); +static_assert (nonstatic_data_members_of (^^N2::H, gctx)[0] == ^^N2::H::h); +static_assert (!has_inaccessible_nonstatic_data_members (^^N2::H, gctx)); + +static_assert (members_of (^^N2::I, gctx).size () == 6); +static_assert (is_move_assignment (members_of (^^N2::I, gctx)[0])); +static_assert (members_of (^^N2::I, gctx)[1] == ^^N2::I::i); +static_assert (check_special_members (members_of (^^N2::I, gctx), 4, true, true, true, false, true, true)); +static_assert (static_data_members_of (^^N2::I, gctx).size () == 0); +static_assert (nonstatic_data_members_of (^^N2::I, gctx).size () == 1); +static_assert (nonstatic_data_members_of (^^N2::I, gctx)[0] == ^^N2::I::i); +static_assert (!has_inaccessible_nonstatic_data_members (^^N2::I, gctx)); + +static_assert (members_of (^^N2::J, gctx).size () == 4); +static_assert (is_destructor (members_of (^^N2::J, gctx)[0])); +static_assert (check_special_members (members_of (^^N2::J, gctx), 3, true, true, true, false, false, true)); +static_assert (static_data_members_of (^^N2::J, gctx).size () == 0); +static_assert (nonstatic_data_members_of (^^N2::J, gctx).size () == 0); +static_assert (!has_inaccessible_nonstatic_data_members (^^N2::J, gctx)); + +static_assert (members_of (^^N2::K, gctx).size () == 27); +static_assert (members_of (^^N2::K, gctx)[0] == ^^N2::K::a); +static_assert (members_of (^^N2::K, gctx)[1] == ^^N2::K::b); +static_assert (members_of (^^N2::K, gctx)[2] == ^^N2::K::E); +static_assert (members_of (^^N2::K, gctx)[3] == ^^N2::K::c); +static_assert (members_of (^^N2::K, gctx)[4] == ^^N2::K::d); +static_assert (members_of (^^N2::K, gctx)[5] == ^^N2::K::A); +static_assert (members_of (^^N2::K, gctx)[6] == ^^N2::K::foo); +static_assert (members_of (^^N2::K, gctx)[7] == ^^N2::K::e); +static_assert (members_of (^^N2::K, gctx)[8] == ^^N2::K::f); +static_assert (members_of (^^N2::K, gctx)[9] == ^^N2::K::bar); +static_assert (members_of (^^N2::K, gctx)[10] == ^^N2::K::g); +static_assert (is_bit_field (members_of (^^N2::K, gctx)[11])); +static_assert (!has_identifier (members_of (^^N2::K, gctx)[11])); +static_assert (bit_size_of (members_of (^^N2::K, gctx)[11]) == 2); +static_assert (type_of (members_of (^^N2::K, gctx)[11]) == ^^long); +static_assert (is_bit_field (members_of (^^N2::K, gctx)[12])); +static_assert (!has_identifier (members_of (^^N2::K, gctx)[12])); +static_assert (bit_size_of (members_of (^^N2::K, gctx)[12]) == 0); +static_assert (type_of (members_of (^^N2::K, gctx)[12]) == ^^int); +static_assert (members_of (^^N2::K, gctx)[13] == ^^N2::K::rXa); +static_assert (members_of (^^N2::K, gctx)[14] == ^^N2::K::rXb); +static_assert (members_of (^^N2::K, gctx)[15] == ^^N2::K::rXE); +static_assert (members_of (^^N2::K, gctx)[16] == ^^N2::K::rXg); +static_assert (members_of (^^N2::K, gctx)[17] == ^^N2::K::rYa); +static_assert (members_of (^^N2::K, gctx)[18] == ^^N2::K::rYb); +static_assert (members_of (^^N2::K, gctx)[19] == ^^N2::K::rYE); +static_assert (members_of (^^N2::K, gctx)[20] == ^^N2::K::rYg); +static_assert (check_special_members (members_of (^^N2::K, gctx), 6, true, true, true, true, true, true)); +static_assert (static_data_members_of (^^N2::K, gctx).size () == 9); +static_assert (static_data_members_of (^^N2::K, gctx)[0] == ^^N2::K::b); +static_assert (static_data_members_of (^^N2::K, gctx)[1] == ^^N2::K::rXa); +static_assert (static_data_members_of (^^N2::K, gctx)[2] == ^^N2::K::rXb); +static_assert (static_data_members_of (^^N2::K, gctx)[3] == ^^N2::K::rXE); +static_assert (static_data_members_of (^^N2::K, gctx)[4] == ^^N2::K::rXg); +static_assert (static_data_members_of (^^N2::K, gctx)[5] == ^^N2::K::rYa); +static_assert (static_data_members_of (^^N2::K, gctx)[6] == ^^N2::K::rYb); +static_assert (static_data_members_of (^^N2::K, gctx)[7] == ^^N2::K::rYE); +static_assert (static_data_members_of (^^N2::K, gctx)[8] == ^^N2::K::rYg); +static_assert (nonstatic_data_members_of (^^N2::K, gctx).size () == 2); +static_assert (nonstatic_data_members_of (^^N2::K, gctx)[0] == ^^N2::K::a); +static_assert (nonstatic_data_members_of (^^N2::K, gctx)[1] == ^^N2::K::g); +static_assert (has_inaccessible_nonstatic_data_members (^^N2::K, gctx)); +static_assert (members_of (^^N2::K, uctx).size () == 53); +static_assert (members_of (^^N2::K, uctx)[0] == ^^N2::K::a); +static_assert (members_of (^^N2::K, uctx)[1] == ^^N2::K::b); +static_assert (members_of (^^N2::K, uctx)[2] == ^^N2::K::E); +static_assert (members_of (^^N2::K, uctx)[3] == ^^N2::K::c); +static_assert (members_of (^^N2::K, uctx)[4] == ^^N2::K::d); +static_assert (members_of (^^N2::K, uctx)[5] == ^^N2::K::A); +static_assert (members_of (^^N2::K, uctx)[6] == ^^N2::K::foo); +static_assert (members_of (^^N2::K, uctx)[7] == ^^N2::K::e); +static_assert (members_of (^^N2::K, uctx)[8] == ^^N2::K::f); +static_assert (members_of (^^N2::K, uctx)[9] == ^^N2::K::bar); +static_assert (members_of (^^N2::K, uctx)[10] == ^^N2::K::g); +static_assert (is_bit_field (members_of (^^N2::K, uctx)[11])); +static_assert (!has_identifier (members_of (^^N2::K, uctx)[11])); +static_assert (bit_size_of (members_of (^^N2::K, uctx)[11]) == 2); +static_assert (type_of (members_of (^^N2::K, uctx)[11]) == ^^long); +static_assert (is_bit_field (members_of (^^N2::K, uctx)[12])); +static_assert (!has_identifier (members_of (^^N2::K, uctx)[12])); +static_assert (bit_size_of (members_of (^^N2::K, uctx)[12]) == 0); +static_assert (type_of (members_of (^^N2::K, uctx)[12]) == ^^int); +static_assert (members_of (^^N2::K, uctx)[13] == N2::K::rXa); +static_assert (members_of (^^N2::K, uctx)[14] == N2::K::rXb); +static_assert (members_of (^^N2::K, uctx)[15] == N2::K::rXE); +static_assert (identifier_of (members_of (^^N2::K, uctx)[16]) == string_view ("Xc")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[17]) == string_view ("Xd")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[18]) == string_view ("XA")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[19]) == string_view ("Xfoo")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[20]) == string_view ("Xe")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[21]) == string_view ("Xf")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[22]) == string_view ("Xbar")); +static_assert (members_of (^^N2::K, uctx)[23] == N2::K::rXg); +static_assert (is_bit_field (members_of (^^N2::K, uctx)[24])); +static_assert (!has_identifier (members_of (^^N2::K, uctx)[24])); +static_assert (bit_size_of (members_of (^^N2::K, uctx)[24]) == 4); +static_assert (type_of (members_of (^^N2::K, uctx)[24]) == ^^long); +static_assert (is_bit_field (members_of (^^N2::K, uctx)[25])); +static_assert (!has_identifier (members_of (^^N2::K, uctx)[25])); +static_assert (bit_size_of (members_of (^^N2::K, uctx)[25]) == 0); +static_assert (type_of (members_of (^^N2::K, uctx)[25]) == ^^int); +static_assert (members_of (^^N2::K, uctx)[26] == N2::K::rYa); +static_assert (members_of (^^N2::K, uctx)[27] == N2::K::rYb); +static_assert (members_of (^^N2::K, uctx)[28] == N2::K::rYE); +static_assert (identifier_of (members_of (^^N2::K, uctx)[29]) == string_view ("Yc")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[30]) == string_view ("Yd")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[31]) == string_view ("YA")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[32]) == string_view ("Yfoo")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[33]) == string_view ("Ye")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[34]) == string_view ("Yf")); +static_assert (identifier_of (members_of (^^N2::K, uctx)[35]) == string_view ("Ybar")); +static_assert (members_of (^^N2::K, uctx)[36] == N2::K::rYg); +static_assert (is_bit_field (members_of (^^N2::K, uctx)[37])); +static_assert (!has_identifier (members_of (^^N2::K, uctx)[37])); +static_assert (bit_size_of (members_of (^^N2::K, uctx)[37]) == 6); +static_assert (type_of (members_of (^^N2::K, uctx)[37]) == ^^long); +static_assert (is_bit_field (members_of (^^N2::K, uctx)[38])); +static_assert (!has_identifier (members_of (^^N2::K, uctx)[38])); +static_assert (bit_size_of (members_of (^^N2::K, uctx)[38]) == 0); +static_assert (type_of (members_of (^^N2::K, uctx)[38]) == ^^int); +static_assert (members_of (^^N2::K, uctx)[39] == ^^N2::K::rXa); +static_assert (members_of (^^N2::K, uctx)[40] == ^^N2::K::rXb); +static_assert (members_of (^^N2::K, uctx)[41] == ^^N2::K::rXE); +static_assert (members_of (^^N2::K, uctx)[42] == ^^N2::K::rXg); +static_assert (members_of (^^N2::K, uctx)[43] == ^^N2::K::rYa); +static_assert (members_of (^^N2::K, uctx)[44] == ^^N2::K::rYb); +static_assert (members_of (^^N2::K, uctx)[45] == ^^N2::K::rYE); +static_assert (members_of (^^N2::K, uctx)[46] == ^^N2::K::rYg); +static_assert (check_special_members (members_of (^^N2::K, uctx), 6, true, true, true, true, true, true)); +static_assert (static_data_members_of (^^N2::K, uctx).size () == 11); +static_assert (static_data_members_of (^^N2::K, uctx)[0] == ^^N2::K::b); +static_assert (static_data_members_of (^^N2::K, uctx)[1] == N2::K::rXb); +static_assert (static_data_members_of (^^N2::K, uctx)[2] == N2::K::rYb); +static_assert (static_data_members_of (^^N2::K, uctx)[3] == ^^N2::K::rXa); +static_assert (static_data_members_of (^^N2::K, uctx)[4] == ^^N2::K::rXb); +static_assert (static_data_members_of (^^N2::K, uctx)[5] == ^^N2::K::rXE); +static_assert (static_data_members_of (^^N2::K, uctx)[6] == ^^N2::K::rXg); +static_assert (static_data_members_of (^^N2::K, uctx)[7] == ^^N2::K::rYa); +static_assert (static_data_members_of (^^N2::K, uctx)[8] == ^^N2::K::rYb); +static_assert (static_data_members_of (^^N2::K, uctx)[9] == ^^N2::K::rYE); +static_assert (static_data_members_of (^^N2::K, uctx)[10] == ^^N2::K::rYg); +static_assert (nonstatic_data_members_of (^^N2::K, uctx).size () == 6); +static_assert (nonstatic_data_members_of (^^N2::K, uctx)[0] == ^^N2::K::a); +static_assert (nonstatic_data_members_of (^^N2::K, uctx)[1] == ^^N2::K::g); +static_assert (nonstatic_data_members_of (^^N2::K, uctx)[2] == N2::K::rXa); +static_assert (nonstatic_data_members_of (^^N2::K, uctx)[3] == N2::K::rXg); +static_assert (nonstatic_data_members_of (^^N2::K, uctx)[4] == N2::K::rYa); +static_assert (nonstatic_data_members_of (^^N2::K, uctx)[5] == N2::K::rYg); +static_assert (!has_inaccessible_nonstatic_data_members (^^N2::K, uctx)); + +static_assert (members_of (^^N2, gctx).size () == 14); +static_assert ((members_of (^^N2, gctx) | filter (is_type) | filter (is_class_type) | to ()).size () == 10); +static_assert ((members_of (^^N2, gctx) | filter (is_namespace) | to ()).size () == 3); +static_assert ((members_of (^^N2, gctx) | filter (is_namespace_alias) | to ()).size () == 1); +static_assert ((members_of (^^N2, gctx) | filter (is_concept) | to ()).size () == 1); + +namespace N2 { + struct L : public K { + static constexpr auto ctx = access_context::current (); + }; + static constexpr auto ctx = L::ctx.via (^^L); +} + +static_assert (members_of (^^N2::K, N2::ctx).size () == 40); +static_assert (members_of (^^N2::K, N2::ctx)[0] == ^^N2::K::a); +static_assert (members_of (^^N2::K, N2::ctx)[1] == ^^N2::K::b); +static_assert (members_of (^^N2::K, N2::ctx)[2] == ^^N2::K::E); +static_assert (members_of (^^N2::K, N2::ctx)[3] == ^^N2::K::c); +static_assert (members_of (^^N2::K, N2::ctx)[4] == ^^N2::K::d); +static_assert (members_of (^^N2::K, N2::ctx)[5] == ^^N2::K::A); +static_assert (members_of (^^N2::K, N2::ctx)[6] == ^^N2::K::foo); +static_assert (members_of (^^N2::K, N2::ctx)[7] == ^^N2::K::e); +static_assert (members_of (^^N2::K, N2::ctx)[8] == ^^N2::K::f); +static_assert (members_of (^^N2::K, N2::ctx)[9] == ^^N2::K::bar); +static_assert (members_of (^^N2::K, N2::ctx)[10] == ^^N2::K::g); +static_assert (is_bit_field (members_of (^^N2::K, N2::ctx)[11])); +static_assert (!has_identifier (members_of (^^N2::K, N2::ctx)[11])); +static_assert (bit_size_of (members_of (^^N2::K, N2::ctx)[11]) == 2); +static_assert (type_of (members_of (^^N2::K, N2::ctx)[11]) == ^^long); +static_assert (is_bit_field (members_of (^^N2::K, N2::ctx)[12])); +static_assert (!has_identifier (members_of (^^N2::K, N2::ctx)[12])); +static_assert (bit_size_of (members_of (^^N2::K, N2::ctx)[12]) == 0); +static_assert (type_of (members_of (^^N2::K, N2::ctx)[12]) == ^^int); +static_assert (members_of (^^N2::K, N2::ctx)[13] == N2::K::rXa); +static_assert (members_of (^^N2::K, N2::ctx)[14] == N2::K::rXb); +static_assert (members_of (^^N2::K, N2::ctx)[15] == N2::K::rXE); +static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[16]) == string_view ("Xc")); +static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[17]) == string_view ("Xd")); +static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[18]) == string_view ("XA")); +static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[19]) == string_view ("Xfoo")); +static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[20]) == string_view ("Xe")); +static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[21]) == string_view ("Xf")); +static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[22]) == string_view ("Xbar")); +static_assert (members_of (^^N2::K, N2::ctx)[23] == N2::K::rXg); +static_assert (is_bit_field (members_of (^^N2::K, N2::ctx)[24])); +static_assert (!has_identifier (members_of (^^N2::K, N2::ctx)[24])); +static_assert (bit_size_of (members_of (^^N2::K, N2::ctx)[24]) == 4); +static_assert (type_of (members_of (^^N2::K, N2::ctx)[24]) == ^^long); +static_assert (is_bit_field (members_of (^^N2::K, N2::ctx)[25])); +static_assert (!has_identifier (members_of (^^N2::K, N2::ctx)[25])); +static_assert (bit_size_of (members_of (^^N2::K, N2::ctx)[25]) == 0); +static_assert (type_of (members_of (^^N2::K, N2::ctx)[25]) == ^^int); +static_assert (members_of (^^N2::K, N2::ctx)[26] == ^^N2::K::rXa); +static_assert (members_of (^^N2::K, N2::ctx)[27] == ^^N2::K::rXb); +static_assert (members_of (^^N2::K, N2::ctx)[28] == ^^N2::K::rXE); +static_assert (members_of (^^N2::K, N2::ctx)[29] == ^^N2::K::rXg); +static_assert (members_of (^^N2::K, N2::ctx)[30] == ^^N2::K::rYa); +static_assert (members_of (^^N2::K, N2::ctx)[31] == ^^N2::K::rYb); +static_assert (members_of (^^N2::K, N2::ctx)[32] == ^^N2::K::rYE); +static_assert (members_of (^^N2::K, N2::ctx)[33] == ^^N2::K::rYg); +static_assert (check_special_members (members_of (^^N2::K, N2::ctx), 6, true, true, true, true, true, true)); +static_assert (static_data_members_of (^^N2::K, N2::ctx).size () == 10); +static_assert (static_data_members_of (^^N2::K, N2::ctx)[0] == ^^N2::K::b); +static_assert (static_data_members_of (^^N2::K, N2::ctx)[1] == N2::K::rXb); +static_assert (static_data_members_of (^^N2::K, N2::ctx)[2] == ^^N2::K::rXa); +static_assert (static_data_members_of (^^N2::K, N2::ctx)[3] == ^^N2::K::rXb); +static_assert (static_data_members_of (^^N2::K, N2::ctx)[4] == ^^N2::K::rXE); +static_assert (static_data_members_of (^^N2::K, N2::ctx)[5] == ^^N2::K::rXg); +static_assert (static_data_members_of (^^N2::K, N2::ctx)[6] == ^^N2::K::rYa); +static_assert (static_data_members_of (^^N2::K, N2::ctx)[7] == ^^N2::K::rYb); +static_assert (static_data_members_of (^^N2::K, N2::ctx)[8] == ^^N2::K::rYE); +static_assert (static_data_members_of (^^N2::K, N2::ctx)[9] == ^^N2::K::rYg); +static_assert (nonstatic_data_members_of (^^N2::K, N2::ctx).size () == 4); +static_assert (nonstatic_data_members_of (^^N2::K, N2::ctx)[0] == ^^N2::K::a); +static_assert (nonstatic_data_members_of (^^N2::K, N2::ctx)[1] == ^^N2::K::g); +static_assert (nonstatic_data_members_of (^^N2::K, N2::ctx)[2] == N2::K::rXa); +static_assert (nonstatic_data_members_of (^^N2::K, N2::ctx)[3] == N2::K::rXg); +static_assert (has_inaccessible_nonstatic_data_members (^^N2::K, N2::ctx)); +static_assert (members_of (^^N2::L, gctx).size () == 7); +static_assert (members_of (^^N2::L, gctx)[0] == ^^N2::L::ctx); +static_assert (check_special_members (members_of (^^N2::L, gctx), 6, true, true, true, true, true, true)); +static_assert (static_data_members_of (^^N2::L, gctx).size () == 1); +static_assert (static_data_members_of (^^N2::L, gctx)[0] == ^^N2::L::ctx); +static_assert (nonstatic_data_members_of (^^N2::L, gctx).size () == 0); +static_assert (!has_inaccessible_nonstatic_data_members (^^N2::L, gctx)); + +static_assert (members_of (^^N2, gctx).size () == 16); +static_assert ((members_of (^^N2, gctx) | filter (is_type) | filter (is_class_type) | to ()).size () == 11); +static_assert ((members_of (^^N2, gctx) | filter (is_namespace) | to ()).size () == 3); +static_assert ((members_of (^^N2, gctx) | filter (is_namespace_alias) | to ()).size () == 1); +static_assert ((members_of (^^N2, gctx) | filter (is_concept) | to ()).size () == 1); +static_assert ((members_of (^^N2, gctx) | filter (is_variable) | to ()).size () == 1); diff --git a/libstdc++-v3/include/std/meta b/libstdc++-v3/include/std/meta index 84250ee2052..e8259aa1437 100644 --- a/libstdc++-v3/include/std/meta +++ b/libstdc++-v3/include/std/meta @@ -296,8 +296,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // [meta.reflection.access.queries], member accessibility queries consteval bool is_accessible(info, access_context); + consteval bool has_inaccessible_nonstatic_data_members(info, + access_context); // [meta.reflection.member.queries], reflection member queries + consteval vector members_of(info, access_context); + consteval vector static_data_members_of(info, access_context); + consteval vector nonstatic_data_members_of(info, access_context); consteval vector enumerators_of(info); // [meta.reflection.layout], reflection layout queries