From 9bacba352da6a96e09baa1e6860b4bda905d5760 Mon Sep 17 00:00:00 2001 From: Kay Hicketts Date: Thu, 4 Apr 2024 11:32:26 -0400 Subject: [PATCH 1/3] add qualified_name_of --- clang/lib/Sema/Metafunctions.cpp | 65 ++++++++++++++++++++++++++++++++ libcxx/include/experimental/meta | 7 ++++ 2 files changed, 72 insertions(+) diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index 3fa124418d1b37..31ec3ea5ea1ca7 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -70,6 +70,10 @@ static bool name_of(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, SourceRange Range, ArrayRef Args); +static bool qualified_name_of(APValue &Result, Sema &S, EvalFn Evaluator, + QualType ResultTy, SourceRange Range, + ArrayRef Args); + static bool display_name_of(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, SourceRange Range, ArrayRef Args); @@ -326,6 +330,7 @@ static constexpr Metafunction Metafunctions[] = { // exposed metafunctions { Metafunction::MFRK_cstring, 1, 1, name_of }, + { Metafunction::MFRK_cstring, 1, 1, qualified_name_of }, { Metafunction::MFRK_cstring, 1, 1, display_name_of }, { Metafunction::MFRK_sourceLoc, 1, 1, source_location_of }, { Metafunction::MFRK_metaInfo, 1, 1, type_of }, @@ -1252,6 +1257,66 @@ bool map_decl_to_entity(APValue &Result, Sema &S, EvalFn Evaluator, llvm_unreachable("unknown reflection kind"); } +template +bool getQualifiedName(APValue &Result, Sema &S, EvalFn Evaluator, DT& declType) +{ + SmallString<128> QualifiedNameBuffer; + llvm::raw_svector_ostream OS(QualifiedNameBuffer); + declType.printQualifiedName(OS); + StringRef Name = QualifiedNameBuffer.str(); + if( makeCString(Result, Name, S.Context, Evaluator) ) + { + llvm_unreachable("failed to create qualified name string"); + return true; + } + return false; +} + +bool qualified_name_of(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, + SourceRange Range, ArrayRef Args) { + assert(Args[0]->getType()->isReflectionType()); + assert(ResultTy == + S.Context.getPointerType(S.Context.getConstType(S.Context.CharTy))); + + APValue R; + if (!Evaluator(R, Args[0], true)) + return true; + + switch (R.getReflection().getKind()) { + case ReflectionValue::RK_type: { + QualType QT = R.getReflectedType(); // inconsitently returns qualified type {fix?} + return SetAndSucceed(Result, getTypeName(S.Context, Evaluator, QT, + /*emptyIfUnnamed=*/true)); + } + case ReflectionValue::RK_declaration: { // works + const ValueDecl *VD = cast(R.getReflectedDecl()); + return getQualifiedName(Result, S, Evaluator, *VD); + } + case ReflectionValue::RK_template: { // works + const TemplateDecl *TD = cast(R.getReflectedTemplate().getAsTemplateDecl()); + return getQualifiedName(Result, S, Evaluator, *TD); + } + case ReflectionValue::RK_const_value: { + if (makeCString(Result, "", S.Context, Evaluator)) + llvm_unreachable("failed to create empty string"); + return false; + } + case ReflectionValue::RK_namespace: { // works + const NamespaceDecl *ND = cast(R.getReflectedNamespace()); + return getQualifiedName(Result, S, Evaluator, *ND); + } + case ReflectionValue::RK_base_specifier: { + QualType QT = R.getReflectedBaseSpecifier()->getType(); + const Decl* D = findTypeDecl(QT); + const TypeDecl *TD = cast(D); + return getQualifiedName(Result, S, Evaluator, *TD); + } + case ReflectionValue::RK_data_member_spec: + return true; + } + llvm_unreachable("unknown reflection kind"); +} + bool name_of(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, SourceRange Range, ArrayRef Args) { assert(Args[0]->getType()->isReflectionType()); diff --git a/libcxx/include/experimental/meta b/libcxx/include/experimental/meta index 871f893e8f4c05..eccbbffdc2f9b6 100644 --- a/libcxx/include/experimental/meta +++ b/libcxx/include/experimental/meta @@ -28,6 +28,7 @@ using info = decltype(^int); // name and location consteval auto name_of(info) -> string_view; +consteval auto qualified_name_of(info) -> string_view; consteval auto display_name_of(info) -> string_view; consteval auto source_location_of(info r) -> source_location; @@ -159,6 +160,7 @@ enum : unsigned { // exposed metafunctions __metafn_name_of, + __metafn_qualified_name_of, __metafn_display_name_of, __metafn_source_location_of, __metafn_type_of, @@ -444,6 +446,11 @@ consteval auto name_of(info r) -> string_view { return __metafunction(detail::__metafn_name_of, r); } +// Returns the qualified name of the reflected entity, or the empty string if it has none. +consteval auto qualified_name_of(info r) -> string_view { + return __metafunction(detail::__metafn_qualified_name_of, r); +} + // Returns a name for the reflected entity. consteval auto display_name_of(info r) -> string_view { return __metafunction(detail::__metafn_display_name_of, r); From 479c0412eec476436382559ee43bd57c97881e21 Mon Sep 17 00:00:00 2001 From: Kay Hicketts Date: Wed, 10 Apr 2024 06:20:24 -0400 Subject: [PATCH 2/3] . --- .../p2996-ex-qualified_name_of.pass.cpp | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 libcxx/test/std/experimental/reflection/p2996-ex-qualified_name_of.pass.cpp diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-qualified_name_of.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-qualified_name_of.pass.cpp new file mode 100644 index 00000000000000..d0af11dc42c929 --- /dev/null +++ b/libcxx/test/std/experimental/reflection/p2996-ex-qualified_name_of.pass.cpp @@ -0,0 +1,68 @@ +#include + +#include +#include + +namespace outer_namespace{ +namespace a_namespace { +namespace an_inner_namespace +{ +struct ClassInsideSomeNamespaces { + int k; + int j; + using type = int; +}; + +typedef ClassInsideSomeNamespaces ClassInsideSomeNamespacesAlias; + +template +class SomeTemplateClass +{ + std::vector stuff; + public: + SomeTemplateClass(const T& t) + { + stuff.push_back(t); + } +}; + +class DerivedClass: public ClassInsideSomeNamespaces +{ + int boopTheBloop; +}; + +const std::string aString = "abcde"; +} // an_inner_namespace +} // a_namespace +} // outer_namespace + +int main() +{ + using namespace outer_namespace; + using namespace a_namespace; + using namespace an_inner_namespace; + + constexpr auto expectedQNofType = "outer_namespace::a_namespace::an_inner_namespace::ClassInsideSomeNamespaces"; + static_assert(expectedQNofType==std::meta::qualified_name_of(^ClassInsideSomeNamespaces)); + + constexpr auto expectedQNofDeclaration = "outer_namespace::a_namespace::an_inner_namespace::aString"; + static_assert(expectedQNofDeclaration==std::meta::qualified_name_of(^aString)); + + constexpr auto expectedQNofNamespace = "outer_namespace::a_namespace::an_inner_namespace"; + static_assert(expectedQNofNamespace==std::meta::qualified_name_of(^an_inner_namespace)); + + constexpr auto expectedQNofTemplate = "outer_namespace::a_namespace::an_inner_namespace::SomeTemplateClass"; + static_assert(expectedQNofTemplate==std::meta::qualified_name_of(^SomeTemplateClass)); + + constexpr auto expectedQNofTypeAlias = "outer_namespace::a_namespace::an_inner_namespace::ClassInsideSomeNamespacesAlias"; + static_assert(expectedQNofTypeAlias==std::meta::qualified_name_of(^ClassInsideSomeNamespacesAlias)); + + constexpr auto expectedQNofDerivedType = "outer_namespace::a_namespace::an_inner_namespace::DerivedClass"; + static_assert(expectedQNofDerivedType==std::meta::qualified_name_of(^DerivedClass)); + + constexpr auto expectedQNofBaseSpecifier="outer_namespace::a_namespace::an_inner_namespace::ClassInsideSomeNamespaces"; + constexpr auto base = [:(std::meta::reflect_value(std::meta::bases_of(^DerivedClass)[0])):]; + static_assert(expectedQNofBaseSpecifier==std::meta::qualified_name_of(base)); + + return 0; +} \ No newline at end of file From a59d242ba33b78e9aa88c426f3d362d926b66856 Mon Sep 17 00:00:00 2001 From: Kay Hicketts Date: Wed, 10 Apr 2024 06:43:08 -0400 Subject: [PATCH 3/3] . --- clang/lib/Sema/Metafunctions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index 31ec3ea5ea1ca7..1611fdc3144e9b 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -1284,15 +1284,15 @@ bool qualified_name_of(APValue &Result, Sema &S, EvalFn Evaluator, QualType Resu switch (R.getReflection().getKind()) { case ReflectionValue::RK_type: { - QualType QT = R.getReflectedType(); // inconsitently returns qualified type {fix?} + QualType QT = R.getReflectedType(); return SetAndSucceed(Result, getTypeName(S.Context, Evaluator, QT, /*emptyIfUnnamed=*/true)); } - case ReflectionValue::RK_declaration: { // works + case ReflectionValue::RK_declaration: { const ValueDecl *VD = cast(R.getReflectedDecl()); return getQualifiedName(Result, S, Evaluator, *VD); } - case ReflectionValue::RK_template: { // works + case ReflectionValue::RK_template: { const TemplateDecl *TD = cast(R.getReflectedTemplate().getAsTemplateDecl()); return getQualifiedName(Result, S, Evaluator, *TD); } @@ -1301,7 +1301,7 @@ bool qualified_name_of(APValue &Result, Sema &S, EvalFn Evaluator, QualType Resu llvm_unreachable("failed to create empty string"); return false; } - case ReflectionValue::RK_namespace: { // works + case ReflectionValue::RK_namespace: { const NamespaceDecl *ND = cast(R.getReflectedNamespace()); return getQualifiedName(Result, S, Evaluator, *ND); }