From 1cefb01b8480c182dd03e8139ccc89d216df7f5b Mon Sep 17 00:00:00 2001 From: Dan Katz Date: Sun, 17 Mar 2024 00:51:04 -0400 Subject: [PATCH] Fix some crashes. - members_of(^int), bases_of(^int), etc. - Tree transform that leaves a value-dependent splice in place. Also replace 'member_of' with 'enumerators_of' in P2996 example. Tested: Ran 'check-all' on MacOS. --- clang/lib/Sema/Metafunctions.cpp | 16 +++++++++++----- clang/lib/Sema/TreeTransform.h | 6 ++++++ .../reflection/p2996-ex-enum-to-string.pass.cpp | 4 ++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index f86df82c4c70de..7d2f189120792b 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -950,7 +950,7 @@ bool get_begin_enumerator_decl_of(APValue &Result, Sema &S, EvalFn Evaluator, case ReflectionValue::RK_type: { Decl *D = findTypeDecl(R.getReflectedType()); - if (auto enumDecl = dyn_cast(D)) { + if (auto enumDecl = dyn_cast_or_null(D)) { if (auto itr = enumDecl->enumerator_begin(); itr != enumDecl->enumerator_end()) { return SetAndSucceed(Result, makeReflection(*itr)); @@ -1030,9 +1030,9 @@ bool get_ith_base_of(APValue &Result, Sema &S, EvalFn Evaluator, case ReflectionValue::RK_type: { Decl *typeDecl = findTypeDecl(R.getReflectedType()); - ensureInstantiated(S, typeDecl, Range); + if (auto cxxRecordDecl = dyn_cast_or_null(typeDecl)) { + ensureInstantiated(S, typeDecl, Range); - if (auto cxxRecordDecl = dyn_cast(typeDecl)) { auto numBases = cxxRecordDecl->getNumBases(); if (idx >= numBases) return SetAndSucceed(Result, Sentinel); @@ -1131,6 +1131,8 @@ bool get_begin_member_decl_of(APValue &Result, Sema &S, EvalFn Evaluator, ensureDeclared(S, QT, Range.getBegin()); Decl *typeDecl = findTypeDecl(QT); + if (!typeDecl) + return true; DeclContext *declContext = dyn_cast(typeDecl); assert(declContext && "no DeclContext?"); @@ -1962,8 +1964,10 @@ bool is_accessible(APValue &Result, Sema &S, EvalFn Evaluator, switch (R.getReflection().getKind()) { case ReflectionValue::RK_type: { - bool Accessible = isAccessible(S, AccessDC, - findTypeDecl(R.getReflectedType())); + NamedDecl *D = findTypeDecl(R.getReflectedType()); + if (!D) + return true; + bool Accessible = isAccessible(S, AccessDC, D); return SetAndSucceed(Result, makeBool(S.Context, Accessible)); } case ReflectionValue::RK_declaration: { @@ -1978,6 +1982,8 @@ bool is_accessible(APValue &Result, Sema &S, EvalFn Evaluator, case ReflectionValue::RK_base_specifier: { // TODO(P2996): Need an edge back to derived class. NamedDecl *ND = findTypeDecl(R.getReflectedBaseSpecifier()->getType()); + if (!ND) + return true; bool Accessible = isAccessible(S, AccessDC, ND); return SetAndSucceed(Result, makeBool(S.Context, Accessible)); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 3df69eb4473c2e..4d7b30cd09d053 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4451,6 +4451,12 @@ NestedNameSpecifierLoc TreeTransform::TransformNestedNameSpecifierLoc( if (ER.isInvalid()) return NestedNameSpecifierLoc(); + else if (ER.get()->isValueDependent()) { + SS.MakeIndeterminateSplice(SemaRef.Context, + cast(ER.get()), + Q.getLocalEndLoc()); + break; + } Expr *Operand = ER.get(); // Should have a non-dependent expression now: Evaluate it. diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-enum-to-string.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-enum-to-string.pass.cpp index 61c33b6dda2c14..765208bad065a5 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-enum-to-string.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-enum-to-string.pass.cpp @@ -51,7 +51,7 @@ template requires std::is_enum_v constexpr std::string enum_to_string(E value) { std::string result = ""; - [:expand(members_of(^E)):] >> [&] { + [:expand(enumerators_of(^E)):] >> [&] { if (value == [:e:]) { result = std::string(name_of(e)); } @@ -63,7 +63,7 @@ template requires std::is_enum_v constexpr std::optional string_to_enum(std::string_view name) { std::optional result = std::nullopt; - [:expand(members_of(^E)):] >> [&] { + [:expand(enumerators_of(^E)):] >> [&] { if (name == name_of(e)) { result = [:e:]; }