[clang] 8498ba6 - [clang] Add the check of membership for the issue #58674 and improve the lookup process

Liming Liu via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 22 00:45:38 PST 2023


Author: Liming Liu
Date: 2023-02-22T16:43:50+08:00
New Revision: 8498ba6c2860c838183f9951b63df26ab5f02265

URL: https://github.com/llvm/llvm-project/commit/8498ba6c2860c838183f9951b63df26ab5f02265
DIFF: https://github.com/llvm/llvm-project/commit/8498ba6c2860c838183f9951b63df26ab5f02265.diff

LOG: [clang] Add the check of membership for the issue #58674 and improve the lookup process

This patch includes the commit 01adf96ebc86 and a fix of unhandled declaration
references.

When looking up base classes, Clang first checks whether a base class is a
template and takes the specialized template based 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
declaration, so the instantiated one will be taken.

Differential Revision: https://reviews.llvm.org/D143840

Added: 
    clang/test/CodeGenCXX/decl-ref-inheritance.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/AST/DeclCXX.h
    clang/lib/AST/CXXInheritance.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/test/SemaCXX/decltype.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 640317e32fe70..24ceac59a96a2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -165,6 +165,9 @@ Bug Fixes to C++ Support
 - Fix crash when evaluating consteval constructor of derived class whose base
   has more than one field.
   (`#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.
+  (`#58674 <https://github.com/llvm/llvm-project/issues/58674>`_)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 11276c77490ce..8909acc71c0a3 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1546,8 +1546,11 @@ class CXXRecordDecl : public RecordDecl {
   ///
   /// \param Base the base class we are searching for.
   ///
+  /// \param LookupInDependentTypes whether to look up in dependent types.
+  ///
   /// \returns true if this class is derived from Base, false otherwise.
-  bool isDerivedFrom(const CXXRecordDecl *Base) const;
+  bool isDerivedFrom(const CXXRecordDecl *Base,
+                     bool LookupInDependentTypes = false) const;
 
   /// Determine whether this class is derived from the type \p Base.
   ///
@@ -1561,11 +1564,14 @@ class CXXRecordDecl : public RecordDecl {
   /// \param Paths will contain the paths taken from the current class to the
   /// given \p Base class.
   ///
+  /// \param LookupInDependentTypes whether to 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 LookupInDependentTypes = false) const;
 
   /// Determine whether this class is virtually derived from
   /// the class \p Base.

diff  --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp
index 25de2a20a7f3b..32b17fc64a463 100644
--- a/clang/lib/AST/CXXInheritance.cpp
+++ b/clang/lib/AST/CXXInheritance.cpp
@@ -64,14 +64,16 @@ void CXXBasePaths::swap(CXXBasePaths &Other) {
   std::swap(DetectedVirtual, Other.DetectedVirtual);
 }
 
-bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base) const {
+bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base,
+                                  bool LookupInDependentTypes) const {
   CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
                      /*DetectVirtual=*/false);
-  return isDerivedFrom(Base, Paths);
+  return isDerivedFrom(Base, Paths, LookupInDependentTypes);
 }
 
 bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base,
-                                  CXXBasePaths &Paths) const {
+                                  CXXBasePaths &Paths,
+                                  bool LookupInDependentTypes) const {
   if (getCanonicalDecl() == Base->getCanonicalDecl())
     return false;
 
@@ -83,7 +85,7 @@ bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base,
         return Specifier->getType()->getAsRecordDecl() &&
                FindBaseClass(Specifier, Path, BaseDecl);
       },
-      Paths);
+      Paths, LookupInDependentTypes);
 }
 
 bool CXXRecordDecl::isVirtuallyDerivedFrom(const CXXRecordDecl *Base) const {
@@ -246,17 +248,16 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
     } 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() ||

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index af88d460137ae..a5e8e664ab160 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2698,20 +2698,36 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
   // 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,

diff  --git a/clang/test/CodeGenCXX/decl-ref-inheritance.cpp b/clang/test/CodeGenCXX/decl-ref-inheritance.cpp
new file mode 100644
index 0000000000000..ba58ec3a8714c
--- /dev/null
+++ b/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();
+}

diff  --git a/clang/test/SemaCXX/decltype.cpp b/clang/test/SemaCXX/decltype.cpp
index 32c61bbccc842..96abb60836e40 100644
--- a/clang/test/SemaCXX/decltype.cpp
+++ b/clang/test/SemaCXX/decltype.cpp
@@ -101,6 +101,44 @@ namespace D5789 {
   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 {
 };


        


More information about the cfe-commits mailing list