[clang] Add missing type source info of decltype specifier in destructor call to AST (#197680)

The type source info will be stored in `MemberExpr::MemberDNLoc`.

This patch fixes the underlying issue of #195788.
This commit is contained in:
Yanzuo Liu 2026-05-26 22:03:32 +08:00 committed by GitHub
parent cb96a3edf7
commit ca9884dd06
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 35 additions and 39 deletions

View file

@ -895,19 +895,13 @@ private:
// rather than the TypeLoc nested inside it.
// We still traverse the TypeLoc, because it may contain other targeted
// things like the T in ~Foo<T>().
// FIXME: Investigate if getNamedTypeInfo() can still return null for
// invalid cases, and drop these checks when it never returns null.
if (const auto *CDD = N.get<CXXDestructorDecl>()) {
if (auto *TypeInfo = CDD->getNameInfo().getNamedTypeInfo())
return TypeInfo->getTypeLoc().getBeginLoc();
}
if (const auto *CDD = N.get<CXXDestructorDecl>())
return CDD->getNameInfo().getNamedTypeInfo()->getTypeLoc().getBeginLoc();
if (const auto *ME = N.get<MemberExpr>()) {
auto NameInfo = ME->getMemberNameInfo();
if (NameInfo.getName().getNameKind() ==
DeclarationName::CXXDestructorName) {
if (auto *TypeInfo = NameInfo.getNamedTypeInfo())
return TypeInfo->getTypeLoc().getBeginLoc();
}
DeclarationName::CXXDestructorName)
return NameInfo.getNamedTypeInfo()->getTypeLoc().getBeginLoc();
}
return SourceRange();

View file

@ -789,13 +789,12 @@ public:
}
bool VisitCXXDestructorDecl(CXXDestructorDecl *D) {
if (auto *TI = D->getNameInfo().getNamedTypeInfo()) {
SourceLocation Loc = TI->getTypeLoc().getBeginLoc();
H.addExtraModifier(Loc, HighlightingModifier::ConstructorOrDestructor);
H.addExtraModifier(Loc, HighlightingModifier::Declaration);
if (D->isThisDeclarationADefinition())
H.addExtraModifier(Loc, HighlightingModifier::Definition);
}
SourceLocation Loc =
D->getNameInfo().getNamedTypeInfo()->getTypeLoc().getBeginLoc();
H.addExtraModifier(Loc, HighlightingModifier::ConstructorOrDestructor);
H.addExtraModifier(Loc, HighlightingModifier::Declaration);
if (D->isThisDeclarationADefinition())
H.addExtraModifier(Loc, HighlightingModifier::Definition);
return true;
}
@ -804,12 +803,12 @@ public:
// `(foo.*pointer_to_member_fun)(arg);`
if (auto *D = CE->getMethodDecl()) {
if (isa<CXXDestructorDecl>(D)) {
if (auto *ME = dyn_cast<MemberExpr>(CE->getCallee())) {
if (auto *TI = ME->getMemberNameInfo().getNamedTypeInfo()) {
H.addExtraModifier(TI->getTypeLoc().getBeginLoc(),
HighlightingModifier::ConstructorOrDestructor);
}
}
if (auto *ME = dyn_cast<MemberExpr>(CE->getCallee()))
H.addExtraModifier(ME->getMemberNameInfo()
.getNamedTypeInfo()
->getTypeLoc()
.getBeginLoc(),
HighlightingModifier::ConstructorOrDestructor);
} else if (D->isOverloadedOperator()) {
if (auto *ME = dyn_cast<MemberExpr>(CE->getCallee()))
H.addToken(

View file

@ -687,6 +687,7 @@ Bug Fixes to AST Handling
- Fixed a crash when parsing Doxygen ``@param`` commands attached to invalid declarations or non-function entities. (#GH182737)
- Fixed the SourceLocation and SourceRange of reversed rewritten CXXOperatorCallExpr. (#GH192467)
- Fixed a assertion when ``__block`` is used on global variables in C mode. (#GH183974)
- Added missing AST nodes representing the ``decltype`` specifiers in destructor call to AST.
Miscellaneous Bug Fixes
^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -830,8 +830,8 @@ public:
const DeclarationNameLoc &getInfo() const { return LocInfo; }
void setInfo(const DeclarationNameLoc &Info) { LocInfo = Info; }
/// getNamedTypeInfo - Returns the source type info associated to
/// the name. Assumes it is a constructor, destructor or conversion.
/// @return The type source info associated to the name if it is a
/// constructor, destructor or conversion function, `nullptr` otherwise.
TypeSourceInfo *getNamedTypeInfo() const {
if (Name.getNameKind() != DeclarationName::CXXConstructorName &&
Name.getNameKind() != DeclarationName::CXXDestructorName &&

View file

@ -479,7 +479,11 @@ ParsedType Sema::getDestructorTypeForDecltype(const DeclSpec &DS,
return nullptr;
}
return ParsedType::make(T);
TypeLocBuilder TLB;
DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
}
bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,

View file

@ -3208,8 +3208,8 @@ void TestNonADLCall3() {
// CHECK-NEXT: "tokLen": 1
// CHECK-NEXT: },
// CHECK-NEXT: "end": {
// CHECK-NEXT: "offset": 1693,
// CHECK-NEXT: "col": 5,
// CHECK-NEXT: "offset": 1704,
// CHECK-NEXT: "col": 16,
// CHECK-NEXT: "tokLen": 1
// CHECK-NEXT: }
// CHECK-NEXT: },

View file

@ -216,7 +216,7 @@ void PostfixExpressions(S a, S *p, U<int> *r) {
// the construct above.
a.~decltype(a)();
// CHECK: CXXMemberCallExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:18> 'void'
// CHECK-NEXT: MemberExpr 0x{{[^ ]*}} <col:3, col:5> '<bound member function type>' .~S 0x{{[^ ]*}}
// CHECK-NEXT: MemberExpr 0x{{[^ ]*}} <col:3, col:16> '<bound member function type>' .~S 0x{{[^ ]*}}
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:3> 'S' lvalue ParmVar 0x{{[^ ]*}} 'a' 'S'
p->::S::~S();

View file

@ -671,10 +671,6 @@ TEST_P(BuildSyntaxTreeTest, UnqualifiedId_DecltypeDestructor) {
R"cpp(
struct X { };
void test(X x) {
// FIXME: Make `decltype(x)` a child of `MemberExpression`. It is currently
// not because `Expr::getSourceRange()` returns the range of `x.~` for the
// `MemberExpr` instead of the expected `x.~decltype(x)`, this is a bug in
// clang.
[[x.~decltype(x)()]];
}
)cpp",
@ -687,12 +683,14 @@ CallExpression Expression
| |-'.' AccessToken
| `-IdExpression Member
| `-UnqualifiedId UnqualifiedId
| `-'~'
|-'decltype'
|-'('
|-'x'
|-')'
|-'('
| |-'~'
| |-'decltype'
| |-'('
| |-IdExpression
| | `-UnqualifiedId UnqualifiedId
| | `-'x'
| `-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}