Author: Yanzuo Liu
Date: 2026-05-26T22:03:32+08:00
New Revision: ca9884dd065961cb112f4940b3f80339765a0104

URL: 
https://github.com/llvm/llvm-project/commit/ca9884dd065961cb112f4940b3f80339765a0104
DIFF: 
https://github.com/llvm/llvm-project/commit/ca9884dd065961cb112f4940b3f80339765a0104.diff

LOG: [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.

Added: 
    

Modified: 
    clang-tools-extra/clangd/Selection.cpp
    clang-tools-extra/clangd/SemanticHighlighting.cpp
    clang/docs/ReleaseNotes.rst
    clang/include/clang/AST/DeclarationName.h
    clang/lib/Sema/SemaExprCXX.cpp
    clang/test/AST/ast-dump-expr-json.cpp
    clang/test/AST/ast-dump-expr.cpp
    clang/unittests/Tooling/Syntax/BuildTreeTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/Selection.cpp 
b/clang-tools-extra/clangd/Selection.cpp
index 21c9e71d3db65..b79ffc7d5a6e9 100644
--- a/clang-tools-extra/clangd/Selection.cpp
+++ b/clang-tools-extra/clangd/Selection.cpp
@@ -895,19 +895,13 @@ class SelectionVisitor : public 
RecursiveASTVisitor<SelectionVisitor> {
     // 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();

diff  --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp 
b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index 751ee254d3623..d1ed3ea9bc88a 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -789,13 +789,12 @@ class CollectExtraHighlightings
   }
 
   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 @@ class CollectExtraHighlightings
     // `(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(

diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index cef93e25f1e7d..fb70b83d6a7c4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -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
 ^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/include/clang/AST/DeclarationName.h 
b/clang/include/clang/AST/DeclarationName.h
index a7185f5bce04b..56d66e1b5e110 100644
--- a/clang/include/clang/AST/DeclarationName.h
+++ b/clang/include/clang/AST/DeclarationName.h
@@ -830,8 +830,8 @@ struct DeclarationNameInfo {
   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 &&

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index db1cf1fb6eaa0..a60e1b84d3e4b 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -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,

diff  --git a/clang/test/AST/ast-dump-expr-json.cpp 
b/clang/test/AST/ast-dump-expr-json.cpp
index 1415cecd58d36..4eabd5a84248e 100644
--- a/clang/test/AST/ast-dump-expr-json.cpp
+++ b/clang/test/AST/ast-dump-expr-json.cpp
@@ -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:        },

diff  --git a/clang/test/AST/ast-dump-expr.cpp 
b/clang/test/AST/ast-dump-expr.cpp
index 7a686b28d80d1..e19c6d4b12451 100644
--- a/clang/test/AST/ast-dump-expr.cpp
+++ b/clang/test/AST/ast-dump-expr.cpp
@@ -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();

diff  --git a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp 
b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp
index d58e190923a1f..aea1a149ed85b 100644
--- a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp
+++ b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp
@@ -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"}));
 }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to