From 9171cf41efdbbc28325e6da80b022f8bf4f22f67 Mon Sep 17 00:00:00 2001 From: zebullax Date: Wed, 22 Oct 2025 17:46:23 +0900 Subject: [PATCH] Fix is_public and is_class_member for scoped/unscoped enum (#194) * Add bubble up for unscoped enum in membership check Check membership for public check access Signed-off-by: zebullax * Fix golden copy for generated headers Signed-off-by: zebullax * Skip validation of reflection unittest that introduce non ascii character Signed-off-by: zebullax * Check class membership for is_private/protected/public Signed-off-by: zebullax --------- Signed-off-by: zebullax --- clang/lib/AST/ExprConstantMeta.cpp | 61 +++++++++++++++---- libcxx/modules/std.cppm.in | 1 + .../reflection/member-visibility.pass.cpp | 29 +++++++++ libcxx/utils/ci/run-buildbot | 2 + 4 files changed, 81 insertions(+), 12 deletions(-) diff --git a/clang/lib/AST/ExprConstantMeta.cpp b/clang/lib/AST/ExprConstantMeta.cpp index 0808f3124833..c8240ec62251 100644 --- a/clang/lib/AST/ExprConstantMeta.cpp +++ b/clang/lib/AST/ExprConstantMeta.cpp @@ -3324,31 +3324,62 @@ bool is_ACCESS(APValue &Result, ASTContext &C, MetaActions &Meta, llvm_unreachable("invalid reflection type"); } +template +static inline +bool is_ClassMember_ACCESS(APValue &Result, ASTContext &C, MetaActions &Meta, + EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, + QualType ResultTy, SourceRange Range, ArrayRef Args, + Decl *ContainingDecl) { + [[maybe_unused]] bool scratch + = is_class_member(Result, C, Meta, Evaluator, Diagnoser, + AllowInjection, ResultTy, Range, Args, + ContainingDecl); + + if (const bool isClassMember = Result.getInt().getBoolValue();isClassMember) { + return is_ACCESS(Result, C, Meta, Evaluator, Diagnoser, + AllowInjection, ResultTy, Range, Args, + ContainingDecl); + } + // fallthrough: base-class relationship + scratch = is_base(Result, C, Meta, Evaluator, Diagnoser, + AllowInjection, ResultTy, Range, Args, + ContainingDecl); + if (const bool isBaseClass = Result.getInt().getBoolValue();isBaseClass) { + return is_ACCESS(Result, C, Meta, Evaluator, Diagnoser, + AllowInjection, ResultTy, Range, Args, + ContainingDecl); + } + return false; +} + bool is_public(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { - return is_ACCESS(Result, C, Meta, Evaluator, Diagnoser, - AllowInjection, ResultTy, Range, Args, - ContainingDecl); + return is_ClassMember_ACCESS( + Result, C, Meta, Evaluator, Diagnoser, + AllowInjection, ResultTy, Range, Args, + ContainingDecl); } bool is_protected(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { - return is_ACCESS(Result, C, Meta, Evaluator, Diagnoser, - AllowInjection, ResultTy, Range, Args, - ContainingDecl); + return is_ClassMember_ACCESS( + Result, C, Meta, Evaluator, Diagnoser, + AllowInjection, ResultTy, Range, Args, + ContainingDecl); } bool is_private(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { - return is_ACCESS(Result, C, Meta, Evaluator, Diagnoser, - AllowInjection, ResultTy, Range, Args, - ContainingDecl); + return is_ClassMember_ACCESS( + Result, C, Meta, Evaluator, Diagnoser, + AllowInjection, ResultTy, Range, Args, + ContainingDecl); } bool is_virtual(APValue &Result, ASTContext &C, MetaActions &Meta, @@ -3890,7 +3921,6 @@ bool is_class_member(APValue &Result, ASTContext &C, MetaActions &Meta, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); - APValue Scratch; bool result = false; @@ -3898,8 +3928,15 @@ bool is_class_member(APValue &Result, ASTContext &C, MetaActions &Meta, if (!parent_of(Scratch, C, Meta, Evaluator, SwallowDiags, AllowInjection, C.MetaInfoTy, Range, Args, ContainingDecl)) { assert(Scratch.isReflection()); - result = Scratch.isReflectedType() && - Scratch.getReflectedType()->isRecordType(); + // For unscoped enumerators, parent_of will return its enumeration type + // We need now to lookup context on that type + if (Scratch.isReflectedType() && Scratch.getReflectedType()->isUnscopedEnumerationType()) { + Decl *D = findTypeDecl(Scratch.getReflectedType()); + result = D && D->getDeclContext() && D->getDeclContext()->isRecord(); + } else { + result = Scratch.isReflectedType() && + Scratch.getReflectedType()->isRecordType(); + } } return SetAndSucceed(Result, makeBool(C, result)); } diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in index 984b18321923..578c0161b632 100644 --- a/libcxx/modules/std.cppm.in +++ b/libcxx/modules/std.cppm.in @@ -82,6 +82,7 @@ module; #include #include #include +#include #include #include #include diff --git a/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp b/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp index 8f6b56da96c2..438717f2ed3b 100644 --- a/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp +++ b/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp @@ -392,4 +392,33 @@ struct D : A, protected B, private C { } // namespace bb_clang_p2996_issue_148_regression_test + // ======================================== + // bb_clang_p2996_issue_193_regression_test + // ======================================== + +namespace bb_clang_p2996_issue_193_regression_test { +struct S { + enum E { + A + }; + + enum class SE { + B + }; +}; + +static_assert(std::meta::is_class_member(^^S::E)); +static_assert(std::meta::is_class_member(^^S::SE)); + +static_assert(std::meta::is_public(^^S::E)); +static_assert(std::meta::is_public(^^S::SE)); + +static_assert(std::meta::is_class_member(^^S::E::A)); +static_assert(!std::meta::is_class_member(^^S::SE::B)); + +static_assert(std::meta::is_public(^^S::E::A)); +static_assert(!std::meta::is_public(^^S::SE::B)); + +} // namespace bb_clang_p2996_issue_193_regression_test + int main() { } diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot index d8b23be9a032..f063e906832b 100755 --- a/libcxx/utils/ci/run-buildbot +++ b/libcxx/utils/ci/run-buildbot @@ -282,6 +282,8 @@ check-generated-output) --exclude 'ostream.pass.cpp' \ --exclude 'transcoding.pass.cpp' \ --exclude 'underflow.pass.cpp' \ + --exclude 'define-aggregate.pass.cpp' \ + --exclude 'names.pass.cpp' \ || false ;; #