Initial implementation of std::meta::{,{,non}static_data_}members_of and std::meta::has_inaccessible_nonstatic_data_members.

Doesn't handle yet https://eel.is/c++draft/meta.reflection#member.queries-3.5.2
nor does it test https://eel.is/c++draft/meta.reflection#member.queries-3.4
undeduced placeholder type, the namespace queries definitely need better
testsuite coverage.
Doesn't handle yet the underlying variables of tuple using namespace
scope structured bindings, doesn't have any tests for structured bindings,
guess structured binding packs need to be tested too.
And for members_of (^^::, access_context::current ()) I guess we need to
decide if e.g. __builtin_ etc. prefixed builtins or anticipated normal identifier
builtins should appear or not.
This commit is contained in:
Jakub Jelinek
2025-10-24 15:37:26 +02:00
committed by Marek Polacek
parent 552ae76eb4
commit 8cc8c8143b
3 changed files with 910 additions and 0 deletions

View File

@@ -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<constructor_elt, va_gc> *
namespace_members_of (location_t loc, tree ns)
{
vec<constructor_elt, va_gc> *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<constructor_elt, va_gc> *
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 <tree, 6> implicitly_declared;
vec<constructor_elt, va_gc> *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<constructor_elt, va_gc> *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<constructor_elt, va_gc> *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<constructor_elt, va_gc> *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<constructor_elt, va_gc> *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);

View File

@@ -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 <meta>
#include <ranges>
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 <info> &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 <vector> ()).size () != cnt)
throw 1;
if ((vec | filter (is_default_constructor) | to <vector> ()).size () != dct)
throw 2;
if ((vec | filter (is_copy_constructor) | to <vector> ()).size () != cct)
throw 3;
if ((vec | filter (is_copy_assignment) | to <vector> ()).size () != cas)
throw 4;
if ((vec | filter (is_move_constructor) | to <vector> ()).size () != mct)
throw 5;
if ((vec | filter (is_move_assignment) | to <vector> ()).size () != mas)
throw 6;
if ((vec | filter (is_destructor) | to <vector> ()).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 <typename T>
struct A {};
template <typename T>
static consteval bool foo (const T &) { return true; }
template <int N>
static constexpr int e = N;
template <typename T>
using f = const T &;
void bar () {}
auto baz ();
int g : 3;
long : 2;
int : 0;
consteval {
A <int> z = {};
static_assert (e <42> == 42);
f <int> w = 42;
}
protected:
int Xa;
static int Xb;
enum XE { XE0 };
using Xc = int;
typedef long Xd;
template <typename T>
struct XA {};
template <typename T>
static consteval bool Xfoo (const T &) { return true; }
template <int N>
static constexpr int Xe = N;
template <typename T>
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 <typename T>
struct YA {};
template <typename T>
static consteval bool Yfoo (const T &) { return true; }
template <int N>
static constexpr int Ye = N;
template <typename T>
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 <typename T>
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 <vector> ()).size () == 10);
static_assert ((members_of (^^N2, gctx) | filter (is_namespace) | to <vector> ()).size () == 3);
static_assert ((members_of (^^N2, gctx) | filter (is_namespace_alias) | to <vector> ()).size () == 1);
static_assert ((members_of (^^N2, gctx) | filter (is_concept) | to <vector> ()).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 <vector> ()).size () == 11);
static_assert ((members_of (^^N2, gctx) | filter (is_namespace) | to <vector> ()).size () == 3);
static_assert ((members_of (^^N2, gctx) | filter (is_namespace_alias) | to <vector> ()).size () == 1);
static_assert ((members_of (^^N2, gctx) | filter (is_concept) | to <vector> ()).size () == 1);
static_assert ((members_of (^^N2, gctx) | filter (is_variable) | to <vector> ()).size () == 1);

View File

@@ -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<info> members_of(info, access_context);
consteval vector<info> static_data_members_of(info, access_context);
consteval vector<info> nonstatic_data_members_of(info, access_context);
consteval vector<info> enumerators_of(info);
// [meta.reflection.layout], reflection layout queries