lime created this revision.
lime added reviewers: aaron.ballman, erichkeane, cor3ntin, clang-language-wg.
lime added a project: clang.
Herald added a subscriber: yaxunl.
Herald added a project: All.
lime requested review of this revision.
Herald added a subscriber: cfe-commits.

D137531 <https://reviews.llvm.org/D137531> had once fixed the issue. However, 
it caused a crash during compiling 
llvm/unittests/IR/PatternMatch.cpp in stage-2. The reason is the predicator 
`isDerivedFrom` does not consider independent types if the derived type is 
dependent.

This patch improves D137531 <https://reviews.llvm.org/D137531> by adding an 
option to make `isDerivedFrom` consider 
independent types.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D142437

Files:
  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

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/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -2693,20 +2693,34 @@
   // 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, 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
@@ -64,14 +64,16 @@
   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;
 
@@ -80,9 +82,10 @@
   const CXXRecordDecl *BaseDecl = Base->getCanonicalDecl();
   return lookupInBases(
       [BaseDecl](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
-        return FindBaseClass(Specifier, Path, BaseDecl);
+        return Specifier->getType()->getAsRecordDecl() &&
+               FindBaseClass(Specifier, Path, BaseDecl);
       },
-      Paths);
+      Paths, LookupIndependent);
 }
 
 bool CXXRecordDecl::isVirtuallyDerivedFrom(const CXXRecordDecl *Base) const {
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -1547,7 +1547,8 @@
   /// \param Base the base class we are searching for.
   ///
   /// \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.
   ///
@@ -1565,7 +1566,8 @@
   ///
   /// \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
@@ -356,6 +356,9 @@
   `Issue 51227 <https://github.com/llvm/llvm-project/issues/51227>`_.
 - Fix the bug of inserting the ``ZeroInitializationFixit`` before the template
   argument list of ``VarTemplateSpecializationDecl``.
+- 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

Reply via email to