lime created this revision. lime added reviewers: aaron.ballman, erichkeane, cor3ntin, clang-language-wg. Herald added a subscriber: yaxunl. Herald added a project: All. lime requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This patch includes the commit 01adf96ebc86 <https://reviews.llvm.org/rG01adf96ebc8608bcdda0cacc303035b2e60ccb46> and a fix that makes the commit crash due to unhandled declaration references. When looking up base classes, Clang first checks whether a base class is a template and takes the specialized template base on it. However, the base class might be instantiated, and the above behavior can lose information. This patch fixes the problem by first checking whether a base class is a record declarations, so the instantiated one will be taken. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D143840 Files: clang/docs/ReleaseNotes.rst clang/include/clang/AST/DeclCXX.h clang/lib/AST/CXXInheritance.cpp clang/lib/Sema/SemaExpr.cpp clang/test/CodeGenCXX/decl-ref-inheritance.cpp clang/test/SemaCXX/decltype.cpp
Index: clang/test/SemaCXX/decltype.cpp =================================================================== --- clang/test/SemaCXX/decltype.cpp +++ clang/test/SemaCXX/decltype.cpp @@ -101,6 +101,44 @@ template<class T> void foo(decltype(T(LP1{ .p1 = g1, .p1.x[1] = 'x' }))) {} } +namespace GH58674 { + struct Foo { + float value_; + struct nested { + float value_; + }; + }; + + template <typename T> + struct TemplateFoo { + float value_; + }; + + float bar; + + template <typename T> + struct Animal{}; + + template <typename T> + class Cat : Animal<T> { + using okay = decltype(Foo::value_); + using also_okay = decltype(bar); + using okay2 = decltype(Foo::nested::value_); + using okay3 = decltype(TemplateFoo<T>::value_); + public: + void meow() { + using okay = decltype(Foo::value_); + using also_okay = decltype(bar); + using okay2 = decltype(Foo::nested::value_); + using okay3 = decltype(TemplateFoo<T>::value_); + } + }; + + void baz() { + Cat<void>{}.meow(); + } +} + template<typename> class conditional { }; Index: clang/test/CodeGenCXX/decl-ref-inheritance.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/decl-ref-inheritance.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple=x86_64-unknown-linux -emit-llvm %s -o - | FileCheck %s + +// CHECK: [[FOO:%.+]] = type { i32 } +struct foo { + int val; +}; + +template <typename T> struct bar : T { +}; + +struct baz : bar<foo> { + // CHECK-LABEL: define{{.*}} i32 @_ZN3baz3getEv + // CHECK: {{%.+}} = getelementptr inbounds [[FOO]], ptr {{%.+}}, i32 0, i32 0 + int get() { + return val; + } +}; + +int qux() { + auto f = baz{}; + return f.get(); +} Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -2693,20 +2693,36 @@ // to get this right here so that we don't end up making a // spuriously dependent expression if we're inside a dependent // instance method. + // + // We also don't need to do this if R resolved to a member in another + // class, which can happen in an unevaluated operand: + // + // C++ [expr.prim.id]p3.3: + // If that id-expression denotes a non-static data member and it + // appears in an unevaluated operand. if (!R.empty() && (*R.begin())->isCXXClassMember()) { - bool MightBeImplicitMember; - if (!IsAddressOfOperand) - MightBeImplicitMember = true; - else if (!SS.isEmpty()) - MightBeImplicitMember = false; - else if (R.isOverloadedResult()) - MightBeImplicitMember = false; - else if (R.isUnresolvableResult()) - MightBeImplicitMember = true; - else - MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) || - isa<IndirectFieldDecl>(R.getFoundDecl()) || - isa<MSPropertyDecl>(R.getFoundDecl()); + bool MightBeImplicitMember = true, CheckField = true; + if (IsAddressOfOperand) { + MightBeImplicitMember = SS.isEmpty() && !R.isOverloadedResult(); + CheckField = !R.isUnresolvableResult(); + } + if (MightBeImplicitMember && CheckField) { + if (R.isSingleResult() && + isa<FieldDecl, IndirectFieldDecl, MSPropertyDecl>(R.getFoundDecl())) { + auto Class = cast<CXXRecordDecl>((*R.begin())->getDeclContext()); + for (auto Curr = S->getLookupEntity(); Curr && !Curr->isFileContext(); + Curr = Curr->getParent()) { + if (auto ThisClass = dyn_cast_if_present<CXXRecordDecl>(Curr)) { + if ((MightBeImplicitMember = + ThisClass->Equals(Class) || + ThisClass->isDerivedFrom(Class, + /*LookupIndependent=*/true))) + break; + } + } + } else if (IsAddressOfOperand) + MightBeImplicitMember = false; + } if (MightBeImplicitMember) return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, Index: clang/lib/AST/CXXInheritance.cpp =================================================================== --- clang/lib/AST/CXXInheritance.cpp +++ clang/lib/AST/CXXInheritance.cpp @@ -63,15 +63,16 @@ std::swap(DetectVirtual, Other.DetectVirtual); std::swap(DetectedVirtual, Other.DetectedVirtual); } - -bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base) const { +bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base, + bool LookupIndependent) const { CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false, /*DetectVirtual=*/false); - return isDerivedFrom(Base, Paths); + return isDerivedFrom(Base, Paths, LookupIndependent); } bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base, - CXXBasePaths &Paths) const { + CXXBasePaths &Paths, + bool LookupIndependent) const { if (getCanonicalDecl() == Base->getCanonicalDecl()) return false; @@ -246,17 +247,16 @@ } else if (VisitBase) { CXXRecordDecl *BaseRecord; if (LookupInDependent) { - BaseRecord = nullptr; - const TemplateSpecializationType *TST = - BaseSpec.getType()->getAs<TemplateSpecializationType>(); - if (!TST) { - if (auto *RT = BaseSpec.getType()->getAs<RecordType>()) - BaseRecord = cast<CXXRecordDecl>(RT->getDecl()); - } else { - TemplateName TN = TST->getTemplateName(); - if (auto *TD = - dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) - BaseRecord = TD->getTemplatedDecl(); + BaseRecord = cast_if_present<CXXRecordDecl>( + BaseSpec.getType()->getAsRecordDecl()); + if (!BaseRecord) { + if (const TemplateSpecializationType *TST = + BaseSpec.getType()->getAs<TemplateSpecializationType>()) { + TemplateName TN = TST->getTemplateName(); + if (auto *TD = + dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) + BaseRecord = TD->getTemplatedDecl(); + } } if (BaseRecord) { if (!BaseRecord->hasDefinition() || Index: clang/include/clang/AST/DeclCXX.h =================================================================== --- clang/include/clang/AST/DeclCXX.h +++ clang/include/clang/AST/DeclCXX.h @@ -1546,8 +1546,11 @@ /// /// \param Base the base class we are searching for. /// + /// \param LookupIndependent whether look up independent types. + /// /// \returns true if this class is derived from Base, false otherwise. - bool isDerivedFrom(const CXXRecordDecl *Base) const; + bool isDerivedFrom(const CXXRecordDecl *Base, + bool LookupIndependent = false) const; /// Determine whether this class is derived from the type \p Base. /// @@ -1561,11 +1564,14 @@ /// \param Paths will contain the paths taken from the current class to the /// given \p Base class. /// + /// \param LookupIndependent whether look up independent types. + /// /// \returns true if this class is derived from \p Base, false otherwise. /// /// \todo add a separate parameter to configure IsDerivedFrom, rather than /// tangling input and output in \p Paths - bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths) const; + bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths, + bool LookupIndependent = false) const; /// Determine whether this class is virtually derived from /// the class \p Base. Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -67,6 +67,9 @@ - Fix crash when evaluating consteval constructor of derived class whose base has more than one field. This fixes `Issue 60166 <https://github.com/llvm/llvm-project/issues/60166>`_. +- Fix an issue about ``decltype`` in the members of class templates derived from + templates with related parameters. This fixes + `Issue 58674 <https://github.com/llvm/llvm-project/issues/58674>`_. Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits