[clang] [Clang]fix dependent qualified base member lookup crash (PR #199403)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 25 14:56:01 PDT 2026
https://github.com/Serosh-commits updated https://github.com/llvm/llvm-project/pull/199403
>From 5e00093dc1bb444e51449a093020f747529975b3 Mon Sep 17 00:00:00 2001
From: Serosh-commits <janmejayapanda400 at gmail.com>
Date: Sun, 24 May 2026 07:32:40 +0530
Subject: [PATCH 1/3] Fix dependent qualified base member lookup crash
---
clang/lib/AST/CXXInheritance.cpp | 3 +++
clang/test/SemaTemplate/current-instantiation.cpp | 15 +++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp
index 29f5916284ebb..23a9f112f9bcd 100644
--- a/clang/lib/AST/CXXInheritance.cpp
+++ b/clang/lib/AST/CXXInheritance.cpp
@@ -127,6 +127,9 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches) const {
const CXXRecordDecl *Record = this;
while (true) {
+ if (!Record->hasDefinition())
+ return false;
+
for (const auto &I : Record->bases()) {
const auto *Base = I.getType()->getAsCXXRecordDecl();
if (!Base || !(Base->isBeingDefined() || Base->isCompleteDefinition()))
diff --git a/clang/test/SemaTemplate/current-instantiation.cpp b/clang/test/SemaTemplate/current-instantiation.cpp
index 9214bbeb973d6..fdc98638b3923 100644
--- a/clang/test/SemaTemplate/current-instantiation.cpp
+++ b/clang/test/SemaTemplate/current-instantiation.cpp
@@ -247,3 +247,18 @@ namespace RebuildDependentScopeDeclRefExpr {
// FIXME: We should issue a typo-correction here.
template<typename T> N<X<T>::think> X<T>::foo() {} // expected-error {{no member named 'think' in 'RebuildDependentScopeDeclRefExpr::X<T>'}}
}
+
+namespace GH195133 {
+ template <typename T> struct A {
+ void f();
+ };
+
+ template <typename T> struct X {
+ struct S : A<int> {};
+ static void f(S *p) {
+ p->template A<int>::f();
+ }
+ };
+
+ void g() { X<int>::f(nullptr); }
+}
>From 9d269fad178f3cbd2844df5b655e53432865c2f2 Mon Sep 17 00:00:00 2001
From: Serosh-commits <janmejayapanda400 at gmail.com>
Date: Mon, 25 May 2026 10:31:48 +0530
Subject: [PATCH 2/3] address feedback
---
clang/include/clang/AST/DeclCXX.h | 39 ++++++++++++++++-----------
clang/lib/AST/CXXInheritance.cpp | 3 ---
clang/lib/AST/DeclCXX.cpp | 18 ++++++++-----
clang/lib/AST/ODRDiagsEmitter.cpp | 23 ++++++++++------
clang/lib/Sema/SemaExprMember.cpp | 3 ++-
clang/lib/Serialization/ASTWriter.cpp | 4 +--
6 files changed, 53 insertions(+), 37 deletions(-)
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index cc4b4ff9db273..50caba9b0129f 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -352,29 +352,30 @@ class CXXRecordDecl : public RecordDecl {
DefinitionData(CXXRecordDecl *D);
/// Retrieve the set of direct base classes.
- CXXBaseSpecifier *getBases() const {
+ CXXBaseSpecifier *getBases(const ASTContext &Context) const {
if (!Bases.isOffset())
return Bases.get(nullptr);
- return getBasesSlowCase();
+ return getBasesSlowCase(Context);
}
/// Retrieve the set of virtual base classes.
- CXXBaseSpecifier *getVBases() const {
+ CXXBaseSpecifier *getVBases(const ASTContext &Context) const {
if (!VBases.isOffset())
return VBases.get(nullptr);
- return getVBasesSlowCase();
+ return getVBasesSlowCase(Context);
+ }
+ ArrayRef<CXXBaseSpecifier> bases(const ASTContext &Context) const {
+ return {getBases(Context), NumBases};
}
- ArrayRef<CXXBaseSpecifier> bases() const { return {getBases(), NumBases}; }
-
- ArrayRef<CXXBaseSpecifier> vbases() const {
- return {getVBases(), NumVBases};
+ ArrayRef<CXXBaseSpecifier> vbases(const ASTContext &Context) const {
+ return {getVBases(Context), NumVBases};
}
- private:
- CXXBaseSpecifier *getBasesSlowCase() const;
- CXXBaseSpecifier *getVBasesSlowCase() const;
- };
+ private:
+ CXXBaseSpecifier *getBasesSlowCase(const ASTContext &Context) const;
+ CXXBaseSpecifier *getVBasesSlowCase(const ASTContext &Context) const;
+};
struct DefinitionData *DefinitionData;
@@ -612,8 +613,10 @@ class CXXRecordDecl : public RecordDecl {
return base_class_const_range(bases_begin(), bases_end());
}
- base_class_iterator bases_begin() { return data().getBases(); }
- base_class_const_iterator bases_begin() const { return data().getBases(); }
+ base_class_iterator bases_begin() { return data().getBases(getASTContext()); }
+ base_class_const_iterator bases_begin() const {
+ return data().getBases(getASTContext());
+ }
base_class_iterator bases_end() { return bases_begin() + data().NumBases; }
base_class_const_iterator bases_end() const {
return bases_begin() + data().NumBases;
@@ -629,8 +632,12 @@ class CXXRecordDecl : public RecordDecl {
return base_class_const_range(vbases_begin(), vbases_end());
}
- base_class_iterator vbases_begin() { return data().getVBases(); }
- base_class_const_iterator vbases_begin() const { return data().getVBases(); }
+ base_class_iterator vbases_begin() {
+ return data().getVBases(getASTContext());
+ }
+ base_class_const_iterator vbases_begin() const {
+ return data().getVBases(getASTContext());
+ }
base_class_iterator vbases_end() { return vbases_begin() + data().NumVBases; }
base_class_const_iterator vbases_end() const {
return vbases_begin() + data().NumVBases;
diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp
index 23a9f112f9bcd..29f5916284ebb 100644
--- a/clang/lib/AST/CXXInheritance.cpp
+++ b/clang/lib/AST/CXXInheritance.cpp
@@ -127,9 +127,6 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches) const {
const CXXRecordDecl *Record = this;
while (true) {
- if (!Record->hasDefinition())
- return false;
-
for (const auto &I : Record->bases()) {
const auto *Base = I.getType()->getAsCXXRecordDecl();
if (!Base || !(Base->isBeingDefined() || Base->isCompleteDefinition()))
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 1a4753fc29b88..1b11824f04abf 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -113,12 +113,16 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
IsLambda(false), IsParsingBaseSpecifiers(false),
ComputedVisibleConversions(false), HasODRHash(false), Definition(D) {}
-CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
- return Bases.get(Definition->getASTContext().getExternalSource());
+CXXBaseSpecifier *
+CXXRecordDecl::DefinitionData::getBasesSlowCase(
+ const ASTContext &Context) const {
+ return Bases.get(Context.getExternalSource());
}
-CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getVBasesSlowCase() const {
- return VBases.get(Definition->getASTContext().getExternalSource());
+CXXBaseSpecifier *
+CXXRecordDecl::DefinitionData::getVBasesSlowCase(
+ const ASTContext &Context) const {
+ return VBases.get(Context.getExternalSource());
}
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C,
@@ -186,7 +190,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
ASTContext &C = getASTContext();
if (!data().Bases.isOffset() && data().NumBases > 0)
- C.Deallocate(data().getBases());
+ C.Deallocate(data().getBases(C));
if (NumBases) {
if (!C.getLangOpts().CPlusPlus17) {
@@ -209,7 +213,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().Bases = new(C) CXXBaseSpecifier [NumBases];
data().NumBases = NumBases;
for (unsigned i = 0; i < NumBases; ++i) {
- data().getBases()[i] = *Bases[i];
+ data().getBases(C)[i] = *Bases[i];
// Keep track of inherited vbases for this base class.
const CXXBaseSpecifier *Base = Bases[i];
QualType BaseType = Base->getType();
@@ -484,7 +488,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
QualType Type = VBases[I]->getType();
if (!Type->isDependentType())
addedClassSubobject(Type->getAsCXXRecordDecl());
- data().getVBases()[I] = *VBases[I];
+ data().getVBases(C)[I] = *VBases[I];
}
data().IsParsingBaseSpecifiers = false;
diff --git a/clang/lib/AST/ODRDiagsEmitter.cpp b/clang/lib/AST/ODRDiagsEmitter.cpp
index 74f3881ed3c96..e8f25c110bc4e 100644
--- a/clang/lib/AST/ODRDiagsEmitter.cpp
+++ b/clang/lib/AST/ODRDiagsEmitter.cpp
@@ -739,11 +739,12 @@ bool ODRDiagsEmitter::diagnoseMismatch(
return Diag(Loc, diag::note_module_odr_violation_definition_data)
<< SecondModule << Range << DiffType;
};
- auto GetSourceRange = [](const struct CXXRecordDecl::DefinitionData *DD) {
+ auto GetSourceRange = [](const CXXRecordDecl *Record,
+ const struct CXXRecordDecl::DefinitionData *DD) {
unsigned NumBases = DD->NumBases;
if (NumBases == 0)
return SourceRange();
- ArrayRef<CXXBaseSpecifier> bases = DD->bases();
+ ArrayRef<CXXBaseSpecifier> bases = DD->bases(Record->getASTContext());
return SourceRange(bases[0].getBeginLoc(),
bases[NumBases - 1].getEndLoc());
};
@@ -753,27 +754,33 @@ bool ODRDiagsEmitter::diagnoseMismatch(
unsigned SecondNumBases = SecondDD->NumBases;
unsigned SecondNumVBases = SecondDD->NumVBases;
if (FirstNumBases != SecondNumBases) {
- DiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+ DiagBaseError(FirstRecord->getLocation(),
+ GetSourceRange(FirstRecord, FirstDD),
NumBases)
<< FirstNumBases;
- DiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+ DiagBaseNote(SecondRecord->getLocation(),
+ GetSourceRange(SecondRecord, SecondDD),
NumBases)
<< SecondNumBases;
return true;
}
if (FirstNumVBases != SecondNumVBases) {
- DiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+ DiagBaseError(FirstRecord->getLocation(),
+ GetSourceRange(FirstRecord, FirstDD),
NumVBases)
<< FirstNumVBases;
- DiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+ DiagBaseNote(SecondRecord->getLocation(),
+ GetSourceRange(SecondRecord, SecondDD),
NumVBases)
<< SecondNumVBases;
return true;
}
- ArrayRef<CXXBaseSpecifier> FirstBases = FirstDD->bases();
- ArrayRef<CXXBaseSpecifier> SecondBases = SecondDD->bases();
+ ArrayRef<CXXBaseSpecifier> FirstBases =
+ FirstDD->bases(FirstRecord->getASTContext());
+ ArrayRef<CXXBaseSpecifier> SecondBases =
+ SecondDD->bases(SecondRecord->getASTContext());
for (unsigned I = 0; I < FirstNumBases; ++I) {
const CXXBaseSpecifier FirstBase = FirstBases[I];
const CXXBaseSpecifier SecondBase = SecondBases[I];
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 851d58c49f7b9..b95f01454b7a2 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -630,7 +630,6 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
assert(BaseType->isDependentType());
return false;
}
-
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
// If this is an implicit member reference and we find a
// non-instance member, it's not an error.
@@ -643,6 +642,8 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
continue;
CXXRecordDecl *MemberRecord = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+ if (!BaseRecord->hasDefinition() || !MemberRecord->hasDefinition())
+ return false;
if (BaseRecord->getCanonicalDecl() == MemberRecord ||
!BaseRecord->isProvablyNotDerivedFrom(MemberRecord))
return false;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 074b0fccdb65d..64a584d0a3173 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -7481,12 +7481,12 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
if (!Data.IsLambda) {
Record->push_back(Data.NumBases);
if (Data.NumBases > 0)
- AddCXXBaseSpecifiers(Data.bases());
+ AddCXXBaseSpecifiers(Data.bases(D->getASTContext()));
// FIXME: Make VBases lazily computed when needed to avoid storing them.
Record->push_back(Data.NumVBases);
if (Data.NumVBases > 0)
- AddCXXBaseSpecifiers(Data.vbases());
+ AddCXXBaseSpecifiers(Data.vbases(D->getASTContext()));
AddDeclRef(D->getFirstFriend());
} else {
>From 2a318c99f4eea04641ec878f873970cad4f9c622 Mon Sep 17 00:00:00 2001
From: Serosh-commits <janmejayapanda400 at gmail.com>
Date: Mon, 25 May 2026 10:46:54 +0530
Subject: [PATCH 3/3] format fix
---
clang/include/clang/AST/DeclCXX.h | 6 +++---
clang/lib/AST/DeclCXX.cpp | 6 ++----
clang/lib/AST/ODRDiagsEmitter.cpp | 12 ++++--------
3 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 50caba9b0129f..d3c3bee606dba 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -363,7 +363,7 @@ class CXXRecordDecl : public RecordDecl {
if (!VBases.isOffset())
return VBases.get(nullptr);
return getVBasesSlowCase(Context);
- }
+ }
ArrayRef<CXXBaseSpecifier> bases(const ASTContext &Context) const {
return {getBases(Context), NumBases};
}
@@ -372,10 +372,10 @@ class CXXRecordDecl : public RecordDecl {
return {getVBases(Context), NumVBases};
}
- private:
+ private:
CXXBaseSpecifier *getBasesSlowCase(const ASTContext &Context) const;
CXXBaseSpecifier *getVBasesSlowCase(const ASTContext &Context) const;
-};
+ };
struct DefinitionData *DefinitionData;
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 1b11824f04abf..70dc446725d17 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -113,14 +113,12 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
IsLambda(false), IsParsingBaseSpecifiers(false),
ComputedVisibleConversions(false), HasODRHash(false), Definition(D) {}
-CXXBaseSpecifier *
-CXXRecordDecl::DefinitionData::getBasesSlowCase(
+CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase(
const ASTContext &Context) const {
return Bases.get(Context.getExternalSource());
}
-CXXBaseSpecifier *
-CXXRecordDecl::DefinitionData::getVBasesSlowCase(
+CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getVBasesSlowCase(
const ASTContext &Context) const {
return VBases.get(Context.getExternalSource());
}
diff --git a/clang/lib/AST/ODRDiagsEmitter.cpp b/clang/lib/AST/ODRDiagsEmitter.cpp
index e8f25c110bc4e..37222c0347e9b 100644
--- a/clang/lib/AST/ODRDiagsEmitter.cpp
+++ b/clang/lib/AST/ODRDiagsEmitter.cpp
@@ -755,24 +755,20 @@ bool ODRDiagsEmitter::diagnoseMismatch(
unsigned SecondNumVBases = SecondDD->NumVBases;
if (FirstNumBases != SecondNumBases) {
DiagBaseError(FirstRecord->getLocation(),
- GetSourceRange(FirstRecord, FirstDD),
- NumBases)
+ GetSourceRange(FirstRecord, FirstDD), NumBases)
<< FirstNumBases;
DiagBaseNote(SecondRecord->getLocation(),
- GetSourceRange(SecondRecord, SecondDD),
- NumBases)
+ GetSourceRange(SecondRecord, SecondDD), NumBases)
<< SecondNumBases;
return true;
}
if (FirstNumVBases != SecondNumVBases) {
DiagBaseError(FirstRecord->getLocation(),
- GetSourceRange(FirstRecord, FirstDD),
- NumVBases)
+ GetSourceRange(FirstRecord, FirstDD), NumVBases)
<< FirstNumVBases;
DiagBaseNote(SecondRecord->getLocation(),
- GetSourceRange(SecondRecord, SecondDD),
- NumVBases)
+ GetSourceRange(SecondRecord, SecondDD), NumVBases)
<< SecondNumVBases;
return true;
}
More information about the cfe-commits
mailing list