Skip to content

Commit e1cb316

Browse files
authored
Reapply "[clang] Fix name lookup for dependent bases" (#118003)
Unlike the previous version (#114978), this patch also removes an unnecessary assert that causes Clang to crash when compiling such tests. (clang/lib/AST/DeclCXX.cpp) https://lab.llvm.org/buildbot/#/builders/52/builds/4021 ```c++ template <class T> class X { public: X() = default; virtual ~X() = default; virtual int foo(int x, int y, T &entry) = 0; void bar() { struct Y : public X<T> { Y() : X() {} int foo(int, int, T &) override { return 42; } }; } }; ``` the assertions: ```c++ llvm-project/clang/lib/AST/DeclCXX.cpp:2508: void clang::CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *): Assertion `!MD->getParent()->isDependentContext() && "Can't add an overridden method to a class template!"' failed. ``` I believe that this assert is unnecessary and contradicts the logic of this patch. After its removal, Clang was successfully built using itself, and all tests passed.
1 parent 2a0ee09 commit e1cb316

File tree

5 files changed

+62
-11
lines changed

5 files changed

+62
-11
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ Resolutions to C++ Defect Reports
310310
by default.
311311
(`CWG2521: User-defined literals and reserved identifiers <https://cplusplus.github.io/CWG/issues/2521.html>`_).
312312

313+
- Fix name lookup for a dependent base class that is the current instantiation.
314+
(`CWG591: When a dependent base class is the current instantiation <https://cplusplus.github.io/CWG/issues/591.html>`_).
315+
313316
C Language Changes
314317
------------------
315318

clang/lib/AST/CXXInheritance.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches) const {
134134
return false;
135135

136136
CXXRecordDecl *Base =
137-
cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition());
137+
cast_if_present<CXXRecordDecl>(Ty->getDecl()->getDefinition());
138138
if (!Base ||
139139
(Base->isDependentContext() &&
140140
!Base->isCurrentInstantiation(Record))) {
@@ -169,13 +169,21 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
169169
QualType BaseType =
170170
Context.getCanonicalType(BaseSpec.getType()).getUnqualifiedType();
171171

172+
bool isCurrentInstantiation = isa<InjectedClassNameType>(BaseType);
173+
if (!isCurrentInstantiation) {
174+
if (auto *BaseRecord = cast_if_present<CXXRecordDecl>(
175+
BaseSpec.getType()->getAsRecordDecl()))
176+
isCurrentInstantiation = BaseRecord->isDependentContext() &&
177+
BaseRecord->isCurrentInstantiation(Record);
178+
}
172179
// C++ [temp.dep]p3:
173180
// In the definition of a class template or a member of a class template,
174181
// if a base class of the class template depends on a template-parameter,
175182
// the base class scope is not examined during unqualified name lookup
176183
// either at the point of definition of the class template or member or
177184
// during an instantiation of the class tem- plate or member.
178-
if (!LookupInDependent && BaseType->isDependentType())
185+
if (!LookupInDependent &&
186+
(BaseType->isDependentType() && !isCurrentInstantiation))
179187
continue;
180188

181189
// Determine whether we need to visit this base class at all,
@@ -243,9 +251,8 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
243251
return FoundPath;
244252
}
245253
} else if (VisitBase) {
246-
CXXRecordDecl *BaseRecord;
254+
CXXRecordDecl *BaseRecord = nullptr;
247255
if (LookupInDependent) {
248-
BaseRecord = nullptr;
249256
const TemplateSpecializationType *TST =
250257
BaseSpec.getType()->getAs<TemplateSpecializationType>();
251258
if (!TST) {
@@ -264,8 +271,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
264271
BaseRecord = nullptr;
265272
}
266273
} else {
267-
BaseRecord = cast<CXXRecordDecl>(
268-
BaseSpec.getType()->castAs<RecordType>()->getDecl());
274+
BaseRecord = cast<CXXRecordDecl>(BaseSpec.getType()->getAsRecordDecl());
269275
}
270276
if (BaseRecord &&
271277
lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) {

clang/lib/AST/DeclCXX.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2602,8 +2602,6 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const {
26022602

26032603
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
26042604
assert(MD->isCanonicalDecl() && "Method is not canonical!");
2605-
assert(!MD->getParent()->isDependentContext() &&
2606-
"Can't add an overridden method to a class template!");
26072605
assert(MD->isVirtual() && "Method is not virtual!");
26082606

26092607
getASTContext().addOverriddenMethod(this, MD);

clang/test/CXX/drs/cwg5xx.cpp

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,17 +1178,61 @@ namespace cwg590 { // cwg590: yes
11781178
template<typename T> typename A<T>::B::C A<T>::B::C::f(A<T>::B::C) {}
11791179
}
11801180

1181-
namespace cwg591 { // cwg591: no
1181+
namespace cwg591 { // cwg591: 20
11821182
template<typename T> struct A {
11831183
typedef int M;
11841184
struct B {
11851185
typedef void M;
11861186
struct C;
1187+
struct D;
1188+
};
1189+
};
1190+
1191+
template<typename T> struct G {
1192+
struct B {
1193+
typedef int M;
1194+
struct C {
1195+
typedef void M;
1196+
struct D;
1197+
};
1198+
};
1199+
};
1200+
1201+
template<typename T> struct H {
1202+
template<typename U> struct B {
1203+
typedef int M;
1204+
template<typename F> struct C {
1205+
typedef void M;
1206+
struct D;
1207+
struct P;
1208+
};
11871209
};
11881210
};
11891211

11901212
template<typename T> struct A<T>::B::C : A<T> {
1191-
// FIXME: Should find member of non-dependent base class A<T>.
1213+
M m;
1214+
};
1215+
1216+
template<typename T> struct G<T>::B::C::D : B {
1217+
M m;
1218+
};
1219+
1220+
template<typename T>
1221+
template<typename U>
1222+
template<typename F>
1223+
struct H<T>::B<U>::C<F>::D : B<U> {
1224+
M m;
1225+
};
1226+
1227+
template<typename T> struct A<T>::B::D : A<T*> {
1228+
M m;
1229+
// expected-error@-1 {{field has incomplete type 'M' (aka 'void'}}
1230+
};
1231+
1232+
template<typename T>
1233+
template<typename U>
1234+
template<typename F>
1235+
struct H<T>::B<U>::C<F>::P : B<F> {
11921236
M m;
11931237
// expected-error@-1 {{field has incomplete type 'M' (aka 'void'}}
11941238
};

clang/www/cxx_dr_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3599,7 +3599,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
35993599
<td><a href="https://cplusplus.github.io/CWG/issues/591.html">591</a></td>
36003600
<td>CD4</td>
36013601
<td>When a dependent base class is the current instantiation</td>
3602-
<td class="none" align="center">No</td>
3602+
<td class="unreleased" align="center">Clang 20</td>
36033603
</tr>
36043604
<tr id="592">
36053605
<td><a href="https://cplusplus.github.io/CWG/issues/592.html">592</a></td>

0 commit comments

Comments
 (0)