[clang] [Clang] Fix name lookup for dependent bases (PR #114978)

via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 5 04:49:26 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Vladislav Belov (vbe-sc)

<details>
<summary>Changes</summary>

Currently the following example is a compilation failure: 
```
template<typename T> struct A {
    typedef int M;
    struct B {
      typedef void M;
      struct C;
    };
};

template<typename T> struct A<T>::B::C : A<T> {
    M m; // void or int ?
};
```

According to the point 13.8.3.2

```
A dependent base class is a base class that is a dependent type and is not the current instantiation.
Note 2 : A base class can be the current instantiation in the case of a nested class naming an enclosing class as a base.
```

The base class `A` is the current instantiation, because `C` is a nested class for an enclosing class `A<T>`, it's is the not-dependent base class and we need to search the names through its scope.

This patch makes this example compile

---
Full diff: https://github.com/llvm/llvm-project/pull/114978.diff


2 Files Affected:

- (modified) clang/lib/AST/CXXInheritance.cpp (+8-5) 
- (modified) clang/test/CXX/drs/cwg5xx.cpp (+6-2) 


``````````diff
diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp
index eb265a872c1259..049532f942d051 100644
--- a/clang/lib/AST/CXXInheritance.cpp
+++ b/clang/lib/AST/CXXInheritance.cpp
@@ -169,6 +169,9 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
     // Find the record of the base class subobjects for this type.
     QualType BaseType =
         Context.getCanonicalType(BaseSpec.getType()).getUnqualifiedType();
+    bool isCurrentInstantiation = false;
+    if (auto *TST = BaseSpec.getType()->getAs<TemplateSpecializationType>())
+      isCurrentInstantiation = TST->isCurrentInstantiation();
 
     // C++ [temp.dep]p3:
     //   In the definition of a class template or a member of a class template,
@@ -176,7 +179,8 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
     //   the base class scope is not examined during unqualified name lookup
     //   either at the point of definition of the class template or member or
     //   during an instantiation of the class tem- plate or member.
-    if (!LookupInDependent && BaseType->isDependentType())
+    if (!LookupInDependent &&
+        (BaseType->isDependentType() && !isCurrentInstantiation))
       continue;
 
     // Determine whether we need to visit this base class at all,
@@ -244,9 +248,8 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
         return FoundPath;
       }
     } else if (VisitBase) {
-      CXXRecordDecl *BaseRecord;
+      CXXRecordDecl *BaseRecord = nullptr;
       if (LookupInDependent) {
-        BaseRecord = nullptr;
         const TemplateSpecializationType *TST =
             BaseSpec.getType()->getAs<TemplateSpecializationType>();
         if (!TST) {
@@ -265,8 +268,8 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
             BaseRecord = nullptr;
         }
       } else {
-        BaseRecord = cast<CXXRecordDecl>(
-            BaseSpec.getType()->castAs<RecordType>()->getDecl());
+        if (auto *RT = BaseSpec.getType()->getAs<RecordType>())
+          BaseRecord = cast<CXXRecordDecl>(RT->getDecl());
       }
       if (BaseRecord &&
           lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) {
diff --git a/clang/test/CXX/drs/cwg5xx.cpp b/clang/test/CXX/drs/cwg5xx.cpp
index ed0c7159dfc889..b283684aef2f7e 100644
--- a/clang/test/CXX/drs/cwg5xx.cpp
+++ b/clang/test/CXX/drs/cwg5xx.cpp
@@ -1178,17 +1178,21 @@ namespace cwg590 { // cwg590: yes
   template<typename T> typename A<T>::B::C A<T>::B::C::f(A<T>::B::C) {}
 }
 
-namespace cwg591 { // cwg591: no
+namespace cwg591 { // cwg591: yes
   template<typename T> struct A {
     typedef int M;
     struct B {
       typedef void M;
       struct C;
+      struct D;
     };
   };
 
   template<typename T> struct A<T>::B::C : A<T> {
-    // FIXME: Should find member of non-dependent base class A<T>.
+    M m;
+  };
+
+  template<typename T> struct A<T>::B::D : A<T*> {
     M m;
     // expected-error at -1 {{field has incomplete type 'M' (aka 'void'}}
   };

``````````

</details>


https://github.com/llvm/llvm-project/pull/114978


More information about the cfe-commits mailing list