committing on behalf of the author Valentyn Yukhymenko <vyuhimenko@bloomberg.net>:implement std::meta::is_public/private/protected including pr feedback

Signed-off-by: mlevine55 <mlevine55@bloomberg.net>
This commit is contained in:
mlevine55
2025-10-30 14:52:09 -04:00
committed by Marek Polacek
parent 063041c5a8
commit 4ca1672070
6 changed files with 605 additions and 3 deletions

View File

@@ -1340,6 +1340,18 @@ eval_is_class_member (tree r)
r = TYPE_NAME (r);
else if (VAR_P (r) && DECL_ANON_UNION_VAR_P (r))
return boolean_true_node;
else if (TREE_CODE (r) == BIT_NOT_EXPR
&& CLASS_TYPE_P (TREE_OPERAND (r, 0))
&& COMPLETE_TYPE_P (TREE_OPERAND (r, 0)))
{
// TODO: move this code into reusable function
tree t = TREE_OPERAND (r, 0);
if (CLASSTYPE_LAZY_DESTRUCTOR (t))
lazily_declare_fn (sfk_destructor, t);
if (tree dtor = CLASSTYPE_DESTRUCTOR (t))
r = dtor;
}
if (DECL_P (r) && DECL_CLASS_SCOPE_P (r))
return boolean_true_node;
else if (TYPE_P (r) && TYPE_CLASS_SCOPE_P (r))
@@ -1348,6 +1360,114 @@ eval_is_class_member (tree r)
return boolean_false_node;
}
/* Helper function for eval_is_{public, protected, private}. */
static tree
eval_is_expected_access (tree r, reflect_kind kind, tree expected_access)
{
if (eval_is_class_member (r) == boolean_true_node)
{
r = MAYBE_BASELINK_FUNCTIONS (r);
r = OVL_FIRST (r);
if (TYPE_P (r))
{
if (TYPE_NAME (r) == NULL_TREE || !DECL_P (TYPE_NAME (r)))
return boolean_false_node;
r = TYPE_NAME (r);
}
if (TREE_CODE (r) == BIT_NOT_EXPR)
{
// TODO: move this code into reusable function
tree t = TREE_OPERAND (r, 0);
if (CLASSTYPE_LAZY_DESTRUCTOR (t))
lazily_declare_fn (sfk_destructor, t);
r = CLASSTYPE_DESTRUCTOR (t);
gcc_assert (r != NULL_TREE);
}
bool matches = false;
if (expected_access == access_private_node)
matches = TREE_PRIVATE (r);
else if (expected_access == access_protected_node)
matches = TREE_PROTECTED (r);
else if (expected_access == access_public_node)
matches = !(TREE_PRIVATE (r) || TREE_PROTECTED (r));
else
gcc_unreachable ();
if (matches)
return boolean_true_node;
else
return boolean_false_node;
}
if (kind == REFLECT_BASE)
{
gcc_assert (TREE_CODE (r) == TREE_BINFO);
tree c = r;
while (BINFO_INHERITANCE_CHAIN (c))
c = BINFO_INHERITANCE_CHAIN (c);
vec<tree, va_gc> *accesses = BINFO_BASE_ACCESSES (c);
tree base_binfo;
for (unsigned ix = 0; BINFO_BASE_ITERATE (c, ix, base_binfo); ix++)
{
if (base_binfo == r)
{
tree access = (accesses ? (*accesses)[ix] : access_public_node);
if (access == expected_access)
return boolean_true_node;
else
return boolean_false_node;
}
}
gcc_unreachable ();
}
return boolean_false_node;
}
/* Process std::meta::is_public.
Returns: true if r represents either:
- a class member or unnamed bit-field that is public or
- a direct base class relationship (D, B) for which
B is a public base class of D.
Otherwise, false. */
static tree
eval_is_public (tree r, reflect_kind kind)
{
return eval_is_expected_access (r, kind, access_public_node);
}
/* Process std::meta::is_protected.
Returns: true if r represents either:
- a class member or unnamed bit-field that is protected, or
- a direct base class relationship (D, B) for which
B is a protected base class of D.
Otherwise, false. */
static tree
eval_is_protected (tree r, reflect_kind kind)
{
return eval_is_expected_access (r, kind, access_protected_node);
}
/* Process std::meta::is_private
Returns: true if r represents either:
- a class member or unnamed bit-field that is private, or
- a direct base class relationship (D, B) for which
B is a private base class of D.
Otherwise, false. */
static tree
eval_is_private (tree r, reflect_kind kind)
{
return eval_is_expected_access (r, kind, access_private_node);
}
/* Process std::meta::is_namespace_member.
Returns: true if r represents a namespace member. Otherwise, false. */
@@ -6887,8 +7007,11 @@ process_metafunction (const constexpr_ctx *ctx, tree fun, tree call,
case METAFN_CONSTANT_OF:
return eval_constant_of (loc, ctx, h, jump_target, fun);
case METAFN_IS_PUBLIC:
return eval_is_public (h, kind);
case METAFN_IS_PROTECTED:
return eval_is_protected (h, kind);
case METAFN_IS_PRIVATE:
return eval_is_private (h, kind);
case METAFN_IS_VIRTUAL:
case METAFN_IS_PURE_VIRTUAL:
case METAFN_IS_OVERRIDE:

View File

@@ -57,6 +57,7 @@ static_assert (!is_class_member (^^ns));
static_assert (!is_class_member (^^ns_alias));
static_assert (!is_class_member (reflect_constant (3)));
static_assert (!is_class_member (^^cls));
static_assert (is_class_member (^^cls::~cls));
static_assert (is_class_member (^^cls::dm));
static_assert (is_class_member (^^cls::ref_dm));
static_assert (is_class_member (^^cls::static_dm));

View File

@@ -0,0 +1,412 @@
// { dg-do compile { target c++26 } }
// { dg-additional-options "-freflection" }
// Tests std::meta::is_public, std::meta::is_private, std::meta::is_protected
#include <meta>
class PublicBase { };
class ProtectedBase { };
class PrivateBase { };
class VirtualBase { };
class VirtualProtectedBase { };
class A : public PublicBase, protected ProtectedBase, private PrivateBase,
virtual VirtualBase, protected virtual VirtualProtectedBase
{
void test_bases_visibility()
{
constexpr auto ctx = std::meta::access_context::unchecked();
static_assert (std::meta::bases_of (^^A, ctx).size() == 5);
static_assert (std::meta::is_public (std::meta::bases_of (^^A, ctx)[0]));
static_assert (std::meta::is_protected (std::meta::bases_of (^^A, ctx)[1]));
static_assert (std::meta::is_private (std::meta::bases_of (^^A, ctx)[2]));
static_assert (std::meta::is_private (std::meta::bases_of (^^A, ctx)[3]));
static_assert (std::meta::is_protected (std::meta::bases_of (^^A, ctx)[4]));
}
// private:
A(int)
{
int a;
static_assert (!std::meta::is_public (std::meta::parent_of (^^a)));
static_assert (!std::meta::is_protected (std::meta::parent_of (^^a)));
static_assert (std::meta::is_private (std::meta::parent_of (^^a)));
}
protected:
A(bool)
{
int a;
static_assert (!std::meta::is_public (std::meta::parent_of (^^a)));
static_assert (std::meta::is_protected (std::meta::parent_of (^^a)));
static_assert (!std::meta::is_private (std::meta::parent_of (^^a)));
}
~A() = default;
public:
A()
{
int a;
static_assert (std::meta::is_public (std::meta::parent_of (^^a)));
static_assert (!std::meta::is_protected (std::meta::parent_of (^^a)));
static_assert (!std::meta::is_private (std::meta::parent_of (^^a)));
}
int public_field;
static int public_static_field;
int public_function();
static int public_static_function();
virtual void public_virtual_function() = 0;
template <typename T>
void public_template_function();
template <typename T>
static void public_static_template_function();
using public_type_alias = int;
struct PublicCls {};
enum PublicEnum {
B, C, D
};
enum class PublicEnumClass {
E, F
};
union PublicUnion {};
protected:
int protected_field;
static int protected_static_field;
int protected_function();
static int protected_static_function();
virtual void protected_virtual_function() = 0;
template <typename T>
void protected_template_function();
template <typename T>
static void protected_static_template_function();
using protected_type_alias = int;
struct ProtectedCls {};
enum ProtectedEnum {
G, H
};
enum class ProtectedEnumClass {
I, J
};
union ProtectedUnion {};
private:
int private_field;
static int private_static_field;
int private_function();
static int private_static_function();
virtual void private_virtual_function() = 0;
template <typename T>
void private_template_function();
template <typename T>
static void private_static_template_function();
using private_type_alias = int;
struct PrivateCls {};
enum PrivateEnum {
K, L
};
enum class PrivateEnumClass {
M, N
};
union PrivateUnion {};
void test_is_public()
{
// positive cases for public class members
static_assert (std::meta::is_public (^^public_field));
static_assert (std::meta::is_public (^^public_static_field));
static_assert (std::meta::is_public(^^public_function));
static_assert (std::meta::is_public (^^public_static_function));
static_assert (std::meta::is_public (^^public_virtual_function));
static_assert (std::meta::is_public (^^public_template_function));
static_assert (std::meta::is_public (^^public_template_function<int>));
static_assert (std::meta::is_public (^^public_static_template_function));
static_assert (std::meta::is_public (^^public_static_template_function<int>));
static_assert (std::meta::is_public (^^public_type_alias));
static_assert (std::meta::is_public (^^PublicCls));
static_assert (std::meta::is_public (^^PublicUnion));
static_assert (std::meta::is_public (^^PublicEnum));
static_assert (std::meta::is_public (^^PublicEnumClass));
static_assert (std::meta::is_public (^^B));
static_assert (std::meta::is_public (^^C));
static_assert (std::meta::is_public (^^D));
// negative test cases
static_assert (!std::meta::is_public (^^A));
// scoped enum values are not class members
static_assert (!std::meta::is_public (^^PublicEnumClass::E));
static_assert (!std::meta::is_public (^^PublicEnumClass::F));
static_assert (!std::meta::is_public (^^ProtectedEnumClass::I));
static_assert (!std::meta::is_public (^^ProtectedEnumClass::J));
static_assert (!std::meta::is_public (^^PrivateEnumClass::M));
static_assert (!std::meta::is_public (^^PrivateEnumClass::N));
// protected class members
static_assert (!std::meta::is_public (^^~A));
static_assert (!std::meta::is_public (^^protected_field));
static_assert (!std::meta::is_public (^^protected_static_field));
static_assert (!std::meta::is_public (^^protected_function));
static_assert (!std::meta::is_public (^^protected_static_function));
static_assert (!std::meta::is_public (^^protected_virtual_function));
static_assert (!std::meta::is_public (^^protected_template_function));
static_assert (!std::meta::is_public (^^protected_template_function<int>));
static_assert (!std::meta::is_public (^^protected_static_template_function));
static_assert (!std::meta::is_public (^^protected_static_template_function<int>));
static_assert (!std::meta::is_public (^^protected_type_alias));
static_assert (!std::meta::is_public (^^ProtectedCls));
static_assert (!std::meta::is_public (^^ProtectedUnion));
static_assert (!std::meta::is_public (^^ProtectedEnum));
static_assert (!std::meta::is_public (^^ProtectedEnumClass));
static_assert (!std::meta::is_public (^^G));
static_assert (!std::meta::is_public (^^H));
// private class members
static_assert (!std::meta::is_public (^^private_field));
static_assert (!std::meta::is_public (^^private_static_field));
static_assert (!std::meta::is_public (^^private_function));
static_assert (!std::meta::is_public (^^private_static_function));
static_assert (!std::meta::is_public (^^private_virtual_function));
static_assert (!std::meta::is_public (^^private_template_function));
static_assert (!std::meta::is_public (^^private_template_function<int>));
static_assert (!std::meta::is_public (^^private_static_template_function));
static_assert (!std::meta::is_public (^^private_static_template_function<int>));
static_assert (!std::meta::is_public (^^private_type_alias));
static_assert (!std::meta::is_public (^^PrivateCls));
static_assert (!std::meta::is_public (^^PrivateUnion));
static_assert (!std::meta::is_public (^^PrivateEnum));
static_assert (!std::meta::is_public (^^PrivateEnumClass));
static_assert (!std::meta::is_public (^^K));
static_assert (!std::meta::is_public (^^L));
}
void test_is_protected()
{
// positive cases for protected class members
static_assert (std::meta::is_protected (^^~A));
static_assert (std::meta::is_protected (^^protected_field));
static_assert (std::meta::is_protected (^^protected_static_field));
static_assert (std::meta::is_protected (^^protected_function));
static_assert (std::meta::is_protected (^^protected_static_function));
static_assert (std::meta::is_protected (^^protected_virtual_function));
static_assert (std::meta::is_protected (^^protected_template_function));
static_assert (std::meta::is_protected (^^protected_template_function<int>));
static_assert (std::meta::is_protected (^^protected_static_template_function));
static_assert (std::meta::is_protected (^^protected_static_template_function<int>));
static_assert (std::meta::is_protected (^^protected_type_alias));
static_assert (std::meta::is_protected (^^ProtectedCls));
static_assert (std::meta::is_protected (^^ProtectedUnion));
static_assert (std::meta::is_protected (^^ProtectedEnum));
static_assert (std::meta::is_protected (^^ProtectedEnumClass));
static_assert (std::meta::is_protected (^^G));
static_assert (std::meta::is_protected (^^H));
// negative cases:
static_assert (!std::meta::is_protected (^^A));
// scoped enum values are not class members
static_assert (!std::meta::is_protected (^^PublicEnumClass::E));
static_assert (!std::meta::is_protected (^^PublicEnumClass::F));
static_assert (!std::meta::is_protected (^^ProtectedEnumClass::I));
static_assert (!std::meta::is_protected (^^ProtectedEnumClass::J));
static_assert (!std::meta::is_protected (^^PrivateEnumClass::M));
static_assert (!std::meta::is_protected (^^PrivateEnumClass::N));
// public class members
static_assert (!std::meta::is_protected (^^public_field));
static_assert (!std::meta::is_protected (^^public_static_field));
static_assert (!std::meta::is_protected (^^public_function));
static_assert (!std::meta::is_protected (^^public_static_function));
static_assert (!std::meta::is_protected (^^public_virtual_function));
static_assert (!std::meta::is_protected (^^public_template_function));
static_assert (!std::meta::is_protected (^^public_template_function<int>));
static_assert (!std::meta::is_protected (^^public_static_template_function));
static_assert (!std::meta::is_protected (^^public_static_template_function<int>));
static_assert (!std::meta::is_protected (^^public_type_alias));
static_assert (!std::meta::is_protected (^^PublicCls));
static_assert (!std::meta::is_protected (^^PublicUnion));
static_assert (!std::meta::is_protected (^^PublicEnum));
static_assert (!std::meta::is_protected (^^PublicEnumClass));
static_assert (!std::meta::is_protected (^^B));
static_assert (!std::meta::is_protected (^^C));
static_assert (!std::meta::is_protected (^^D));
// private class members
static_assert (!std::meta::is_protected (^^private_field));
static_assert (!std::meta::is_protected (^^private_static_field));
static_assert (!std::meta::is_protected (^^private_function));
static_assert (!std::meta::is_protected (^^private_static_function));
static_assert (!std::meta::is_protected (^^private_virtual_function));
static_assert (!std::meta::is_protected (^^private_template_function));
static_assert (!std::meta::is_protected (^^private_template_function<int>));
static_assert (!std::meta::is_protected (^^private_static_template_function));
static_assert (!std::meta::is_protected (^^private_static_template_function<int>));
static_assert (!std::meta::is_protected (^^private_type_alias));
static_assert (!std::meta::is_protected (^^PrivateCls));
static_assert (!std::meta::is_protected (^^PrivateUnion));
static_assert (!std::meta::is_protected (^^PrivateEnum));
static_assert (!std::meta::is_protected (^^PrivateEnumClass));
static_assert (!std::meta::is_protected (^^K));
static_assert (!std::meta::is_protected (^^L));
}
void test_is_private()
{
// positive test cases: private class members
static_assert (std::meta::is_private (^^private_field));
static_assert (std::meta::is_private (^^private_static_field));
static_assert (std::meta::is_private (^^private_function));
static_assert (std::meta::is_private (^^private_static_function));
static_assert (std::meta::is_private (^^private_virtual_function));
static_assert (std::meta::is_private (^^private_template_function));
static_assert (std::meta::is_private (^^private_template_function<int>));
static_assert (std::meta::is_private (^^private_static_template_function));
static_assert (std::meta::is_private (^^private_static_template_function<int>));
static_assert (std::meta::is_private (^^private_type_alias));
static_assert (std::meta::is_private (^^PrivateCls));
static_assert (std::meta::is_private (^^PrivateUnion));
static_assert (std::meta::is_private (^^PrivateEnum));
static_assert (std::meta::is_private (^^PrivateEnumClass));
static_assert (std::meta::is_private (^^K));
static_assert (std::meta::is_private (^^L));
// negative cases:
static_assert (!std::meta::is_private (^^A));
// scoped enum values are not class members
static_assert (!std::meta::is_private (^^PublicEnumClass::E));
static_assert (!std::meta::is_private (^^PublicEnumClass::F));
static_assert (!std::meta::is_private (^^ProtectedEnumClass::I));
static_assert (!std::meta::is_private (^^ProtectedEnumClass::J));
static_assert (!std::meta::is_private (^^PrivateEnumClass::M));
static_assert (!std::meta::is_private (^^PrivateEnumClass::N));
// public class members
static_assert (!std::meta::is_private (^^public_field));
static_assert (!std::meta::is_private (^^public_static_field));
static_assert (!std::meta::is_private (^^public_function));
static_assert (!std::meta::is_private (^^public_static_function));
static_assert (!std::meta::is_private (^^public_virtual_function));
static_assert (!std::meta::is_private (^^public_template_function));
static_assert (!std::meta::is_private (^^public_template_function<int>));
static_assert (!std::meta::is_private (^^public_static_template_function));
static_assert (!std::meta::is_private (^^public_static_template_function<int>));
static_assert (!std::meta::is_private (^^public_type_alias));
static_assert (!std::meta::is_private (^^PublicCls));
static_assert (!std::meta::is_private (^^PublicUnion));
static_assert (!std::meta::is_private (^^PublicEnum));
static_assert (!std::meta::is_private (^^PublicEnumClass));
static_assert (!std::meta::is_private (^^B));
static_assert (!std::meta::is_private (^^C));
static_assert (!std::meta::is_private (^^D));
// protected class members
static_assert (!std::meta::is_private (^^~A));
static_assert (!std::meta::is_private (^^protected_field));
static_assert (!std::meta::is_private (^^protected_static_field));
static_assert (!std::meta::is_private (^^protected_function));
static_assert (!std::meta::is_private (^^protected_static_function));
static_assert (!std::meta::is_private (^^protected_virtual_function));
static_assert (!std::meta::is_private (^^protected_template_function));
static_assert (!std::meta::is_private (^^protected_template_function<int>));
static_assert (!std::meta::is_private (^^protected_static_template_function));
static_assert (!std::meta::is_private (^^protected_static_template_function<int>));
static_assert (!std::meta::is_private (^^protected_type_alias));
static_assert (!std::meta::is_private (^^ProtectedCls));
static_assert (!std::meta::is_private (^^ProtectedUnion));
static_assert (!std::meta::is_private (^^ProtectedEnum));
static_assert (!std::meta::is_private (^^ProtectedEnumClass));
static_assert (!std::meta::is_private (^^G));
static_assert (!std::meta::is_private (^^H));
}
};

View File

@@ -0,0 +1,62 @@
// { dg-do compile { target c++26 } }
// { dg-additional-options "-freflection" }
// Tests std::meta::is_public, std::meta::is_private, std::meta::is_protected
#include <meta>
// Test bit-fields
struct S {
unsigned char b1 : 3;
protected:
unsigned char : 2;
private:
unsigned char b2 : 6;
};
constexpr auto ctx = std::meta::access_context::unchecked();
static_assert (std::meta::members_of (^^S, ctx).size() > 3);
static_assert (std::meta::is_bit_field (std::meta::members_of (^^S, ctx)[0]));
static_assert (std::meta::has_identifier (std::meta::members_of (^^S, ctx)[0]));
static_assert (std::meta::is_public (std::meta::members_of (^^S, ctx)[0]));
static_assert (std::meta::is_bit_field (std::meta::members_of (^^S, ctx)[1]));
static_assert (!std::meta::has_identifier (std::meta::members_of (^^S, ctx)[1]));
static_assert (std::meta::is_protected (std::meta::members_of (^^S, ctx)[1]));
static_assert (std::meta::is_bit_field (std::meta::members_of (^^S, ctx)[2]));
static_assert (std::meta::has_identifier (std::meta::members_of (^^S, ctx)[2]));
static_assert (std::meta::is_private (std::meta::members_of (^^S, ctx)[2]));
// Test inheritance and change of access modifier
class A {
protected:
int protected_member;
void protected_function();
virtual void protected_virtual_function();
void test() {
static_assert (std::meta::is_protected (^^protected_member));
static_assert (std::meta::is_protected (^^protected_function));
static_assert (std::meta::is_protected (^^protected_virtual_function));
}
};
class B : public A {
private:
void protected_virtual_function() override;
void test() {
static_assert (std::meta::is_protected (^^B::protected_member));
static_assert (std::meta::is_protected (^^B::protected_function));
static_assert (std::meta::is_protected (^^A::protected_virtual_function));
static_assert (std::meta::is_private (^^B::protected_virtual_function));
}
};
// TODO: add more tests for inheritance and change of access modification
// TODO: add more tests for base access during multilevel inheritence

View File

@@ -201,6 +201,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
consteval info object_of(info);
consteval info constant_of(info);
consteval bool is_public(info);
consteval bool is_protected(info);
consteval bool is_private(info);
consteval bool is_deleted(info);
consteval bool is_defaulted(info);
consteval bool is_user_provided(info);

View File

@@ -2085,9 +2085,9 @@ export namespace std
using std::meta::type_of;
using std::meta::object_of;
using std::meta::constant_of;
// using std::meta::is_public;
// using std::meta::is_protected;
// using std::meta::is_private;
using std::meta::is_public;
using std::meta::is_protected;
using std::meta::is_private;
// using std::meta::is_virtual;
// using std::meta::is_pure_virtual;
// using std::meta::is_override;