diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h index 303fdffa4984..bc5b5b3ba7e1 100644 --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -42,6 +42,7 @@ template class BasicReaderBase; class NamespaceDecl; struct PrintingPolicy; class Type; + class UsingShadowDecl; class ValueDecl; class QualType; @@ -560,6 +561,9 @@ public: bool isReflectedNamespace() const { return isReflection() && getReflectionKind() == ReflectionKind::Namespace; } + bool isReflectedEntityProxy() const { + return isReflection() && getReflectionKind() == ReflectionKind::EntityProxy; + } bool isReflectedBaseSpecifier() const { return isReflection() && getReflectionKind() == ReflectionKind::BaseSpecifier; @@ -758,6 +762,7 @@ public: ValueDecl *getReflectedDecl() const; const TemplateName getReflectedTemplate() const; Decl *getReflectedNamespace() const; + UsingShadowDecl *getReflectedEntityProxy() const; CXXBaseSpecifier *getReflectedBaseSpecifier() const; TagDataMemberSpec *getReflectedDataMemberSpec() const; CXX26AnnotationAttr *getReflectedAnnotation() const; diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 4b8b0d3f5a71..31372d2e7c39 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -501,6 +501,10 @@ let Class = PropertyTypeCase in { let Conditional = [{ kind == ReflectionKind::Namespace }]; let Read = [{ base.getReflectedNamespace() }]; } + def : Property<"baseEntityProxy", UsingShadowDeclRef> { + let Conditional = [{ kind == ReflectionKind::EntityProxy }]; + let Read = [{ base.getReflectedEntityProxy() }]; + } def : Property<"baseBaseSpecDerivedFrom", CXXRecordDeclRef> { let Conditional = [{ kind == ReflectionKind::BaseSpecifier }]; let Read = [{ base.getReflectedBaseSpecifier()->getDerived() }]; @@ -565,6 +569,9 @@ let Class = PropertyTypeCase in { case ReflectionKind::Namespace: V = APValue(kind, *baseNamespace); break; + case ReflectionKind::EntityProxy: + V = APValue(kind, *baseEntityProxy); + break; case ReflectionKind::BaseSpecifier: V = APValue( kind, diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 6004d0eee770..575bf8b0120f 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3043,6 +3043,10 @@ DEF_TRAVERSE_STMT(CXXReflectExpr, { TRY_TO(TraverseTemplateName(RV.getReflectedTemplate())); break; } + case ReflectionKind::EntityProxy: { + TRY_TO(TraverseDecl(RV.getReflectedEntityProxy())); + break; + } case ReflectionKind::Annotation: { TRY_TO(TraverseStmt(RV.getReflectedAnnotation()->getArg())); break; diff --git a/clang/include/clang/AST/Reflection.h b/clang/include/clang/AST/Reflection.h index 5838d310e00c..7e80f5d17c07 100644 --- a/clang/include/clang/AST/Reflection.h +++ b/clang/include/clang/AST/Reflection.h @@ -82,6 +82,11 @@ enum class ReflectionKind { /// the Decl class. Namespace, + /// \brief A reflection of an entity proxy. + /// + /// Corresponds to a UsingShadowDecl. + EntityProxy, + /// \brief A reflection of a base class specifier. /// /// Corresponds to a CXXBaseSpecifier. diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 33c9bece0e06..9e8b9f6ea4f9 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -102,8 +102,8 @@ def err_fe_invalid_code_complete_file : Error< def err_fe_parameter_reflection_without_reflection : Error< "cannot specify '-fparameter-reflection' without '-freflection'">, DefaultFatal; -def err_fe_access_contexts_without_reflection : Error< - "cannot specify '-faccess-contexts' without '-freflection'">, +def err_fe_entity_proxy_reflection_without_reflection : Error< + "cannot specify '-fentity-proxy-reflection' without '-freflection'">, DefaultFatal; def err_fe_dependency_file_requires_MT : Error< "-dependency-file requires at least one -MT or -MQ option">; diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index d1d320158c28..337b10674790 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -320,7 +320,7 @@ FEATURE(reflection, LangOpts.Reflection) FEATURE(parameter_reflection, LangOpts.ParameterReflection) FEATURE(expansion_statements, LangOpts.ExpansionStatements) FEATURE(annotation_attributes, LangOpts.AnnotationAttributes) -FEATURE(access_contexts, LangOpts.AccessContexts) +FEATURE(entity_proxy_reflection, LangOpts.EntityProxyReflection) FEATURE(reflection_latest, LangOpts.ReflectionLatest) // CUDA/HIP Features diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 3c8258f63314..8c5df22888f2 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -310,12 +310,12 @@ LANGOPT(HIPStdParInterposeAlloc, 1, 0, "Replace allocations / deallocations with LANGOPT(OpenACC , 1, 0, "OpenACC Enabled") -LANGOPT(Reflection , 1, 0, "Experimental C++26 Reflection") -LANGOPT(ParameterReflection , 1, 0, "Augments C++26 Reflection with function parameter reflection") -LANGOPT(ExpansionStatements , 1, 0, "Experimental C++26 Expansion Statements") -LANGOPT(AnnotationAttributes, 1, 0, "Experimental C++26 support for annotations") -LANGOPT(AccessContexts, 1, 0, "Experimental C++26 support for reflection with access contexts") -LANGOPT(ReflectionLatest , 1, 0, "Enable all experimental C++26 features supported by Clang/P2996") +LANGOPT(Reflection , 1, 0, "Experimental C++26 Reflection") +LANGOPT(ParameterReflection , 1, 0, "Augments C++26 Reflection with function parameter reflection") +LANGOPT(ExpansionStatements , 1, 0, "Experimental C++26 Expansion Statements") +LANGOPT(AnnotationAttributes, 1, 0, "Experimental C++26 support for annotations") +LANGOPT(EntityProxyReflection, 1, 0, "Augments C++26 Reflection with entity proxy reflection") +LANGOPT(ReflectionLatest , 1, 0, "Enable all experimental C++26 features supported by Clang/P2996") LANGOPT(MSVCEnableStdcMacro , 1, 0, "Define __STDC__ with '-fms-compatibility'") LANGOPT(SizedDeallocation , 1, 0, "sized deallocation") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 5620c82142fa..3e5a43b57c49 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3531,10 +3531,10 @@ defm annotation_attributes : BoolFOption<"annotation-attributes", PosFlag, NegFlag>; -defm access_contexts : BoolFOption<"access-contexts", - LangOpts<"AccessContexts">, DefaultFalse, +defm entity_proxy_reflection : BoolFOption<"entity-proxy-reflection", + LangOpts<"EntityProxyReflection">, DefaultFalse, PosFlag, + "Enable proposed reflection of entity proxies as described by P3XYZ">, NegFlag>; defm reflection_latest : BoolFOption<"reflection-latest", LangOpts<"ReflectionLatest">, DefaultFalse, diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index c87cfd49d873..25fe9e380b03 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -553,6 +553,7 @@ static void profileReflection(llvm::FoldingSetNodeID &ID, APValue V) { return; } case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Annotation: ID.AddPointer(V.getOpaqueReflectionData()); @@ -929,6 +930,13 @@ Decl *APValue::getReflectedNamespace() const { const_cast(getOpaqueReflectionData())); } +UsingShadowDecl *APValue::getReflectedEntityProxy() const { + assert(getReflectionKind() == ReflectionKind::EntityProxy && + "not a reflection of an entity proxy"); + return reinterpret_cast( + const_cast(getOpaqueReflectionData())); +} + CXXBaseSpecifier *APValue::getReflectedBaseSpecifier() const { assert(getReflectionKind() == ReflectionKind::BaseSpecifier && "not a reflection of a base specifier"); @@ -1294,6 +1302,9 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy, case ReflectionKind::Namespace: Repr = "namespace"; break; + case ReflectionKind::EntityProxy: + Repr = "entity-proxy"; + break; case ReflectionKind::BaseSpecifier: Repr = "base-specifier"; break; @@ -1636,6 +1647,7 @@ void APValue::setReflection(ReflectionKind RK, const void *Ptr) { case ReflectionKind::Declaration: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 4b6f70d8b013..35c77d12751e 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -947,8 +947,23 @@ ExprDependence clang::computeDependence(CXXReflectExpr *E, if (E->hasDependentSubExpr()) return E->getDependentSubExpr()->getDependence(); - APValue RV = E->getReflection(); ExprDependence D = ExprDependence::None; + + // Unwrap entity proxies. + APValue RV = E->getReflection(); + if (RV.isReflectedEntityProxy()) { + NamedDecl *ND = RV.getReflectedEntityProxy()->getTargetDecl(); + + if (auto *T = dyn_cast(ND)) { + QualType QT = Ctx.getTypeDeclType(T); + RV = APValue(ReflectionKind::Type, QT.getAsOpaquePtr()); + } else if (auto *T = dyn_cast(ND)) { + RV = APValue(ReflectionKind::Template, T); + } else { + RV = APValue(ReflectionKind::Declaration, ND); + } + } + switch (RV.getReflectionKind()) { case ReflectionKind::Type: { QualType T = RV.getReflectedType(); @@ -989,6 +1004,8 @@ ExprDependence clang::computeDependence(CXXReflectExpr *E, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: return ExprDependence::None; + case ReflectionKind::EntityProxy: + llvm_unreachable("should already have been unwrapped"); } llvm_unreachable("unknown reflection kind while computing dependence"); } diff --git a/clang/lib/AST/ExprConstantMeta.cpp b/clang/lib/AST/ExprConstantMeta.cpp index 07aee2372519..b393fcd7d2f2 100644 --- a/clang/lib/AST/ExprConstantMeta.cpp +++ b/clang/lib/AST/ExprConstantMeta.cpp @@ -1,6 +1,6 @@ //===-- ExprConstantMeta.cpp - Functions targeting reflections --*- C++ -*-===// // -// Copyright 2024 Bloomberg Finance L.P. +// Copyright 2025 Bloomberg Finance L.P. // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -364,6 +364,12 @@ static bool is_alias(APValue &Result, ASTContext &C, MetaActions &Meta, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); +static bool is_entity_proxy(APValue &Result, ASTContext &C, MetaActions &Meta, + EvalFn Evaluator, DiagFn Diagnoser, + bool AllowInjection, QualType ResultTy, + SourceRange Range, ArrayRef Args, + Decl *ContainingDecl); + static bool is_complete_type(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, @@ -776,6 +782,7 @@ static constexpr Metafunction Metafunctions[] = { { Metafunction::MFRK_bool, 1, 1, is_variable }, { Metafunction::MFRK_bool, 1, 1, is_type }, { Metafunction::MFRK_bool, 1, 1, is_alias }, + { Metafunction::MFRK_bool, 1, 1, is_entity_proxy }, { Metafunction::MFRK_bool, 1, 1, is_complete_type }, { Metafunction::MFRK_bool, 1, 1, has_complete_definition }, { Metafunction::MFRK_bool, 1, 1, is_enumerable_type }, @@ -883,6 +890,8 @@ static APValue makeReflection(Decl *D) { return APValue(ReflectionKind::Namespace, D); else if (isa(D)) return APValue(ReflectionKind::Template, D); + else if (isa(D)) + return APValue(ReflectionKind::EntityProxy, D); return APValue(ReflectionKind::Declaration, D); } @@ -1317,14 +1326,18 @@ static bool ensureDeclared(ASTContext &C, QualType QT, SourceLocation SpecLoc) { return true; } -static bool isReflectableDecl(MetaActions &Meta, Decl *D) { +static bool isReflectableDecl(MetaActions &Meta, ASTContext &C, Decl *D) { assert(D && "null declaration"); if (isa(D)) return true; if (!isa(D)) + NamespaceDecl, NamespaceAliasDecl, TranslationUnitDecl, + UsingShadowDecl>(D)) + return false; + + if (isa(D) && !C.getLangOpts().EntityProxyReflection) return false; if (auto *Class = dyn_cast(D)) @@ -1348,17 +1361,18 @@ static bool isReflectableDecl(MetaActions &Meta, Decl *D) { } /// Filter non-reflectable members. -static Decl *findIterableMember(MetaActions &Meta, Decl *D, bool Inclusive) { +static Decl *findIterableMember(MetaActions &Meta, ASTContext &C, Decl *D, + bool Inclusive) { if (!D) return D; if (Inclusive) { - if (isReflectableDecl(Meta, D)) + if (isReflectableDecl(Meta, C, D)) return D; // Handle the case where the first Decl is a LinkageSpecDecl. if (auto *LSDecl = dyn_cast_or_null(D)) { - Decl *RecD = findIterableMember(Meta, *LSDecl->decls_begin(), true); + Decl *RecD = findIterableMember(Meta, C, *LSDecl->decls_begin(), true); if (RecD) return RecD; } } @@ -1389,14 +1403,14 @@ static Decl *findIterableMember(MetaActions &Meta, Decl *D, bool Inclusive) { // We need to recursively descend into LinkageSpecDecls to iterate over the // members declared therein (e.g., `extern "C"` blocks). if (auto *LSDecl = dyn_cast_or_null(D)) { - Decl *RecD = findIterableMember(Meta, *LSDecl->decls_begin(), true); + Decl *RecD = findIterableMember(Meta, C, *LSDecl->decls_begin(), true); if (RecD) return RecD; } // Pop back out of a recursively entered LinkageSpecDecl. if (!D && isa(DC)) - return findIterableMember(Meta, cast(DC), false); - } while (D && !isReflectableDecl(Meta, D)); + return findIterableMember(Meta, C, cast(DC), false); + } while (D && !isReflectableDecl(Meta, C, D)); return D; } @@ -1513,6 +1527,27 @@ QualType ComputeResultType(QualType ExprTy, const APValue &V) { /*DropRefs=*/true); } +static APValue MaybeUnproxy(ASTContext &C, APValue RV, bool Dealias = true) { + assert(RV.isReflection()); + + if (!RV.isReflectedEntityProxy()) + return RV; + + NamedDecl *ND = RV.getReflectedEntityProxy()->getTargetDecl(); + if (auto *T = dyn_cast(ND)) { + QualType QT = C.getTypeDeclType(T); + if (Dealias) + QT = desugarType(QT, /*UnwrapAlias=*/true, /*DropCV=*/false, + /*DropRefs=*/false); + + return APValue(ReflectionKind::Type, QT.getAsOpaquePtr()); + } else if (auto *T = dyn_cast(ND)) { + return APValue(ReflectionKind::Template, T); + } + + return APValue(ReflectionKind::Declaration, ND); +} + // ----------------------------------------------------------------------------- // Diagnostic helper function @@ -1589,6 +1624,9 @@ StringRef DescriptionOf(APValue RV, bool Granular = true) { else if (isa(D)) return "a namespace"; llvm_unreachable("unhandled namespace kind"); } + case ReflectionKind::EntityProxy: { + return "an entity proxy"; + } case ReflectionKind::BaseSpecifier: { return "a base class specifier"; } @@ -1654,6 +1692,7 @@ bool get_begin_enumerator_decl_of(APValue &Result, ASTContext &C, case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: { @@ -1695,6 +1734,7 @@ bool get_next_enumerator_decl_of(APValue &Result, ASTContext &C, case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: { @@ -1752,6 +1792,7 @@ bool get_ith_base_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: @@ -1812,6 +1853,7 @@ bool get_ith_template_argument_of(APValue &Result, ASTContext &C, case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: @@ -1877,7 +1919,7 @@ bool get_begin_member_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, DeclContext *declContext = dyn_cast(typeDecl); assert(declContext && "no DeclContext?"); - Decl* beginMember = findIterableMember(Meta, *declContext->decls_begin(), + Decl* beginMember = findIterableMember(Meta, C, *declContext->decls_begin(), true); if (!beginMember) return SetAndSucceed(Result, Sentinel); @@ -1891,7 +1933,7 @@ bool get_begin_member_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, DeclContext *DC = cast(NS->getMostRecentDecl()); - Decl *beginMember = findIterableMember(Meta, *DC->decls_begin(), true); + Decl *beginMember = findIterableMember(Meta, C, *DC->decls_begin(), true); if (!beginMember) return SetAndSucceed(Result, Sentinel); return SetAndSucceed(Result, @@ -1899,6 +1941,7 @@ bool get_begin_member_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, } case ReflectionKind::Null: case ReflectionKind::Declaration: + case ReflectionKind::EntityProxy: case ReflectionKind::Template: case ReflectionKind::Object: case ReflectionKind::Value: @@ -1921,14 +1964,14 @@ bool get_next_member_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, APValue RV; if (!Evaluator(RV, Args[0], true)) return true; - assert(Args[1]->getType()->isReflectionType()); + APValue Sentinel; if (!Evaluator(Sentinel, Args[1], true)) return true; assert(Sentinel.isReflectedType()); - if (Decl *Next = findIterableMember(Meta, RV.getReflectedDecl(), false)) + if (Decl *Next = findIterableMember(Meta, C, RV.getReflectedDecl(), false)) return SetAndSucceed(Result, APValue(ReflectionKind::Declaration, Next)); return SetAndSucceed(Result, Sentinel); } @@ -1970,13 +2013,8 @@ bool map_decl_to_entity(APValue &Result, ASTContext &C, MetaActions &Meta, if (auto *TyDecl = dyn_cast(D)) { QualType QT = C.getTypeDeclType(TyDecl); return SetAndSucceed(Result, makeReflection(QT)); - } else if (auto *TDecl = dyn_cast(D)) { - TemplateName TName(TDecl); - return SetAndSucceed(Result, makeReflection(TName)); - } else { - return SetAndSucceed(Result, makeReflection(D)); } - llvm_unreachable("unknown reflection kind"); + return SetAndSucceed(Result, makeReflection(D)); } bool identifier_of(APValue &Result, ASTContext &C, MetaActions &Meta, @@ -2005,6 +2043,8 @@ bool identifier_of(APValue &Result, ASTContext &C, MetaActions &Meta, EnforceConsistent = Scratch.getInt().getBoolValue(); } + RV = MaybeUnproxy(C, RV, /*Dealias=*/false); + std::string Name; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { @@ -2102,6 +2142,8 @@ bool identifier_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_have_name) << DescriptionOf(RV) << Range; + case ReflectionKind::EntityProxy: + llvm_unreachable("proxies should already have been unwrapped"); } if (Name.empty()) return Diagnoser(Range.getBegin(), diag::metafn_anonymous_entity) @@ -2124,6 +2166,8 @@ bool has_identifier(APValue &Result, ASTContext &C, MetaActions &Meta, if (!Evaluator(RV, Args[0], true)) return true; + RV = MaybeUnproxy(C, RV, /*Dealias=*/false); + bool HasIdentifier = false; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { @@ -2181,6 +2225,8 @@ bool has_identifier(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Value: case ReflectionKind::Annotation: break; + case ReflectionKind::EntityProxy: + llvm_unreachable("proxies should already have been unwrapped"); } return SetAndSucceed(Result, makeBool(C, HasIdentifier)); @@ -2221,6 +2267,8 @@ bool operator_of(APValue &Result, ASTContext &C, MetaActions &Meta, if (!Evaluator(RV, Args[0], true)) return true; + RV = MaybeUnproxy(C, RV); + size_t OperatorId = 0; if (RV.isReflectedTemplate()) { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); @@ -2263,6 +2311,9 @@ bool source_location_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Namespace: return findDeclLoc(Result, C, Evaluator, ResultTy, RV.getReflectedNamespace()); + case ReflectionKind::EntityProxy: + return findDeclLoc(Result, C, Evaluator, ResultTy, + RV.getReflectedEntityProxy()); case ReflectionKind::BaseSpecifier: return findBaseSpecLoc(Result, C, Evaluator, ResultTy, RV.getReflectedBaseSpecifier()); @@ -2293,6 +2344,7 @@ bool type_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Type: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: return Diagnoser(Range.getBegin(), diag::metafn_no_associated_property) << DescriptionOf(RV) << 0 << Range; case ReflectionKind::Object: @@ -2391,6 +2443,8 @@ bool parent_of(APValue &Result, ASTContext &C, MetaActions &Meta, return true; } return DiagWrapper(parentOf(Result, RV.getReflectedNamespace())); + case ReflectionKind::EntityProxy: + return DiagWrapper(parentOf(Result, RV.getReflectedEntityProxy())); case ReflectionKind::BaseSpecifier: { CXXRecordDecl *RD = RV.getReflectedBaseSpecifier()->getDerived(); QualType QT = desugarType(QualType(RD->getTypeForDecl(), 0), @@ -2435,6 +2489,8 @@ bool dealias(APValue &Result, ASTContext &C, MetaActions &Meta, NS = A->getNamespace(); return SetAndSucceed(Result, makeReflection(NS)); } + case ReflectionKind::EntityProxy: + return SetAndSucceed(Result, MaybeUnproxy(C, RV)); } llvm_unreachable("unknown reflection kind"); } @@ -2481,15 +2537,16 @@ bool object_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Null: case ReflectionKind::Value: case ReflectionKind::Type: - case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: + case ReflectionKind::Template: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 1 << DescriptionOf(RV) << Range; } - llvm_unreachable("unimplemented"); + llvm_unreachable("unknown reflection kind"); } @@ -2580,12 +2637,13 @@ bool value_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Type: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 2 << DescriptionOf(RV) << Range; } - llvm_unreachable("unimplemented"); + llvm_unreachable("unknown reflection kind"); } bool template_of(APValue &Result, ASTContext &C, MetaActions &Meta, @@ -2621,6 +2679,7 @@ bool template_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: @@ -2649,6 +2708,8 @@ static bool CanActAsTemplateArg(const APValue &RV) { case ReflectionKind::Annotation: case ReflectionKind::Null: return false; + case ReflectionKind::EntityProxy: + llvm_unreachable("expected proxies to have been unwrapped before calling"); } llvm_unreachable("unknown reflection kind"); } @@ -2692,6 +2753,8 @@ static TemplateArgument TArgFromReflection(ASTContext &C, EvalFn Evaluator, case ReflectionKind::Template: return TemplateArgument(RV.getReflectedTemplate()); break; + case ReflectionKind::EntityProxy: + llvm_unreachable("expected proxies to have been unwrapped before calling"); default: llvm_unreachable("unimplemented for template argument kind"); } @@ -2744,6 +2807,7 @@ bool can_substitute(APValue &Result, ASTContext &C, MetaActions &Meta, if (!Evaluator(Unwrapped, Synthesized, true) || !Unwrapped.isReflection()) return true; + Unwrapped = MaybeUnproxy(C, Unwrapped); if (!CanActAsTemplateArg(Unwrapped)) return SetAndSucceed(Result, makeBool(C, false)); @@ -2807,6 +2871,7 @@ bool substitute(APValue &Result, ASTContext &C, MetaActions &Meta, if (!Evaluator(Unwrapped, Synthesized, true) || !Unwrapped.isReflection()) return true; + Unwrapped = MaybeUnproxy(C, Unwrapped); if (!CanActAsTemplateArg(Unwrapped)) return Diagnoser(Range.getBegin(), diag::metafn_cannot_be_arg) << DescriptionOf(Unwrapped) << 1 << Range; @@ -3095,6 +3160,7 @@ bool extract(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Type: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: return Diagnoser(Range.getBegin(), diag::metafn_cannot_extract) @@ -3127,6 +3193,11 @@ bool is_ACCESS(APValue &Result, ASTContext &C, MetaActions &Meta, bool HasTargetAccess = (RV.getReflectedDecl()->getAccess() == Specifier); return SetAndSucceed(Result, makeBool(C, HasTargetAccess)); } + case ReflectionKind::EntityProxy: { + bool HasTargetAccess = (RV.getReflectedEntityProxy()->getAccess() == + Specifier); + return SetAndSucceed(Result, makeBool(C, HasTargetAccess)); + } case ReflectionKind::Template: { const Decl *D = RV.getReflectedTemplate().getAsTemplateDecl(); @@ -3204,6 +3275,7 @@ bool is_virtual(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, IsVirtual)); @@ -3385,6 +3457,7 @@ bool is_const(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: @@ -3426,6 +3499,7 @@ bool is_volatile(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: @@ -3721,7 +3795,8 @@ 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(); + result = Scratch.isReflectedType() && + Scratch.getReflectedType()->isRecordType(); } return SetAndSucceed(Result, makeBool(C, result)); } @@ -3810,6 +3885,8 @@ bool is_static_member(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, result)); + case ReflectionKind::EntityProxy: + llvm_unreachable("proxies should already have been unwrapped"); } llvm_unreachable("unknown reflection kind"); } @@ -3937,11 +4014,26 @@ bool is_alias(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::EntityProxy: return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("unknown reflection kind"); } +bool is_entity_proxy(APValue &Result, ASTContext &C, MetaActions &Meta, + EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, + QualType ResultTy, SourceRange Range, + ArrayRef Args, Decl *ContainingDecl) { + assert(Args[0]->getType()->isReflectionType()); + assert(ResultTy == C.BoolTy); + + APValue RV; + if (!Evaluator(RV, Args[0], true)) + return true; + + return SetAndSucceed(Result, makeBool(C, RV.isReflectedEntityProxy())); +} + bool is_complete_type(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, @@ -4001,6 +4093,8 @@ bool has_complete_definition(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: break; + case ReflectionKind::EntityProxy: + llvm_unreachable("proxies should already have been unwrapped"); } return SetAndSucceed(Result, makeBool(C, result)); @@ -4038,6 +4132,8 @@ bool is_enumerable_type(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: break; + case ReflectionKind::EntityProxy: + llvm_unreachable("proxies should already have been unwrapped"); } return SetAndSucceed(Result, makeBool(C, result)); @@ -4326,6 +4422,7 @@ bool has_template_arguments(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: @@ -4441,6 +4538,8 @@ bool is_constructor(APValue &Result, ASTContext &C, MetaActions &Meta, bool result = isa(RV.getReflectedDecl()); return SetAndSucceed(Result, makeBool(C, result)); } + case ReflectionKind::EntityProxy: + llvm_unreachable("proxies should already have been unwrapped"); } llvm_unreachable("invalid reflection type"); } @@ -4588,6 +4687,8 @@ bool is_destructor(APValue &Result, ASTContext &C, MetaActions &Meta, bool result = isa(RV.getReflectedDecl()); return SetAndSucceed(Result, makeBool(C, result)); } + case ReflectionKind::EntityProxy: + llvm_unreachable("proxies should already have been unwrapped"); } llvm_unreachable("invalid reflection type"); } @@ -4628,6 +4729,8 @@ bool is_special_member_function(APValue &Result, ASTContext &C, result = isSpecialMember(FTD->getTemplatedDecl()); return SetAndSucceed(Result, makeBool(C, result)); } + case ReflectionKind::EntityProxy: + llvm_unreachable("proxies should already have been unwrapped"); } llvm_unreachable("invalid reflection type"); } @@ -4934,6 +5037,7 @@ bool offset_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member", @@ -5005,6 +5109,7 @@ bool size_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) @@ -5030,6 +5135,7 @@ bool bit_offset_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member", @@ -5099,6 +5205,7 @@ bool bit_size_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) @@ -5163,6 +5270,7 @@ bool alignment_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) @@ -5221,6 +5329,7 @@ bool get_ith_parameter_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: @@ -5260,6 +5369,7 @@ bool has_consistent_identifier(APValue &Result, ASTContext &C, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::EntityProxy: return has_identifier(Result, C, Meta, Evaluator, Diagnoser, AllowInjection, ResultTy, Range, Args, ContainingDecl); } @@ -5284,6 +5394,7 @@ bool has_ellipsis_parameter(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: @@ -5333,6 +5444,7 @@ bool has_default_argument(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: @@ -5405,8 +5517,6 @@ bool return_type_of(APValue &Result, ASTContext &C, MetaActions &Meta, return Diagnoser(Range.getBegin(), diag::metafn_cannot_introspect_type) << 3 << 2 << Range; } - - case ReflectionKind::Declaration: if (auto *FD = dyn_cast(RV.getReflectedDecl()); FD && !isa(FD) && !isa(FD)) { @@ -5421,6 +5531,7 @@ bool return_type_of(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: @@ -5484,6 +5595,11 @@ bool get_ith_annotation_of(APValue &Result, ASTContext &C, MetaActions &Meta, return SetAndSucceed(Result, findAnnotation(D, idx, Sentinel)); } + case ReflectionKind::EntityProxy: { + Decl *D = RV.getReflectedEntityProxy()->getIntroducer(); + + return SetAndSucceed(Result, findAnnotation(D, idx, Sentinel)); + } // Disallow reflecting annotations of unspecialized templates, as they might // contain a dependent name. case ReflectionKind::Template: /*{ @@ -5569,6 +5685,7 @@ bool annotate(APValue &Result, ASTContext &C, MetaActions &Meta, case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: + case ReflectionKind::EntityProxy: return Diagnoser(Range.getBegin(), diag::metafn_cannot_annotate) << DescriptionOf(Appertainee) << Range; } @@ -5638,6 +5755,7 @@ bool is_accessible(APValue &Result, ASTContext &C, MetaActions &Meta, CXXRecordDecl *NamingCls = nullptr; if (!Evaluator(Scratch, Args[2], true) || !Scratch.isReflection()) return true; + Scratch = MaybeUnproxy(C, Scratch); assert(Scratch.isNullReflection() || Scratch.isReflectedType()); if (Scratch.isReflectedType()) { NamingCls = cast(findTypeDecl(Scratch.getReflectedType())); @@ -5700,6 +5818,17 @@ bool is_accessible(APValue &Result, ASTContext &C, MetaActions &Meta, Meta.IsAccessible(D, AccessDC, NamingCls); return SetAndSucceed(Result, makeBool(C, Accessible)); } + case ReflectionKind::EntityProxy: { + UsingShadowDecl *USD = RV.getReflectedEntityProxy(); + if (validate(USD, NamingCls)) + return true; + else if (!NamingCls) + return SetAndSucceed(Result, makeBool(C, true)); + + bool Accessible = UnconditionalAccess || + Meta.IsAccessible(USD, AccessDC, NamingCls); + return SetAndSucceed(Result, makeBool(C, Accessible)); + } case ReflectionKind::BaseSpecifier: { CXXBaseSpecifier *BaseSpec = RV.getReflectedBaseSpecifier(); @@ -5777,6 +5906,12 @@ bool is_access_specified(APValue &Result, ASTContext &C, MetaActions &Meta, bool IsSpecified = findAccessSpec(D) != AS_none; return SetAndSucceed(Result, makeBool(C, IsSpecified)); } + case ReflectionKind::EntityProxy: { + Decl *D = RV.getReflectedEntityProxy()->getIntroducer(); + + bool IsSpecified = findAccessSpec(D) != AS_none; + return SetAndSucceed(Result, makeBool(C, IsSpecified)); + } case ReflectionKind::BaseSpecifier: { CXXBaseSpecifier *Base = RV.getReflectedBaseSpecifier(); bool IsSpecified = (Base->getAccessSpecifierAsWritten() != AS_none); @@ -5886,6 +6021,7 @@ bool reflect_invoke(APValue &Result, ASTContext &C, MetaActions &Meta, if (!Evaluator(Scratch, Synthesized, true) || !Scratch.isReflection()) return false; + Scratch = MaybeUnproxy(C, Scratch); Out.push_back(Scratch); } @@ -5895,6 +6031,7 @@ bool reflect_invoke(APValue &Result, ASTContext &C, MetaActions &Meta, APValue FnRefl; if (!Evaluator(FnRefl, Args[0], true)) return true; + FnRefl = MaybeUnproxy(C, FnRefl); SmallVector ExplicitTArgs; { @@ -6023,6 +6160,8 @@ bool reflect_invoke(APValue &Result, ASTContext &C, MetaActions &Meta, VK_LValue, Spec, nullptr); break; } + case ReflectionKind::EntityProxy: + llvm_unreachable("proxies should already have been unwrapped"); } Expr* CallExpr; diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index d20fcaa98452..c693b24f4fcf 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4959,6 +4959,12 @@ void CXXNameMangler::mangleReflection(const APValue &R) { Out << '$'; break; } + case ReflectionKind::EntityProxy: { + Out << 'a'; + mangleNameWithAbiTags(R.getReflectedEntityProxy(), nullptr); + Out << '$'; + break; + } case ReflectionKind::BaseSpecifier: { Out << 'b'; Context.mangleCanonicalTypeName(R.getReflectedBaseSpecifier()->getType(), diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index db1a41757fb4..3f61ecd19418 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -2197,6 +2197,7 @@ void MicrosoftCXXNameMangler::mangleReflection(const APValue &R) { case ReflectionKind::Declaration: case ReflectionKind::Template: case ReflectionKind::Namespace: + case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 27fd23898cab..bd310195b748 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -5328,10 +5328,10 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { bool MemberPointerType::isSugared() const { CXXRecordDecl *D1 = getMostRecentCXXRecordDecl(), *D2 = getQualifier()->getAsRecordDecl(); - if (getQualifier()->getKind() == NestedNameSpecifier::Splice) + if (getQualifier()->getKind() == NestedNameSpecifier::Splice || + getQualifier()->getKind() == NestedNameSpecifier::SpliceWithTemplate) return true; - assert(!D1 == !D2); return D1 != D2 && D1->getCanonicalDecl() != D2->getCanonicalDecl(); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 1704aad27ae4..b836a58d9aae 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7182,8 +7182,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-freflection"); CmdArgs.push_back("-fparameter-reflection"); CmdArgs.push_back("-fannotation-attributes"); - if (!Args.hasArg(options::OPT_fno_access_contexts)) - CmdArgs.push_back("-faccess-contexts"); + CmdArgs.push_back("-fentity-proxy-reflection"); CmdArgs.push_back("-fexpansion-statements"); } @@ -7524,9 +7523,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fannotation-attributes is likewise off by default. Args.addOptInFlag(CmdArgs, options::OPT_fannotation_attributes, options::OPT_fno_annotation_attributes); - // -faccess-contexts is likewise off by default. - Args.addOptInFlag(CmdArgs, options::OPT_faccess_contexts, - options::OPT_fno_access_contexts); + Args.addOptInFlag(CmdArgs, options::OPT_fentity_proxy_reflection, + options::OPT_fno_entity_proxy_reflection); // -freflection-latest is likewise off by default. Args.addOptInFlag(CmdArgs, options::OPT_freflection_latest, options::OPT_fno_reflection_latest); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index f1a1e6e346f5..da4a46047633 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -638,8 +638,8 @@ static bool FixupInvocation(CompilerInvocation &Invocation, if (!LangOpts.Reflection) { if (LangOpts.ParameterReflection) { Diags.Report(diag::err_fe_parameter_reflection_without_reflection); - } else if (LangOpts.AccessContexts) { - Diags.Report(diag::err_fe_access_contexts_without_reflection); + } else if (LangOpts.EntityProxyReflection) { + Diags.Report(diag::err_fe_entity_proxy_reflection_without_reflection); } } diff --git a/clang/lib/Sema/SemaReflect.cpp b/clang/lib/Sema/SemaReflect.cpp index d0b284fc8f97..da393af3766a 100644 --- a/clang/lib/Sema/SemaReflect.cpp +++ b/clang/lib/Sema/SemaReflect.cpp @@ -155,6 +155,26 @@ bool CheckSpliceVar(Sema &S, VarDecl *VD, SourceRange Range) { return false; } +APValue MaybeUnproxy(ASTContext &C, APValue RV) { + assert(RV.isReflection()); + + if (!RV.isReflectedEntityProxy()) + return RV; + + NamedDecl *ND = RV.getReflectedEntityProxy()->getTargetDecl(); + if (auto *T = dyn_cast(ND)) { + QualType QT = T->getUnderlyingType(); + return APValue(ReflectionKind::Type, QT.getAsOpaquePtr()); + } else if (auto *T = dyn_cast(ND)) { + QualType QT = C.getTypeDeclType(T); + return APValue(ReflectionKind::Type, QT.getAsOpaquePtr()); + } else if (auto *T = dyn_cast(ND)) { + return APValue(ReflectionKind::Template, T); + } + + return APValue(ReflectionKind::Declaration, ND); +} + class MetaActionsImpl : public MetaActions { Sema &S; @@ -881,10 +901,15 @@ ExprResult Sema::ActOnCXXReflectExpr(SourceLocation OpLoc, return ExprError(); } - // Unwrap any 'UsingShadowDecl'-nodes. NamedDecl *ND = Found.getRepresentativeDecl(); - while (auto *USD = dyn_cast(ND)) - ND = USD->getTargetDecl(); + + if (auto *USD = dyn_cast(ND)) { + if (getLangOpts().EntityProxyReflection) + return BuildCXXReflectExpr(OpLoc, NameInfo.getBeginLoc(), USD); + else do + ND = cast(ND)->getTargetDecl(); + while (isa(ND)); + } if (auto *TD = dyn_cast(ND)) { QualType QT = Context.getTypeDeclType(TD); @@ -910,6 +935,8 @@ ExprResult Sema::ActOnCXXReflectExpr(SourceLocation OpLoc, VD && CheckReflectVar(*this, VD, Id.getSourceRange())) return ExprError(); + // TODO(P2996): Try addressing this. + // // Why do we have to build an expression here? Just stash in an APValue? if (isa(ND)) { @@ -1122,36 +1149,37 @@ Sema::ActOnSpliceTemplateArgument(SpliceSpecifier *Splice) { } assert(ER.Val.getKind() == APValue::Reflection); - switch (ER.Val.getReflectionKind()) { + APValue Refl = MaybeUnproxy(Context, ER.Val); + switch (Refl.getReflectionKind()) { case ReflectionKind::Type: return ParsedTemplateArgument(ParsedTemplateArgument::Type, const_cast( - ER.Val.getOpaqueReflectionData()), + Refl.getOpaqueReflectionData()), Splice->getBeginLoc()); case ReflectionKind::Object: { - QualType ResultTy = ER.Val.getTypeOfReflectedResult(Context); + QualType ResultTy = Refl.getTypeOfReflectedResult(Context); Expr *OVE = new (Context) OpaqueValueExpr(Splice->getBeginLoc(), ResultTy, VK_LValue); - Expr *CE = ConstantExpr::Create(Context, OVE, ER.Val.getReflectedObject()); + Expr *CE = ConstantExpr::Create(Context, OVE, Refl.getReflectedObject()); return ParsedTemplateArgument(ParsedTemplateArgument::NonType, CE, Splice->getBeginLoc()); } case ReflectionKind::Value: { - QualType ResultTy = ER.Val.getTypeOfReflectedResult(Context); + QualType ResultTy = Refl.getTypeOfReflectedResult(Context); Expr *OVE = new (Context) OpaqueValueExpr(Splice->getBeginLoc(), ResultTy, VK_PRValue); - Expr *CE = ConstantExpr::Create(Context, OVE, ER.Val.getReflectedValue()); + Expr *CE = ConstantExpr::Create(Context, OVE, Refl.getReflectedValue()); return ParsedTemplateArgument(ParsedTemplateArgument::NonType, CE, Splice->getBeginLoc()); } case ReflectionKind::Template: { - TemplateName TName = ER.Val.getReflectedTemplate(); + TemplateName TName = Refl.getReflectedTemplate(); return ParsedTemplateArgument(ParsedTemplateArgument::Template, TName.getAsTemplateDecl(), Splice->getBeginLoc()); } case ReflectionKind::Declaration: { - Expr *E = CreateRefToDecl(*this, cast(ER.Val.getReflectedDecl()), + Expr *E = CreateRefToDecl(*this, cast(Refl.getReflectedDecl()), Splice->getBeginLoc()); return ParsedTemplateArgument(ParsedTemplateArgument::NonType, E, E->getBeginLoc()); @@ -1209,11 +1237,13 @@ ExprResult Sema::BuildCXXReflectExpr(SourceLocation OperatorLoc, SourceLocation OperandLoc, Decl *D) { D = D->getCanonicalDecl(); - bool IsNamespace = isa(D); + ReflectionKind RK = ReflectionKind::Declaration; + if (isa(D)) + RK = ReflectionKind::Namespace; + else if (isa(D)) + RK = ReflectionKind::EntityProxy; - APValue RV(IsNamespace ? ReflectionKind::Namespace : - ReflectionKind::Declaration, D); + APValue RV(RK, D); return CXXReflectExpr::Create(Context, OperatorLoc, SourceRange(OperandLoc, OperandLoc), RV); } @@ -1479,16 +1509,17 @@ QualType Sema::BuildReflectionSpliceType(SourceLocation TypenameKWLoc, Diag(Splice->getBeginLoc(), diag::err_splice_operand_not_reflection); return QualType(); } + APValue Refl = MaybeUnproxy(Context, ER.Val); QualType ReflectedTy; - if (ER.Val.isReflectedTemplate() && - !isa(ER.Val.getReflectedTemplate().getAsTemplateDecl())) { + if (Refl.isReflectedTemplate() && + !isa(Refl.getReflectedTemplate().getAsTemplateDecl())) { if (Splice->isSpecialization()) { TemplateArgumentListInfo TAListInfo; for (const auto &TArg : Splice->getTemplateArgs()->arguments()) TAListInfo.addArgument(TArg); ReflectedTy = - CheckTemplateIdType(ER.Val.getReflectedTemplate(), + CheckTemplateIdType(Refl.getReflectedTemplate(), Splice->getBeginLoc(), TAListInfo); if (ReflectedTy.isNull()) { return QualType(); @@ -1496,15 +1527,15 @@ QualType Sema::BuildReflectionSpliceType(SourceLocation TypenameKWLoc, } else { ReflectedTy = Context.getDeducedTemplateSpecializationType( - ER.Val.getReflectedTemplate(), QualType(), false); + Refl.getReflectedTemplate(), QualType(), false); } - } else if (!ER.Val.isReflectedType()) { + } else if (!Refl.isReflectedType()) { if (Complain) Diag(Splice->getBeginLoc(), diag::err_unexpected_reflection_kind_in_splice) << 0; return QualType(); } else { - ReflectedTy = ER.Val.getReflectedType(); + ReflectedTy = Refl.getReflectedType(); } // Check if the type refers to a substituted but uninstantiated template. @@ -1574,18 +1605,20 @@ ExprResult Sema::BuildReflectionSpliceExpr(SourceLocation TemplateKWLoc, Diag(Splice->getBeginLoc(), diag::err_splice_operand_not_reflection); return ExprError(); } + APValue Refl = MaybeUnproxy(Context, ER.Val); + bool RequireTemplate = TemplateKWLoc.isValid() || Splice->isSpecialization(); - if (RequireTemplate && !ER.Val.isReflectedTemplate()) { + if (RequireTemplate && !Refl.isReflectedTemplate()) { Diag(Splice->getBeginLoc(), diag::err_unexpected_reflection_kind_in_splice) << 3; return ExprError(); } Expr *Result = nullptr; - switch (ER.Val.getReflectionKind()) { + switch (Refl.getReflectionKind()) { case ReflectionKind::Declaration: { - Decl *TheDecl = ER.Val.getReflectedDecl(); + Decl *TheDecl = Refl.getReflectedDecl(); // Class members may not be implicitly referenced through a splice. if (!AllowMemberReference && @@ -1623,22 +1656,21 @@ ExprResult Sema::BuildReflectionSpliceExpr(SourceLocation TemplateKWLoc, break; } case ReflectionKind::Object: { - QualType QT = ER.Val.getTypeOfReflectedResult(Context); + QualType QT = Refl.getTypeOfReflectedResult(Context); Expr *OVE = new (Context) OpaqueValueExpr(Splice->getBeginLoc(), QT, VK_LValue); Expr *CE = ConstantExpr::Create(Context, OVE, - ER.Val.getReflectedObject()); + Refl.getReflectedObject()); Result = CXXSpliceExpr::Create(Context, VK_LValue, TemplateKWLoc, Splice, CE, AllowMemberReference); break; } case ReflectionKind::Value: { - QualType QT = ER.Val.getTypeOfReflectedResult(Context); + QualType QT = Refl.getTypeOfReflectedResult(Context); Expr *OVE = new (Context) OpaqueValueExpr(Splice->getBeginLoc(), QT, VK_PRValue); - Expr *CE = ConstantExpr::Create(Context, OVE, - ER.Val.getReflectedValue()); + Expr *CE = ConstantExpr::Create(Context, OVE, Refl.getReflectedValue()); Result = CXXSpliceExpr::Create(Context, VK_PRValue, TemplateKWLoc, Splice, CE, AllowMemberReference); @@ -1652,7 +1684,7 @@ ExprResult Sema::BuildReflectionSpliceExpr(SourceLocation TemplateKWLoc, return ExprError(); } - TemplateName TName = ER.Val.getReflectedTemplate(); + TemplateName TName = Refl.getReflectedTemplate(); assert(!TName.isDependent()); TemplateDecl *TDecl = TName.getAsTemplateDecl(); @@ -1843,10 +1875,11 @@ DeclContext *Sema::TryFindDeclContextOf(SpliceSpecifier *Splice) { Diag(PD.first, PD.second); return nullptr; } + APValue Refl = MaybeUnproxy(Context, ER.Val); - switch (ER.Val.getReflectionKind()) { + switch (Refl.getReflectionKind()) { case ReflectionKind::Type: { - QualType QT = ER.Val.getReflectedType(); + QualType QT = Refl.getReflectedType(); if (auto *RD = QT->getAsTagDecl()) return RD; @@ -1861,7 +1894,7 @@ DeclContext *Sema::TryFindDeclContextOf(SpliceSpecifier *Splice) { return nullptr; } - Decl *NS = ER.Val.getReflectedNamespace(); + Decl *NS = Refl.getReflectedNamespace(); if (auto *A = dyn_cast(NS)) NS = A->getNamespace(); return cast(NS); @@ -1877,7 +1910,7 @@ DeclContext *Sema::TryFindDeclContextOf(SpliceSpecifier *Splice) { TemplateArgumentListInfo TAListInfo; for (const auto &TArg : Splice->getTemplateArgs()->arguments()) TAListInfo.addArgument(TArg); - QualType QT = CheckTemplateIdType(ER.Val.getReflectedTemplate(), + QualType QT = CheckTemplateIdType(Refl.getReflectedTemplate(), SourceLocation(), TAListInfo); if (QT.isNull()) return nullptr; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 7a41280eaaa6..3dc1b37f1a54 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -9123,6 +9123,15 @@ TreeTransform::TransformCXXReflectExpr(CXXReflectExpr *E) { E->getOperandRange().getBegin(), Template)); } + case ReflectionKind::EntityProxy: { + Decl *Transformed = + getDerived().TransformDecl(E->getExprLoc(), + RV.getReflectedEntityProxy()); + return RecordConstevalOnly.RecordAndReturn( + getSema().BuildCXXReflectExpr(E->getOperatorLoc(), + E->getOperandRange().getBegin(), + cast(Transformed))); + } case ReflectionKind::Namespace: { Decl *Transformed = getDerived().TransformDecl(E->getExprLoc(), diff --git a/clang/test/Reflection/splice-exprs.cpp b/clang/test/Reflection/splice-exprs.cpp index 8c4fb095721b..3ff04d109563 100644 --- a/clang/test/Reflection/splice-exprs.cpp +++ b/clang/test/Reflection/splice-exprs.cpp @@ -8,7 +8,7 @@ // //===----------------------------------------------------------------------===// // -// RUN: %clang_cc1 %s -std=c++23 -freflection +// RUN: %clang_cc1 %s -std=c++26 -freflection -fentity-proxy-reflection using info = decltype(^^int); @@ -180,6 +180,33 @@ int dK = d.[:^^S::k:]; } // namespace with_member_access + // =================== + // with_entity_proxies + // =================== + +namespace with_entity_proxies { +namespace NS { +namespace Inner { +consteval int fn() { return 42; } +template consteval int tfn() { return V; } +} // namespace Inner + +using Inner::fn; +using Inner::tfn; +} // namespace NS + +// splice-expressions +static_assert([:^^NS::fn:]() == 42); +static_assert(template [:^^NS::tfn:]<4>() == 4); + +// nested proxies +struct A { int m; }; +struct B : A { using A::m; }; +struct C : B { using B::m; }; + +static_assert(&[:^^C::m:] == &A::m); +} // namespace with_entity_proxies + // =========================== // with_implicit_member_access // =========================== diff --git a/clang/test/Reflection/splice-types.cpp b/clang/test/Reflection/splice-types.cpp index e40670531863..b4c8c956d4e6 100644 --- a/clang/test/Reflection/splice-types.cpp +++ b/clang/test/Reflection/splice-types.cpp @@ -197,6 +197,30 @@ static_assert(int(B) == 1); } // namespace } // namespace with_enum_types + // =================== + // with_entity_proxies + // =================== + +namespace with_entity_proxies { +namespace NS { +namespace Inner { +struct S { int a = 11; }; +template struct TCls { T t; void fn(); }; +} // namespace Inner + +using Inner::S; +using Inner::TCls; +} // namespace NS + +// splice-type-specifiers +static_assert(typename [:^^NS::S:]{}.a == 11); +static_assert(typename [:^^NS::TCls:]{4}.t == 4); + +// splice-scope-specifiers +static_assert(&[:^^NS::S:]::a == &NS::Inner::S::a); +static_assert(&template [:^^NS::TCls:]::fn == &NS::Inner::TCls::fn); +} // namespace with_entity_proxies + // =================== // friend_declarations // =================== diff --git a/libcxx/include/experimental/meta b/libcxx/include/experimental/meta index 1374a9417bb3..ae9267067893 100644 --- a/libcxx/include/experimental/meta +++ b/libcxx/include/experimental/meta @@ -59,19 +59,14 @@ consteval auto template_of(info r) -> info; consteval auto template_arguments_of(info r) -> vector; // member queries -consteval auto members_of(info class_type) -> vector; -consteval auto bases_of(info class_type) -> vector; -consteval auto static_data_members_of(info class_type) -> vector; -consteval auto nonstatic_data_members_of(info class_type) -> vector; -consteval auto subobjects_of(info class_type) -> vector; +consteval auto members_of(info class_type, access_context ctx) -> vector; +consteval auto bases_of(info class_type, access_context ctx) -> vector; +consteval auto static_data_members_of(info class_type, + access_context ctx) -> vector; +consteval auto nonstatic_data_members_of(info class_type, + access_context ctx) -> vector; consteval auto enumerators_of(info enum_type) -> vector; -// public member queries (removal proposed by P3547) -consteval auto get_public_members(info) -> vector; -consteval auto get_public_bases(info) -> vector; -consteval auto get_static_data_members(info) -> vector; -consteval auto get_nonstatic_data_members(info) -> vector; - // substitute template > consteval auto can_substitute(info templ, R &&args) -> bool; @@ -340,6 +335,9 @@ consteval auto tuple_element(size_t, info) -> info; consteval auto variant_size(info) -> size_t; consteval auto variant_alternative(size_t, info) -> info; +// entity proxies (PXYZ) +consteval auto is_entity_proxy(info) -> bool; + // function parameters (P3096) consteval auto parameters_of(info) -> vector; consteval auto has_consistent_identifier(info) -> bool; @@ -486,6 +484,7 @@ enum : unsigned { __metafn_is_variable, __metafn_is_type, __metafn_is_alias, + __metafn_is_entity_proxy, __metafn_is_complete_type, __metafn_has_complete_definition, __metafn_is_enumerable_type, @@ -948,7 +947,10 @@ consteval auto is_complete_type(info r) -> bool { return __metafunction(detail::__metafn_is_complete_type, r); } -#if __has_feature(access_contexts) +// Returns whether the reflected class data member is an enumerator. +consteval auto is_enumerator(info r) -> bool { + return __metafunction(detail::__metafn_is_enumerator, r); +} class access_context { consteval access_context(info scope, info naming_class) noexcept @@ -988,20 +990,16 @@ public: }; consteval auto is_accessible(info r, access_context ctx) -> bool { - if (!is_class_member(r) && !is_base(r)) + // Note: The accessibility of an enumerator may be looked up in a class + // for which it's not a member, since that enumerator could be + if (!is_class_member(r) && !is_base(r) && !is_enumerator(r)) return true; return __metafunction(detail::__metafn_is_accessible, r, ctx.scope(), ctx.naming_class()); } -#endif // __has_feature(access_contexts) - -#if __has_feature(access_contexts) consteval auto members_of(info r, access_context ctx) -> vector { -#else -consteval auto members_of(info r) -> vector { -#endif // __has_feature(access_contexts) using iterator = __range_of_infos::iterator<__range_of_infos::front_member_of_fn, __range_of_infos::next_member_of_fn, @@ -1010,14 +1008,10 @@ consteval auto members_of(info r) -> vector { auto rng = range{r}; vector v {rng.begin(), rng.end()}; -#if __has_feature(access_contexts) return vector{ from_range, v | views::filter([=](info r) { return is_accessible(r, ctx); }) }; -#else - return v; -#endif // __has_feature(access_contexts) } // Returns whether the reflected entity is a namespace. @@ -1025,11 +1019,7 @@ consteval auto is_namespace(info r) -> bool { return __metafunction(detail::__metafn_is_namespace, r); } -#if __has_feature(access_contexts) consteval auto bases_of(info r, access_context ctx) -> vector { -#else -consteval auto bases_of(info r) -> vector { -#endif // __has_feature(access_contexts) if (is_namespace(r)) throw "Namespaces cannot have base classes"; @@ -1041,14 +1031,10 @@ consteval auto bases_of(info r) -> vector { auto rng = range{r}; vector v {rng.begin(), rng.end()}; -#if __has_feature(access_contexts) return vector{ from_range, v | views::filter([=](info r) { return is_accessible(r, ctx); }) }; -#else - return v; -#endif // __has_feature(access_contexts) } // Returns whether the reflected entity is a variable. @@ -1056,38 +1042,22 @@ consteval auto is_variable(info r) -> bool { return __metafunction(detail::__metafn_is_variable, r); } -#if __has_feature(access_contexts) consteval auto static_data_members_of(info r, access_context ctx) -> vector { -#else -consteval auto static_data_members_of(info r) -> vector { -#endif // has_feature(access_contexts if (is_namespace(r)) throw "Namespaces cannot have static data members"; -#if __has_feature(access_contexts) return members_of(r, ctx) | -#else - return members_of(r) | -#endif // __has_feature(access_contexts) views::filter(is_variable) | ranges::to(); } -#if __has_feature(access_contexts) consteval auto nonstatic_data_members_of(info r, access_context ctx) -> vector { -#else -consteval auto nonstatic_data_members_of(info r) -> vector { -#endif // __has_feature(access_contexts) if (is_namespace(r)) throw "Namespaces cannot have non-static data members"; -#if __has_feature(access_contexts) return members_of(r, ctx) | -#else - return members_of(r) | -#endif // __has_feature(access_contexts) views::filter(is_nonstatic_data_member) | ranges::to(); } @@ -1115,26 +1085,6 @@ consteval auto is_public(info r) -> bool { return __metafunction(detail::__metafn_is_public, r); } -#if !__has_feature(access_contexts) -consteval auto get_public_members(info r) -> vector { - return members_of(r) | views::filter(is_public) | ranges::to(); -} - -consteval auto get_public_bases(info r) -> vector { - return bases_of(r) | views::filter(is_public) | ranges::to(); -} - -consteval auto get_public_static_data_members(info r) -> vector { - return static_data_members_of(r) | views::filter(is_public) | - ranges::to(); -} - -consteval auto get_public_nonstatic_data_members(info r) -> vector { - return nonstatic_data_members_of(r) | views::filter(is_public) | - ranges::to(); -} -#endif // !__has_feature(access_contexts) - // Returns whether the reflected entity is a protected class member. consteval auto is_protected(info r) -> bool { return __metafunction(detail::__metafn_is_protected, r); @@ -1188,11 +1138,6 @@ consteval auto is_bit_field(info r) -> bool { return __metafunction(detail::__metafn_is_bit_field, r); } -// Returns whether the reflected class data member is an enumerator. -consteval auto is_enumerator(info r) -> bool { - return __metafunction(detail::__metafn_is_enumerator, r); -} - // Returns whether the reflected type is const-qualified, or if the reflected // entity is of such a type. consteval auto is_const(info r) -> bool { @@ -1275,16 +1220,23 @@ consteval auto is_type(info r) -> bool { return __metafunction(detail::__metafn_is_type, r); } -// Returns true if the reflected entity is an alias. +// Returns true if the reflected entity is a type alias. consteval auto is_type_alias(info r) -> bool { return is_type(r) && __metafunction(detail::__metafn_is_alias, r); } -// Returns true if the reflected entity is an alias. +// Returns true if the reflected entity is a namespace alias. consteval auto is_namespace_alias(info r) -> bool { return is_namespace(r) && __metafunction(detail::__metafn_is_alias, r); } +#if __has_feature(entity_proxy_reflection) +// Returns true if the reflected entity is an entity proxy. +consteval auto is_entity_proxy(info r) -> bool { + return __metafunction(detail::__metafn_is_entity_proxy, r); +} +#endif + // Returns true if the reflected entity is a template. consteval auto is_template(info r) -> bool { return __metafunction(detail::__metafn_is_template, r); @@ -2089,11 +2041,7 @@ namespace detail { template struct __wrap_workaround { using type = T; }; consteval auto __workaround_expand_compiler_builtins(info type) -> info { auto r = substitute(^^__wrap_workaround, {type}); -#if __has_feature(access_contexts) return dealias(members_of(r, access_context::unchecked())[0]); -#else - return dealias(members_of(r)[0]); -#endif } } // namespace detail @@ -2193,8 +2141,6 @@ consteval auto annotate(info entity, info val) -> info { #endif // __has_feature(annotation_attributes) -#if __has_feature(access_contexts) - consteval auto has_inaccessible_nonstatic_data_members( info r, access_context ctx) -> bool { @@ -2208,8 +2154,6 @@ consteval auto has_inaccessible_bases(info r, access_context ctx) -> bool { [=](info b) { return is_accessible(b, ctx); }); } -#endif // __has_feature(access_contexts) - // =================================================== // Other bespoke functions (not proposed at this time) // =================================================== @@ -2310,7 +2254,6 @@ consteval auto define_class(info class_type, R &&members) -> info { return define_aggregate(class_type, members); } -#if __has_feature(access_contexts) [[deprecated("P3547 requires an 'access_context' argument " "(compile with '-fno-access-contexts' to disable this warning)")]] consteval auto members_of(info r) -> vector { @@ -2340,8 +2283,6 @@ consteval auto has_complete_definition(info r) -> bool { return __metafunction(detail::__metafn_has_complete_definition, r); } -#endif // __has_feature(access_contexts) - _LIBCPP_END_NAMESPACE_REFLECTION_V2 _LIBCPP_BEGIN_NAMESPACE_STD @@ -2692,12 +2633,8 @@ consteval auto pretty_printer::tprint_impl::render() -> string_t { string_t result = render() + string_constant("{"); size_t Idx = 0; -#if __has_feature(access_contexts) [:expand(nonstatic_data_members_of(type_of(R), access_context::unchecked())):] >> -#else - [:expand(nonstatic_data_members_of(type_of(R))):] >> -#endif [&] { if (Idx++ > 0) result += string_constant(", "); result += tprint_impl::render(); diff --git a/libcxx/test/std/experimental/reflection/define-aggregate.pass.cpp b/libcxx/test/std/experimental/reflection/define-aggregate.pass.cpp index 5e2410878ddd..b9ae227b9d98 100644 --- a/libcxx/test/std/experimental/reflection/define-aggregate.pass.cpp +++ b/libcxx/test/std/experimental/reflection/define-aggregate.pass.cpp @@ -23,6 +23,7 @@ #include +constexpr auto ctx = std::meta::access_context::unchecked(); // ========================= // completion_with_no_fields @@ -43,9 +44,9 @@ consteval { static_assert(is_complete_type(^^S)); static_assert(is_complete_type(^^C)); static_assert(is_complete_type(^^U)); -static_assert(nonstatic_data_members_of(^^S).size() == 0); -static_assert(nonstatic_data_members_of(^^C).size() == 0); -static_assert(nonstatic_data_members_of(^^U).size() == 0); +static_assert(nonstatic_data_members_of(^^S, ctx).size() == 0); +static_assert(nonstatic_data_members_of(^^C, ctx).size() == 0); +static_assert(nonstatic_data_members_of(^^U, ctx).size() == 0); S s; C c; @@ -69,17 +70,18 @@ consteval { } static_assert(is_complete_type(^^S)); // unnamed bitfields are not nonstatic data members. -static_assert(nonstatic_data_members_of(^^S).size() == 3); +static_assert(nonstatic_data_members_of(^^S, ctx).size() == 3); static_assert(alignment_of(^^S::count) == 16); -static_assert(bit_size_of(nonstatic_data_members_of(^^S)[2]) == 5); -static_assert((members_of(^^S) | std::views::filter(std::meta::is_bit_field) | +static_assert(bit_size_of(nonstatic_data_members_of(^^S, ctx)[2]) == 5); +static_assert((members_of(^^S, ctx) | + std::views::filter(std::meta::is_bit_field) | std::views::transform(std::meta::bit_size_of) | std::ranges::to()) == std::vector {0, 5}); constexpr S s = {14, true, 11}; static_assert(s.count == 14); static_assert(s.flag); -static_assert(s.[:nonstatic_data_members_of(^^S)[2]:] == 11); +static_assert(s.[:nonstatic_data_members_of(^^S, ctx)[2]:] == 11); struct Empty {}; struct WithEmpty; @@ -105,9 +107,9 @@ consteval { }); } static_assert(is_complete_type(^^C)); -static_assert(nonstatic_data_members_of(^^C).size() == 2); +static_assert(nonstatic_data_members_of(^^C, ctx).size() == 2); static_assert( - (members_of(^^C) | + (members_of(^^C, ctx) | std::views::filter(std::meta::is_nonstatic_data_member) | std::views::filter(std::meta::is_public) | std::ranges::to()).size() == 2); @@ -130,9 +132,9 @@ consteval { } static_assert(is_complete_type(^^U)); static_assert(size_of(^^U) == size_of(^^U::count)); -static_assert(nonstatic_data_members_of(^^U).size() == 2); +static_assert(nonstatic_data_members_of(^^U, ctx).size() == 2); static_assert( - (members_of(^^U) | + (members_of(^^U, ctx) | std::views::filter(std::meta::is_nonstatic_data_member) | std::ranges::to()).size() == 2); @@ -164,11 +166,11 @@ consteval { }); } -static_assert(nonstatic_data_members_of(^^S<0>).size() == 0); -static_assert(nonstatic_data_members_of(^^S<1>).size() == 1); +static_assert(nonstatic_data_members_of(^^S<0>, ctx).size() == 0); +static_assert(nonstatic_data_members_of(^^S<1>, ctx).size() == 1); static_assert(type_of(^^S<1>::mem) == ^^int); -static_assert(nonstatic_data_members_of(^^S<2>).size() == 0); -static_assert(nonstatic_data_members_of(^^S<3>).size() == 1); +static_assert(nonstatic_data_members_of(^^S<2>, ctx).size() == 0); +static_assert(nonstatic_data_members_of(^^S<3>, ctx).size() == 1); static_assert(type_of(^^S<3>::mem) == ^^bool); static_assert(!is_complete_type(^^S<4>)); } // namespace template_specialization_completion @@ -190,7 +192,7 @@ consteval { data_member_spec(^^int, {.name="count"})>(); } static_assert(is_complete_type(^^S)); -static_assert(nonstatic_data_members_of(^^S).size() == 2); +static_assert(nonstatic_data_members_of(^^S, ctx).size() == 2); S s; } // namespace completion_of_dependent_type @@ -261,7 +263,7 @@ consteval { static_assert(type_of(^^foo::i) == ^^int); static_assert(type_of(^^foo::b) == ^^bool); -static_assert(nonstatic_data_members_of(^^foo).size() == 2); +static_assert(nonstatic_data_members_of(^^foo, ctx).size() == 2); } // namespace with_non_contiguous_range // ============================= @@ -277,9 +279,10 @@ consteval { data_member_spec(^^int, {.name=u8identifier_of(^^Kühl)}) }); } -static_assert(u8identifier_of(nonstatic_data_members_of(^^Cls1)[0]) == +static_assert(u8identifier_of(nonstatic_data_members_of(^^Cls1, ctx)[0]) == u8"Kühl"); -static_assert(identifier_of(nonstatic_data_members_of(^^Cls1)[0]) == "Kühl"); +static_assert(identifier_of(nonstatic_data_members_of(^^Cls1, ctx)[0]) == + "Kühl"); } // namespace utf8_identifier_of_roundtrip // =========================== diff --git a/libcxx/test/std/experimental/reflection/define-aggregate.verify.cpp b/libcxx/test/std/experimental/reflection/define-aggregate.verify.cpp index 97545c4556f6..f0e0a99accc6 100644 --- a/libcxx/test/std/experimental/reflection/define-aggregate.verify.cpp +++ b/libcxx/test/std/experimental/reflection/define-aggregate.verify.cpp @@ -21,6 +21,9 @@ #include + +constexpr auto ctx = std::meta::access_context::unchecked(); + // =========== // well_formed // =========== @@ -185,7 +188,8 @@ struct S1 { namespace speculative_and_trial_evaluations { struct S1; consteval auto fn() { - return members_of(define_aggregate(^^S1, {})).empty() ? new int : nullptr; + return members_of(define_aggregate(^^S1, {}), ctx).empty() ? new int : + nullptr; }; consteval void fn2() { diff --git a/libcxx/test/std/experimental/reflection/entity-classification.pass.cpp b/libcxx/test/std/experimental/reflection/entity-classification.pass.cpp index eb20ea17eff6..a01cf170322d 100644 --- a/libcxx/test/std/experimental/reflection/entity-classification.pass.cpp +++ b/libcxx/test/std/experimental/reflection/entity-classification.pass.cpp @@ -18,6 +18,9 @@ #include #include + +constexpr auto ctx = std::meta::access_context::current(); + struct type {}; using alias = type; @@ -558,8 +561,8 @@ static_assert(is_complete_type(^^IncompleteTClsAlias)); struct Base {}; struct Derived : Base {}; static_assert(!is_base(^^Base)); -static_assert(!is_type(bases_of(^^Derived)[0])); -static_assert(is_base(bases_of(^^Derived)[0])); +static_assert(!is_type(bases_of(^^Derived, ctx)[0])); +static_assert(is_base(bases_of(^^Derived, ctx)[0])); // ================================================= // test_is_structured_binding_and_related_edge_cases @@ -630,29 +633,29 @@ struct S3 { S3(); }; S3::S3() {} static_assert( - (members_of(^^S1) | std::views::filter(std::meta::is_constructor) | - std::views::filter(std::meta::is_user_provided) | - std::ranges::to()).size() == 0); + (members_of(^^S1, ctx) | std::views::filter(std::meta::is_constructor) | + std::views::filter(std::meta::is_user_provided) | + std::ranges::to()).size() == 0); static_assert( - (members_of(^^S1) | std::views::filter(std::meta::is_constructor) | - std::views::filter(std::meta::is_user_declared) | - std::ranges::to()).size() == 0); + (members_of(^^S1, ctx) | std::views::filter(std::meta::is_constructor) | + std::views::filter(std::meta::is_user_declared) | + std::ranges::to()).size() == 0); static_assert( - (members_of(^^S2) | std::views::filter(std::meta::is_constructor) | - std::views::filter(std::meta::is_user_provided) | - std::ranges::to()).size() == 0); + (members_of(^^S2, ctx) | std::views::filter(std::meta::is_constructor) | + std::views::filter(std::meta::is_user_provided) | + std::ranges::to()).size() == 0); static_assert( - (members_of(^^S2) | std::views::filter(std::meta::is_constructor) | - std::views::filter(std::meta::is_user_declared) | - std::ranges::to()).size() == 2); + (members_of(^^S2, ctx) | std::views::filter(std::meta::is_constructor) | + std::views::filter(std::meta::is_user_declared) | + std::ranges::to()).size() == 2); static_assert( - (members_of(^^S3) | std::views::filter(std::meta::is_constructor) | - std::views::filter(std::meta::is_user_provided) | - std::ranges::to()).size() == 1); + (members_of(^^S3, ctx) | std::views::filter(std::meta::is_constructor) | + std::views::filter(std::meta::is_user_provided) | + std::ranges::to()).size() == 1); static_assert( - (members_of(^^S3) | std::views::filter(std::meta::is_constructor) | - std::views::filter(std::meta::is_user_declared) | - std::ranges::to()).size() == 1); + (members_of(^^S3, ctx) | std::views::filter(std::meta::is_constructor) | + std::views::filter(std::meta::is_user_declared) | + std::ranges::to()).size() == 1); } // namespace test_is_user_provided_and_declared diff --git a/libcxx/test/std/experimental/reflection/entity-proxies.pass.cpp b/libcxx/test/std/experimental/reflection/entity-proxies.pass.cpp new file mode 100644 index 000000000000..71f6e4689026 --- /dev/null +++ b/libcxx/test/std/experimental/reflection/entity-proxies.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Copyright 2024 Bloomberg Finance L.P. +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20 +// ADDITIONAL_COMPILE_FLAGS: -freflection +// ADDITIONAL_COMPILE_FLAGS: -fentity-proxy-reflection +// ADDITIONAL_COMPILE_FLAGS: -fannotation-attributes + +// +// +// [reflection] + +#include + + +constexpr auto ctx = std::meta::access_context::current(); +constexpr auto unchecked = std::meta::access_context::unchecked(); + +struct Base {}; +enum Enum { Red }; + +struct A { + int m; + struct Inner : Base { int m; }; + using Alias = std::vector; +}; +struct B : private A { using A::m; using A::Inner; using A::Alias; }; + +struct C { template struct TCls {}; struct Inner {}; int m; }; +struct D : C { using C::TCls; using C::Inner; private: using C::m; }; + +struct E { using Enum::Red; }; +namespace InnerNS { using Enum::Red; } + +struct F { int m; int n; }; +struct G : F { [[=32]] using F::m; public: using F::n; }; +struct H : G { using G::n; }; + +static_assert(is_accessible(^^A::Inner, ctx)); +static_assert(!is_accessible(^^A::Inner, ctx.via(^^B))); +static_assert(is_accessible(^^B::Inner, ctx)); + +static_assert(is_entity_proxy(^^B::Inner)); +static_assert(!is_entity_proxy(^^A::Inner)); + +static_assert(nonstatic_data_members_of(dealias(^^B::Inner), ctx).size() == 1); +static_assert(bases_of(dealias(^^B::Inner), ctx).size() == 1); + +static_assert(template_arguments_of(dealias(^^B::Alias)) == + std::vector {^^int, ^^std::allocator}); +static_assert(identifier_of(^^B::Alias) == "Alias"); +static_assert(source_location_of(^^B::Alias).line() == 34); + +static_assert(type_of(dealias(^^B::m)) == ^^int); +static_assert(parent_of(^^B::m) == ^^B); +static_assert(dealias(^^B::Alias) == ^^std::vector); +static_assert(template_of(dealias(^^B::Alias)) == ^^std::vector); +static_assert(has_template_arguments(dealias(^^B::Alias))); +static_assert(!has_template_arguments(^^B::Alias)); + +static_assert(substitute(dealias(^^D::TCls), {^^D::Inner}) == + ^^C::TCls); + +static_assert(identifier_of(members_of(^^D, unchecked)[2]) == "m"); +static_assert(is_private(members_of(^^D, unchecked)[2])); + +static_assert(!is_class_member(^^Enum::Red)); +static_assert(is_class_member(^^E::Red)); +static_assert(is_entity_proxy(^^E::Red)); +static_assert(dealias(^^E::Red) == ^^Enum::Red); + +static_assert(!is_namespace_member(^^Enum::Red)); +static_assert(is_namespace_member(^^InnerNS::Red)); + +static_assert(extract(annotations_of(^^G::m)[0]) == 32); +static_assert(!is_access_specified(^^G::m)); +static_assert(is_access_specified(^^G::n)); + +static_assert(dealias(^^H::n) == ^^F::n); + +int main() { } diff --git a/libcxx/test/std/experimental/reflection/example-module.cppm b/libcxx/test/std/experimental/reflection/example-module.cppm index 9d31c6ef20f5..96e13ca03f21 100644 --- a/libcxx/test/std/experimental/reflection/example-module.cppm +++ b/libcxx/test/std/experimental/reflection/example-module.cppm @@ -63,8 +63,9 @@ export struct Base { static constexpr int K = 12; }; export struct Child : private Empty, Base {}; -export constexpr auto rBase1 = bases_of(^^Child)[0]; -export constexpr auto rBase2 = bases_of(^^Child)[1]; +constexpr auto ctx = std::meta::access_context::unchecked(); +export constexpr auto rBase1 = bases_of(^^Child, ctx)[0]; +export constexpr auto rBase2 = bases_of(^^Child, ctx)[1]; // ================================= // Reflections of data members specs diff --git a/libcxx/test/std/experimental/reflection/layout.pass.cpp b/libcxx/test/std/experimental/reflection/layout.pass.cpp index c9981221fc7c..133c84fd1e83 100644 --- a/libcxx/test/std/experimental/reflection/layout.pass.cpp +++ b/libcxx/test/std/experimental/reflection/layout.pass.cpp @@ -9,7 +9,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20 -// ADDITIONAL_COMPILE_FLAGS: -freflection -faccess-contexts +// ADDITIONAL_COMPILE_FLAGS: -freflection // // diff --git a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp index 634ee509a9aa..b29ef44da9c7 100644 --- a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp +++ b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp @@ -19,6 +19,8 @@ #include +constexpr auto ctx = std::meta::access_context::unchecked(); + // ========================== // class_or_namespace_members // ========================== @@ -214,8 +216,8 @@ struct B1 {}; struct B2 {}; struct D : B1, virtual B2 { }; -static_assert(!is_virtual(bases_of(^^D)[0])); -static_assert(is_virtual(bases_of(^^D)[1])); +static_assert(!is_virtual(bases_of(^^D, ctx)[0])); +static_assert(is_virtual(bases_of(^^D, ctx)[1])); static_assert(!is_virtual(^^B1)); static_assert(!is_virtual(^^B2)); @@ -241,12 +243,14 @@ struct S { template void TMemFn(); struct Inner {}; }; -static_assert((members_of(^^S) | std::views::filter(std::meta::is_constructor) | - std::ranges::to()).size() == 4); -static_assert((members_of(^^S) | std::views::filter(std::meta::is_destructor) | - std::ranges::to()).size() == 1); +static_assert((members_of(^^S, ctx) | + std::views::filter(std::meta::is_constructor) | + std::ranges::to()).size() == 4); +static_assert((members_of(^^S, ctx) | + std::views::filter(std::meta::is_destructor) | + std::ranges::to()).size() == 1); static_assert( - (members_of(^^S) | + (members_of(^^S, ctx) | std::views::filter(std::meta::is_special_member_function) | std::ranges::to()).size() == 6); @@ -350,32 +354,32 @@ static_assert(!is_explicit(^^S::mem)); static_assert(!is_explicit(^^S::memfn)); static_assert(!is_explicit(^^S::TMemFn)); static_assert( - !is_explicit((members_of(^^S) | + !is_explicit((members_of(^^S, ctx) | std::views::filter(std::meta::is_constructor) | std::ranges::to())[0])); static_assert( - !is_explicit((members_of(^^S) | + !is_explicit((members_of(^^S, ctx) | std::views::filter(std::meta::is_constructor_template) | std::ranges::to())[0])); static_assert( - is_explicit((members_of(^^S) | + is_explicit((members_of(^^S, ctx) | std::views::filter(std::meta::is_constructor) | std::ranges::to())[1])); static_assert(!is_explicit(^^S::operator int)); static_assert( - !is_explicit((members_of(^^S) | + !is_explicit((members_of(^^S, ctx) | std::views::filter(std::meta::is_template) | std::ranges::to())[3])); static_assert(is_explicit(^^S::operator bool)); // P2996R3 removes support for checking 'explicit' on templates. static_assert( - !is_explicit((members_of(^^S) | + !is_explicit((members_of(^^S, ctx) | std::views::filter(std::meta::is_constructor) | std::ranges::to())[3])); static_assert( - !is_explicit((members_of(^^S) | + !is_explicit((members_of(^^S, ctx) | std::views::filter(std::meta::is_template) | std::ranges::to())[4])); @@ -768,27 +772,30 @@ struct S { }; static_assert( - (members_of(^^S) | std::views::filter(std::meta::is_user_provided) | - std::views::transform(std::meta::is_default_constructor) | - std::ranges::to()) == + (members_of(^^S, ctx) | + std::views::filter(std::meta::is_user_provided) | + std::views::transform(std::meta::is_default_constructor) | + std::ranges::to()) == std::vector {true, true, false, false, false, false, false, false, false, false, false, false, false}); static_assert( - (members_of(^^S) | std::views::filter(std::meta::is_user_provided) | - std::views::transform(std::meta::is_copy_constructor) | - std::ranges::to()) == + (members_of(^^S, ctx) | + std::views::filter(std::meta::is_user_provided) | + std::views::transform(std::meta::is_copy_constructor) | + std::ranges::to()) == std::vector {false, false, true, true, true, true, true, false, false, false, false, false, false}); static_assert( - (members_of(^^S) | std::views::filter(std::meta::is_user_provided) | - std::views::transform(std::meta::is_move_constructor) | - std::ranges::to()) == + (members_of(^^S, ctx) | + std::views::filter(std::meta::is_user_provided) | + std::views::transform(std::meta::is_move_constructor) | + std::ranges::to()) == std::vector {false, false, false, false, false, false, false, true, true, true, true, true, @@ -818,27 +825,29 @@ struct S { }; static_assert( - (members_of(^^S) | std::views::filter(std::meta::is_user_provided) | - std::views::transform(std::meta::is_assignment) | - std::ranges::to()) == + (members_of(^^S, ctx) | std::views::filter(std::meta::is_user_provided) | + std::views::transform(std::meta::is_assignment) | + std::ranges::to()) == std::vector {true, true, true, true, true, true, true, true, true, false}); static_assert( - (members_of(^^S) | std::views::filter(std::meta::is_user_provided) | - std::views::transform(std::meta::is_copy_assignment) | - std::ranges::to()) == + (members_of(^^S, ctx) | + std::views::filter(std::meta::is_user_provided) | + std::views::transform(std::meta::is_copy_assignment) | + std::ranges::to()) == std::vector {true, true, true, true, false, false, false, false, false, false}); static_assert( - (members_of(^^S) | std::views::filter(std::meta::is_user_provided) | - std::views::transform(std::meta::is_move_assignment) | - std::ranges::to()) == + (members_of(^^S, ctx) | + std::views::filter(std::meta::is_user_provided) | + std::views::transform(std::meta::is_move_assignment) | + std::ranges::to()) == std::vector {false, false, false, false, true, true, true, true, false, @@ -858,7 +867,7 @@ struct S { }; static_assert( - (nonstatic_data_members_of(^^S) | + (nonstatic_data_members_of(^^S, ctx) | std::views::transform(std::meta::has_default_member_initializer) | std::ranges::to()) == std::vector {false, true, true}); @@ -957,7 +966,7 @@ int operator""_b(); constexpr auto conversion_template = - (members_of(^^T) | std::views::filter(std::meta::is_template)).front(); + (members_of(^^T, ctx) | std::views::filter(std::meta::is_template)).front(); static_assert(is_operator_function(^^S::operator+)); static_assert(is_operator_function(^^operator&&)); diff --git a/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp b/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp index b409a04a458c..b45065f741c1 100644 --- a/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp +++ b/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp @@ -10,7 +10,6 @@ // UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20 // ADDITIONAL_COMPILE_FLAGS: -freflection -// ADDITIONAL_COMPILE_FLAGS: -faccess-contexts // // diff --git a/libcxx/test/std/experimental/reflection/members-and-subobjects.pass.cpp b/libcxx/test/std/experimental/reflection/members-and-subobjects.pass.cpp index cfb2e75161d3..a31d6c74247c 100644 --- a/libcxx/test/std/experimental/reflection/members-and-subobjects.pass.cpp +++ b/libcxx/test/std/experimental/reflection/members-and-subobjects.pass.cpp @@ -9,7 +9,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20 -// ADDITIONAL_COMPILE_FLAGS: -freflection -faccess-contexts +// ADDITIONAL_COMPILE_FLAGS: -freflection // // diff --git a/libcxx/test/std/experimental/reflection/miscellaneous.pass.cpp b/libcxx/test/std/experimental/reflection/miscellaneous.pass.cpp index 4f6951760217..b7ece7649cfd 100644 --- a/libcxx/test/std/experimental/reflection/miscellaneous.pass.cpp +++ b/libcxx/test/std/experimental/reflection/miscellaneous.pass.cpp @@ -10,7 +10,7 @@ // UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20 // ADDITIONAL_COMPILE_FLAGS: -fblocks -// ADDITIONAL_COMPILE_FLAGS: -freflection -faccess-contexts +// ADDITIONAL_COMPILE_FLAGS: -freflection // ADDITIONAL_COMPILE_FLAGS: -fexpansion-statements // ADDITIONAL_COMPILE_FLAGS: -Wno-inconsistent-missing-override diff --git a/libcxx/test/std/experimental/reflection/names.pass.cpp b/libcxx/test/std/experimental/reflection/names.pass.cpp index ff6b54b4977d..96c35422ed16 100644 --- a/libcxx/test/std/experimental/reflection/names.pass.cpp +++ b/libcxx/test/std/experimental/reflection/names.pass.cpp @@ -19,6 +19,8 @@ #include +constexpr auto ctx = std::meta::access_context::unchecked(); + static_assert(u8display_string_of(^^::) == u8"(global-namespace)"); static_assert(display_string_of(^^::) == "(global-namespace)"); static_assert(!has_identifier(^^::)); @@ -148,7 +150,7 @@ struct Cls : Base { enum class EnumCls { B }; }; static_assert(identifier_of(^^Cls) == "Cls"); -static_assert(!has_identifier(bases_of(^^Cls)[0])); +static_assert(!has_identifier(bases_of(^^Cls, ctx)[0])); static_assert(identifier_of(^^Cls::Alias) == "Alias"); static_assert(has_identifier(^^Cls::Alias)); static_assert(identifier_of(^^Cls::mem) == "mem"); @@ -157,18 +159,18 @@ static_assert(identifier_of(^^Cls::sfn) == "sfn"); static_assert(identifier_of(^^Cls::Inner) == "Inner"); static_assert( - !has_identifier((members_of(^^Cls) | + !has_identifier((members_of(^^Cls, ctx) | std::views::filter(std::meta::is_constructor)).front())); static_assert( - !has_identifier((members_of(^^Cls) | + !has_identifier((members_of(^^Cls, ctx) | std::views::filter(std::meta::is_constructor_template)).front())); static_assert( - !has_identifier((members_of(^^Cls) | + !has_identifier((members_of(^^Cls, ctx) | std::views::filter(std::meta::is_destructor)).front())); static_assert(!has_identifier(^^Cls::operator bool)); static_assert( !has_identifier( - (members_of(^^Cls) | + (members_of(^^Cls, ctx) | std::views::filter(std::meta::is_template) | std::ranges::to())[5])); static_assert(identifier_of(^^Cls::TInner) == "TInner"); @@ -180,34 +182,34 @@ static_assert(identifier_of(^^Cls::Enum::B) == "B"); static_assert(identifier_of(^^Cls::EnumCls) == "EnumCls"); static_assert(identifier_of(^^Cls::EnumCls::B) == "B"); static_assert(display_string_of(^^Cls) == "Cls"); -static_assert(display_string_of(bases_of(^^Cls)[0]) == "Base"); +static_assert(display_string_of(bases_of(^^Cls, ctx)[0]) == "Base"); static_assert(display_string_of(^^Cls::Alias) == "Alias"); static_assert(display_string_of(^^Cls::mem) == "mem"); static_assert(display_string_of(^^Cls::memfn) == "memfn"); static_assert(display_string_of(^^Cls::sfn) == "sfn"); static_assert(display_string_of(^^Cls::Inner) == "Inner"); static_assert( - (members_of(^^Cls) | + (members_of(^^Cls, ctx) | std::views::filter(std::meta::is_constructor) | std::views::filter(std::meta::is_user_provided) | std::views::transform(std::meta::display_string_of) | std::ranges::to()) == std::vector{"Cls"}); static_assert( - (members_of(^^Cls) | + (members_of(^^Cls, ctx) | std::views::filter(std::meta::is_constructor_template) | std::views::transform(std::meta::display_string_of) | std::ranges::to()) == std::vector{"Cls"}); static_assert( - (members_of(^^Cls) | + (members_of(^^Cls, ctx) | std::views::filter(std::meta::is_destructor) | std::views::transform(std::meta::display_string_of) | std::ranges::to()) == std::vector{"~Cls"}); static_assert(display_string_of(^^Cls::operator bool) == "operator bool"); static_assert( - (members_of(^^Cls) | + (members_of(^^Cls, ctx) | std::views::filter(std::meta::is_template) | std::views::transform(std::meta::display_string_of) | std::ranges::to())[5] == diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-alt-named-tuple.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-alt-named-tuple.pass.cpp index 2901b0738a88..7e6ba6705997 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-alt-named-tuple.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-alt-named-tuple.pass.cpp @@ -37,8 +37,9 @@ consteval { make_named_tuple(^^R, {{^^int, "x"}, {^^double, "y"}}); } -static_assert(type_of(nonstatic_data_members_of(^^R)[0]) == ^^int); -static_assert(type_of(nonstatic_data_members_of(^^R)[1]) == ^^double); +constexpr auto ctx = std::meta::access_context::unchecked(); +static_assert(type_of(nonstatic_data_members_of(^^R, ctx)[0]) == ^^int); +static_assert(type_of(nonstatic_data_members_of(^^R, ctx)[1]) == ^^double); int main() { [[maybe_unused]] auto r = R{.x=1, .y=2.0}; diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-emulating-typeful-reflection.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-emulating-typeful-reflection.pass.cpp index 975fabd05ec5..39cb2cfc12ab 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-emulating-typeful-reflection.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-emulating-typeful-reflection.pass.cpp @@ -58,10 +58,10 @@ consteval std::meta::info enrich(std::meta::info r) { // the first constructor. The copy/move constructors are added at the }, so // will be the last ones in the list. std::array ctors = { - (members_of(^^Choices) | + (members_of(^^Choices, std::meta::access_context::current()) | std::views::filter(std::meta::is_constructor) | std::views::filter(std::meta::is_user_provided)).front()..., - (members_of(^^unmatched) | + (members_of(^^unmatched, std::meta::access_context::current()) | std::views::filter(std::meta::is_constructor) | std::views::filter(std::meta::is_user_provided)).front() }; diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-getting-class-layout.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-getting-class-layout.pass.cpp index 27a9ea8cb091..bd58f865cc5b 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-getting-class-layout.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-getting-class-layout.pass.cpp @@ -32,8 +32,9 @@ struct member_descriptor // returns std::array template consteval auto get_layout() { - auto members = nonstatic_data_members_of(^^S); - constexpr size_t sz = nonstatic_data_members_of(^^S).size(); + constexpr auto ctx = std::meta::access_context::current(); + auto members = nonstatic_data_members_of(^^S, ctx); + constexpr size_t sz = nonstatic_data_members_of(^^S, ctx).size(); std::array layout; for (int i = 0; i < members.size(); ++i) { layout[i] = { diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-named-tuple.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-named-tuple.pass.cpp index 189faca08b3b..23f9342d4121 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-named-tuple.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-named-tuple.pass.cpp @@ -61,8 +61,9 @@ consteval { make_named_tuple(^^R, pair{}, pair{}); } -static_assert(type_of(nonstatic_data_members_of(^^R)[0]) == ^^int); -static_assert(type_of(nonstatic_data_members_of(^^R)[1]) == ^^double); +constexpr auto ctx = std::meta::access_context::current(); +static_assert(type_of(nonstatic_data_members_of(^^R, ctx)[0]) == ^^int); +static_assert(type_of(nonstatic_data_members_of(^^R, ctx)[1]) == ^^double); int main() { [[maybe_unused]] auto r = R{.x=1, .y=2.0}; diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-parsing-command-line-options-1.sh.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-parsing-command-line-options-1.sh.cpp index 29ad66384c69..a184a5dd0210 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-parsing-command-line-options-1.sh.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-parsing-command-line-options-1.sh.cpp @@ -9,7 +9,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20 -// ADDITIONAL_COMPILE_FLAGS: -freflection -faccess-contexts +// ADDITIONAL_COMPILE_FLAGS: -freflection // ADDITIONAL_COMPILE_FLAGS: -fexpansion-statements // ADDITIONAL_COMPILE_FLAGS: -Wno-inconsistent-missing-override diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-parsing-command-line-options-2.sh.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-parsing-command-line-options-2.sh.cpp index 3d1e77f10c80..7a7d8c58f87b 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-parsing-command-line-options-2.sh.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-parsing-command-line-options-2.sh.cpp @@ -10,7 +10,6 @@ // UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20 // ADDITIONAL_COMPILE_FLAGS: -freflection -fexpansion-statements -// ADDITIONAL_COMPILE_FLAGS: -faccess-contexts // ADDITIONAL_COMPILE_FLAGS: -Wno-inconsistent-missing-override // diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-selecting-members-pt2.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-selecting-members-pt2.pass.cpp index 051e25a95df0..b95f63666573 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-selecting-members-pt2.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-selecting-members-pt2.pass.cpp @@ -21,7 +21,8 @@ struct S { unsigned i:2, j:6; }; consteval auto member_number(int n) { - return std::meta::nonstatic_data_members_of(^^S)[n]; + constexpr auto ctx = std::meta::access_context::current(); + return std::meta::nonstatic_data_members_of(^^S, ctx)[n]; } int main() { diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-selecting-members-pt3.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-selecting-members-pt3.pass.cpp index 92efa8e6bc1e..26531b2df8ea 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-selecting-members-pt3.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-selecting-members-pt3.pass.cpp @@ -21,7 +21,8 @@ struct S { unsigned i:2, j:6; }; consteval auto member_named(std::string_view name) { - for (std::meta::info field : nonstatic_data_members_of(^^S)) { + constexpr auto ctx = std::meta::access_context::current(); + for (std::meta::info field : nonstatic_data_members_of(^^S, ctx)) { if (identifier_of(field) == name) return field; } std::unreachable(); diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-simple-tuple-type.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-simple-tuple-type.pass.cpp index 3ff8ea6ccfbb..8343c01358f3 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-simple-tuple-type.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-simple-tuple-type.pass.cpp @@ -38,7 +38,8 @@ template struct Tuple { }; consteval std::meta::info get_nth_field(std::meta::info r, std::size_t n) { - return nonstatic_data_members_of(r)[n]; + constexpr auto ctx = std::meta::access_context::current(); + return nonstatic_data_members_of(r, ctx)[n]; } template diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-struct-to-struct-of-arrays.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-struct-to-struct-of-arrays.pass.cpp index b377fa728756..90515965ffb8 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-struct-to-struct-of-arrays.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-struct-to-struct-of-arrays.pass.cpp @@ -29,7 +29,9 @@ struct struct_of_arrays_impl { struct impl; consteval { - std::vector old_members = nonstatic_data_members_of(^^T); + constexpr auto ctx = std::meta::access_context::current(); + std::vector old_members = nonstatic_data_members_of(^^T, + ctx); std::vector new_members = {}; for (std::meta::info member : old_members) { auto array_type = substitute(^^std::array, { diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-struct-to-tuple.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-struct-to-tuple.pass.cpp index 1dcb711b0a1d..dd1d59038079 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-struct-to-tuple.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-struct-to-tuple.pass.cpp @@ -32,8 +32,9 @@ consteval auto struct_to_tuple_type(std::meta::info type) -> std::meta::info { return substitute(^^std::remove_cvref_t, {r}); }; + constexpr auto ctx = std::meta::access_context::current(); return substitute(^^std::tuple, - nonstatic_data_members_of(type) + nonstatic_data_members_of(type, ctx) | std::views::transform(std::meta::type_of) | std::views::transform(remove_cvref) | std::ranges::to()); @@ -49,7 +50,8 @@ consteval auto get_struct_to_tuple_helper() { using To = [: struct_to_tuple_type(^^From) :]; std::vector args = {^^To, ^^From}; - for (auto mem : nonstatic_data_members_of(^^From)) { + constexpr auto ctx = std::meta::access_context::current(); + for (auto mem : nonstatic_data_members_of(^^From, ctx)) { args.push_back(reflect_value(mem)); } diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-universal-formatter.sh.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-universal-formatter.sh.cpp index d13e4e6e745f..e4a090abefbe 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-universal-formatter.sh.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-universal-formatter.sh.cpp @@ -10,7 +10,6 @@ // UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20 // ADDITIONAL_COMPILE_FLAGS: -freflection -fexpansion-statements -// ADDITIONAL_COMPILE_FLAGS: -faccess-contexts // ADDITIONAL_COMPILE_FLAGS: -Wno-inconsistent-missing-override // diff --git a/libcxx/test/std/experimental/reflection/p3096-fn-parameters.pass.cpp b/libcxx/test/std/experimental/reflection/p3096-fn-parameters.pass.cpp index e6249fda9a11..964d776da191 100644 --- a/libcxx/test/std/experimental/reflection/p3096-fn-parameters.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p3096-fn-parameters.pass.cpp @@ -19,6 +19,8 @@ #include +constexpr auto ctx = std::meta::access_context::unchecked(); + // ================= // with_no_arguments // ================= @@ -84,7 +86,8 @@ struct Cls { }; constexpr auto ctor = - (members_of(^^Cls) | std::views::filter(std::meta::is_constructor)).front(); + (members_of(^^Cls, ctx) | + std::views::filter(std::meta::is_constructor)).front(); static_assert(parameters_of(ctor).size() == 1); static_assert(type_of(parameters_of(ctor)[0]) == ^^int); static_assert(identifier_of(parameters_of(ctor)[0]) == "a"); @@ -94,7 +97,8 @@ static_assert(!is_explicit_object_parameter(parameters_of(ctor)[0])); static_assert(!has_ellipsis_parameter(ctor)); constexpr auto dtor = - (members_of(^^Cls) | std::views::filter(std::meta::is_destructor)).front(); + (members_of(^^Cls, ctx) | + std::views::filter(std::meta::is_destructor)).front(); static_assert(parameters_of(dtor).size() == 0); static_assert(!has_ellipsis_parameter(dtor)); diff --git a/libcxx/test/std/experimental/reflection/reflect-invoke.pass.cpp b/libcxx/test/std/experimental/reflection/reflect-invoke.pass.cpp index 7682e89e0125..f0577ff6ba23 100644 --- a/libcxx/test/std/experimental/reflection/reflect-invoke.pass.cpp +++ b/libcxx/test/std/experimental/reflection/reflect-invoke.pass.cpp @@ -21,6 +21,8 @@ #include +constexpr auto ctx = std::meta::access_context::unchecked(); + // =============== // basic_functions // =============== @@ -175,12 +177,12 @@ struct Cls { }; constexpr auto ctor = - (members_of(^^Cls) | + (members_of(^^Cls, ctx) | std::views::filter(std::meta::is_constructor) | std::views::filter(std::meta::is_user_provided)).front(); constexpr auto ctor_template = - (members_of(^^Cls) | + (members_of(^^Cls, ctx) | std::views::filter(std::meta::is_constructor_template)).front(); // Non-template constructor. diff --git a/libcxx/test/std/experimental/reflection/related-reflections.pass.cpp b/libcxx/test/std/experimental/reflection/related-reflections.pass.cpp index 5ea00abea09a..1897952dfcb2 100644 --- a/libcxx/test/std/experimental/reflection/related-reflections.pass.cpp +++ b/libcxx/test/std/experimental/reflection/related-reflections.pass.cpp @@ -18,6 +18,8 @@ #include +constexpr auto ctx = std::meta::access_context::current(); + // ============ // find_type_of // ============ @@ -104,7 +106,7 @@ static_assert(parent_of(^^Cls::mem) == ^^Cls); static_assert(parent_of(^^Cls::memfn) == ^^Cls); static_assert(parent_of(^^Cls::sfn) == ^^Cls); static_assert(parent_of(^^Cls::Alias) == ^^Cls); -static_assert(parent_of(bases_of(^^Cls)[0]) == ^^Cls); +static_assert(parent_of(bases_of(^^Cls, ctx)[0]) == ^^Cls); static_assert(parent_of(^^Cls::TSMem) == ^^Cls); static_assert(parent_of(^^Cls::TSMem) == ^^Cls); diff --git a/libcxx/test/std/experimental/reflection/source-location.pass.cpp b/libcxx/test/std/experimental/reflection/source-location.pass.cpp index 74718ec9b23b..bec4c764f5a6 100644 --- a/libcxx/test/std/experimental/reflection/source-location.pass.cpp +++ b/libcxx/test/std/experimental/reflection/source-location.pass.cpp @@ -39,8 +39,9 @@ void foo(int param) { static_assert(source_location_of(^^S).function_name() == FnName); struct C : S {}; - static_assert(source_location_of(bases_of(^^C)[0]).line() == - std::source_location::current().line() - 2); + constexpr auto ctx = std::meta::access_context::current(); + static_assert(source_location_of(bases_of(^^C, ctx)[0]).line() == + std::source_location::current().line() - 3); // Check that it works with aliases. using intAlias = int; diff --git a/libcxx/test/std/experimental/reflection/static-arrays.pass.cpp b/libcxx/test/std/experimental/reflection/static-arrays.pass.cpp index 2f2b95b9c08b..5bf5c4e64d6c 100644 --- a/libcxx/test/std/experimental/reflection/static-arrays.pass.cpp +++ b/libcxx/test/std/experimental/reflection/static-arrays.pass.cpp @@ -19,6 +19,8 @@ #include +constexpr auto ctx = std::meta::access_context::unchecked(); + // ============= // static_arrays // ============= @@ -42,7 +44,8 @@ static_assert(objs.size() == 3); static_assert(objs[0].k == 5 && objs[1].k == 7 && objs[2].k == 9); constexpr auto infos = std::define_static_array( - nonstatic_data_members_of(^^Cls)); + nonstatic_data_members_of(^^Cls, + ctx)); static_assert(infos.size() == 1); static_assert(infos[0] == ^^Cls::k); } // namespace static_arrays diff --git a/libcxx/test/std/experimental/reflection/substitute.pass.cpp b/libcxx/test/std/experimental/reflection/substitute.pass.cpp index 9e1aab3e9c23..de553ce603fa 100644 --- a/libcxx/test/std/experimental/reflection/substitute.pass.cpp +++ b/libcxx/test/std/experimental/reflection/substitute.pass.cpp @@ -24,6 +24,9 @@ #include #include + +constexpr auto ctx = std::meta::access_context::unchecked(); + template constexpr std::meta::info RVal = std::meta::reflect_value(K); @@ -369,7 +372,8 @@ namespace with_reflection_of_declaration { template constexpr int Plus1 = V + 1; struct S { static constexpr int val = 4; }; -static_assert([:substitute(^^Plus1, {static_data_members_of(^^S)[0]}):] == 5); +static_assert([:substitute(^^Plus1, + {static_data_members_of(^^S, ctx)[0]}):] == 5); } // namespace with_reflection_of_declaration // ========================== @@ -455,7 +459,7 @@ namespace non_type_ref_regression_test { class Cls { static constexpr int priv = 11; }; template static constexpr auto &Value = V; -static_assert([:substitute(^^Value, {members_of(^^Cls)[0]}):] == 11); +static_assert([:substitute(^^Value, {members_of(^^Cls, ctx)[0]}):] == 11); } // namespace non_type_ref_regression_test int main() { } diff --git a/libcxx/test/std/experimental/reflection/template-arguments.pass.cpp b/libcxx/test/std/experimental/reflection/template-arguments.pass.cpp index 0ef60254b00d..b18803318210 100644 --- a/libcxx/test/std/experimental/reflection/template-arguments.pass.cpp +++ b/libcxx/test/std/experimental/reflection/template-arguments.pass.cpp @@ -18,6 +18,8 @@ #include +constexpr auto ctx = std::meta::access_context::unchecked(); + template class P3> struct TCls { template struct TInnerCls {}; @@ -327,9 +329,9 @@ template void fn() { } void fn() { class S { S(); ~S(); }; - fn<(members_of(^^S) | + fn<(members_of(^^S, ctx) | std::views::filter(std::meta::is_constructor)).front()>(); - fn<(members_of(^^S) | + fn<(members_of(^^S, ctx) | std::views::filter(std::meta::is_destructor)).front()>(); } } // namespace bb_clang_p2996_issue_54_regression_test diff --git a/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp b/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp index f957e4a8fda8..4efb06d52c3e 100644 --- a/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp +++ b/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp @@ -144,7 +144,8 @@ static_assert(CheckValueIs<42>([]() { static_assert( CheckValueIs<3>( static_data_members_of(substitute(^^TCls, - {std::meta::reflect_value(3)}))[0])); + {std::meta::reflect_value(3)}), + std::meta::access_context::unchecked())[0])); } // namespace extract_results // =========