[clang] Issue #63106: [сlang] Representation of ellipsis in AST (PR #80976)

Shahid Iqbal via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 26 10:25:20 PST 2024


https://github.com/shahidiqbal13 updated https://github.com/llvm/llvm-project/pull/80976

>From b6bfb18e25c111baf6c95a0a4a1c3d667bb25b6d Mon Sep 17 00:00:00 2001
From: Shahid Iqbal <shahidiqbal13 at gmail.com>
Date: Thu, 16 Nov 2023 11:26:43 -0500
Subject: [PATCH 1/4] TESTING infra

---
 clang/NOTES.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/NOTES.txt b/clang/NOTES.txt
index f06ea8c70cd340..c83dda52a1fc21 100644
--- a/clang/NOTES.txt
+++ b/clang/NOTES.txt
@@ -4,6 +4,8 @@
 
 //===---------------------------------------------------------------------===//
 
+//TESTING git infra//
+
 To time GCC preprocessing speed without output, use:
    "time gcc -MM file"
 This is similar to -Eonly.

>From 79c592853c77fb0a96746d860be63d4605ea87e7 Mon Sep 17 00:00:00 2001
From: Shahid Iqbal <shahidiqbal13 at gmail.com>
Date: Wed, 7 Feb 2024 06:08:10 -0500
Subject: [PATCH 2/4] =?UTF-8?q?Issue=20#63106:=20[=D1=81lang]=20Representa?=
 =?UTF-8?q?tion=20of=20ellipsis=20in=20AST?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 clang/include/clang/AST/DeclBase.h | 11 +++++++++--
 clang/include/clang/Sema/Sema.h    |  2 +-
 clang/lib/AST/TextNodeDumper.cpp   |  3 +++
 clang/lib/Parse/ParseStmt.cpp      | 14 +++++++++++---
 clang/lib/Sema/SemaDeclCXX.cpp     |  7 +++++--
 clang/test/AST/ast-dump-stmt.cpp   |  2 +-
 6 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 5b1038582bc674..67f5c7dd1b7f98 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -301,6 +301,9 @@ class alignas(8) Decl {
   LLVM_PREFERRED_TYPE(bool)
   unsigned Implicit : 1;
 
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned HasCatchEllipsis : 1;
+
   /// Whether this declaration was "used", meaning that a definition is
   /// required.
   LLVM_PREFERRED_TYPE(bool)
@@ -394,7 +397,7 @@ class alignas(8) Decl {
   Decl(Kind DK, DeclContext *DC, SourceLocation L)
       : NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)),
         DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(false), HasAttrs(false),
-        Implicit(false), Used(false), Referenced(false),
+        Implicit(false), HasCatchEllipsis(false), Used(false), Referenced(false),
         TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
         IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
         CacheValidAndLinkage(llvm::to_underlying(Linkage::Invalid)) {
@@ -402,7 +405,7 @@ class alignas(8) Decl {
   }
 
   Decl(Kind DK, EmptyShell Empty)
-      : DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false),
+      : DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false), HasCatchEllipsis(false),
         Used(false), Referenced(false), TopLevelDeclInObjCContainer(false),
         Access(AS_none), FromASTFile(0),
         IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
@@ -597,6 +600,10 @@ class alignas(8) Decl {
   bool isImplicit() const { return Implicit; }
   void setImplicit(bool I = true) { Implicit = I; }
 
+  /// isCatchEllipsisTok - Indicates whether '...' is present in the catch decl
+  bool isCatchEllipsisTok() const { return HasCatchEllipsis; }
+  void setCatchEllipsisTok(bool I = true) { HasCatchEllipsis = I; }
+
   /// Whether *any* (re-)declaration of the entity was used, meaning that
   /// a definition is required.
   ///
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 501dc01200a1c3..ffc6d2926f85f2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5322,7 +5322,7 @@ class Sema final {
                                      SourceLocation IdLoc,
                                      IdentifierInfo *Id);
 
-  Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D);
+  Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D, bool isCatchAll = false);
 
   StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
                                 Decl *ExDecl, Stmt *HandlerBlock);
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index e8274fcd5cfe9c..1da20cdfa36a66 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -272,6 +272,9 @@ void TextNodeDumper::Visit(const Decl *D) {
   if (D->isImplicit())
     OS << " implicit";
 
+  if (D->isCatchEllipsisTok())
+    OS << " catch_all ";
+
   if (D->isUsed())
     OS << " used";
   else if (D->isThisDeclarationReferenced())
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 2531147c23196a..56c1e86afd4811 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2698,9 +2698,17 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
     Declarator ExDecl(DS, Attributes, DeclaratorContext::CXXCatch);
     ParseDeclarator(ExDecl);
     ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
-  } else
-    ConsumeToken();
-
+  }
+  else {
+  ConsumeToken();
+  // explicitly creating a var of type no-type for '...' and marking it as catch_all
+  ParsedAttributes Attributes(AttrFactory);
+  DeclSpec DS(AttrFactory);
+  Declarator ExDecl(DS, Attributes, DeclaratorContext::BlockLiteral);
+  ParseDeclarator(ExDecl);
+  ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl, true);
+  ExceptionDecl->setCatchEllipsisTok();
+  }
   T.consumeClose();
   if (T.getCloseLocation().isInvalid())
     return StmtError();
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 3688192e6cbe5c..1916d3c3d8ebd3 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -16983,7 +16983,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
 
 /// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch
 /// handler.
-Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
+Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D, bool isCatchAll) {
   TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
   bool Invalid = D.isInvalidType();
 
@@ -16994,6 +16994,9 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
                                              D.getIdentifierLoc());
     Invalid = true;
   }
+    if (isCatchAll)
+    TInfo = Context.getTrivialTypeSourceInfo(Context.UnknownAnyTy,
+                                             D.getIdentifierLoc());
 
   IdentifierInfo *II = D.getIdentifier();
   if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(),
@@ -17021,7 +17024,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
 
   VarDecl *ExDecl = BuildExceptionDeclaration(
       S, TInfo, D.getBeginLoc(), D.getIdentifierLoc(), D.getIdentifier());
-  if (Invalid)
+  if (Invalid && !isCatchAll)
     ExDecl->setInvalidDecl();
 
   // Add the exception declaration into this scope.
diff --git a/clang/test/AST/ast-dump-stmt.cpp b/clang/test/AST/ast-dump-stmt.cpp
index 407584e5b82de4..a5a7e9d535c1d7 100644
--- a/clang/test/AST/ast-dump-stmt.cpp
+++ b/clang/test/AST/ast-dump-stmt.cpp
@@ -41,7 +41,7 @@ void TestCatch2() {
   try {
   }
 // CHECK-NEXT:    CXXCatchStmt
-// CHECK-NEXT:      NULL
+// CHECK-NEXT:      VarDecl {{.*}} '<unknown type>'
 // CHECK-NEXT:      CompoundStmt
   catch (...) {
   }

>From 133a67c0da5fd8df7a522876da509dae78a6d96a Mon Sep 17 00:00:00 2001
From: Shahid Iqbal <150978350+shahidiqbal13 at users.noreply.github.com>
Date: Wed, 7 Feb 2024 17:01:33 +0530
Subject: [PATCH 3/4] Update NOTES.txt

---
 clang/NOTES.txt | 2 --
 1 file changed, 2 deletions(-)

diff --git a/clang/NOTES.txt b/clang/NOTES.txt
index c83dda52a1fc21..f06ea8c70cd340 100644
--- a/clang/NOTES.txt
+++ b/clang/NOTES.txt
@@ -4,8 +4,6 @@
 
 //===---------------------------------------------------------------------===//
 
-//TESTING git infra//
-
 To time GCC preprocessing speed without output, use:
    "time gcc -MM file"
 This is similar to -Eonly.

>From 94408546e0f05d2941308485bd678fc06444057b Mon Sep 17 00:00:00 2001
From: Shahid Iqbal <shahidiqbal13 at gmail.com>
Date: Mon, 26 Feb 2024 13:20:18 -0500
Subject: [PATCH 4/4] Updated fix with passed test cases

---
 clang/include/clang/AST/Decl.h        | 14 ++++++++++++++
 clang/include/clang/AST/DeclBase.h    | 11 ++---------
 clang/lib/AST/JSONNodeDumper.cpp      |  4 ++++
 clang/lib/AST/TextNodeDumper.cpp      |  6 +++---
 clang/lib/Parse/ParseStmt.cpp         |  3 +--
 clang/lib/Sema/SemaDeclCXX.cpp        |  5 ++++-
 clang/test/AST/ast-dump-stmt-json.cpp | 28 ++++++++++++++++++++++-----
 7 files changed, 51 insertions(+), 20 deletions(-)

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index cd0878d7082514..d6e22ce6c46729 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1053,6 +1053,10 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
     LLVM_PREFERRED_TYPE(bool)
     unsigned ExceptionVar : 1;
 
+    /// To Check the ellipsis
+    LLVM_PREFERRED_TYPE(bool)
+    unsigned EllipsisVar : 1;
+
     /// Whether this local variable could be allocated in the return
     /// slot of its function, enabling the named return value optimization
     /// (NRVO).
@@ -1474,6 +1478,16 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
     NonParmVarDeclBits.ExceptionVar = EV;
   }
 
+  /// Determine the Ellipsis (...) or not
+  bool isEllipsisVariable() const {
+    return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.EllipsisVar;
+  }
+  void setEllipsisVariable(bool EV) {
+    assert(!isa<ParmVarDecl>(this));
+    NonParmVarDeclBits.EllipsisVar = EV;
+  }
+
+
   /// Determine whether this local variable can be used with the named
   /// return value optimization (NRVO).
   ///
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 67f5c7dd1b7f98..5b1038582bc674 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -301,9 +301,6 @@ class alignas(8) Decl {
   LLVM_PREFERRED_TYPE(bool)
   unsigned Implicit : 1;
 
-  LLVM_PREFERRED_TYPE(bool)
-  unsigned HasCatchEllipsis : 1;
-
   /// Whether this declaration was "used", meaning that a definition is
   /// required.
   LLVM_PREFERRED_TYPE(bool)
@@ -397,7 +394,7 @@ class alignas(8) Decl {
   Decl(Kind DK, DeclContext *DC, SourceLocation L)
       : NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)),
         DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(false), HasAttrs(false),
-        Implicit(false), HasCatchEllipsis(false), Used(false), Referenced(false),
+        Implicit(false), Used(false), Referenced(false),
         TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
         IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
         CacheValidAndLinkage(llvm::to_underlying(Linkage::Invalid)) {
@@ -405,7 +402,7 @@ class alignas(8) Decl {
   }
 
   Decl(Kind DK, EmptyShell Empty)
-      : DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false), HasCatchEllipsis(false),
+      : DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false),
         Used(false), Referenced(false), TopLevelDeclInObjCContainer(false),
         Access(AS_none), FromASTFile(0),
         IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
@@ -600,10 +597,6 @@ class alignas(8) Decl {
   bool isImplicit() const { return Implicit; }
   void setImplicit(bool I = true) { Implicit = I; }
 
-  /// isCatchEllipsisTok - Indicates whether '...' is present in the catch decl
-  bool isCatchEllipsisTok() const { return HasCatchEllipsis; }
-  void setCatchEllipsisTok(bool I = true) { HasCatchEllipsis = I; }
-
   /// Whether *any* (re-)declaration of the entity was used, meaning that
   /// a definition is required.
   ///
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 637d06cee78c85..2a03ad30dd3baf 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -115,6 +115,10 @@ void JSONNodeDumper::Visit(const Decl *D) {
   else if (D->isThisDeclarationReferenced())
     JOS.attribute("isReferenced", true);
 
+  if (const VarDecl *ND = dyn_cast<VarDecl>(D))
+  if (ND->isEllipsisVariable())
+  JOS.attribute("catch_all", true);
+
   if (const auto *ND = dyn_cast<NamedDecl>(D))
     attributeOnlyIfTrue("isHidden", !ND->isUnconditionallyVisible());
 
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 1da20cdfa36a66..056ea399d7e36c 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -271,9 +271,9 @@ void TextNodeDumper::Visit(const Decl *D) {
       OS << " hidden";
   if (D->isImplicit())
     OS << " implicit";
-
-  if (D->isCatchEllipsisTok())
-    OS << " catch_all ";
+  if (const VarDecl *ND = dyn_cast<VarDecl>(D))
+  if (ND->isEllipsisVariable())
+  OS << " catch_all";
 
   if (D->isUsed())
     OS << " used";
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 56c1e86afd4811..83f2d451486fb7 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2700,14 +2700,13 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
     ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
   }
   else {
-  ConsumeToken();
+  CatchLoc = ConsumeToken();
   // explicitly creating a var of type no-type for '...' and marking it as catch_all
   ParsedAttributes Attributes(AttrFactory);
   DeclSpec DS(AttrFactory);
   Declarator ExDecl(DS, Attributes, DeclaratorContext::BlockLiteral);
   ParseDeclarator(ExDecl);
   ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl, true);
-  ExceptionDecl->setCatchEllipsisTok();
   }
   T.consumeClose();
   if (T.getCloseLocation().isInvalid())
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 1916d3c3d8ebd3..93ee1b2e0891fa 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17024,9 +17024,12 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D, bool isCatchAll) {
 
   VarDecl *ExDecl = BuildExceptionDeclaration(
       S, TInfo, D.getBeginLoc(), D.getIdentifierLoc(), D.getIdentifier());
-  if (Invalid && !isCatchAll)
+  if (Invalid)
     ExDecl->setInvalidDecl();
 
+  if (isCatchAll)
+    ExDecl->setEllipsisVariable(true);
+
   // Add the exception declaration into this scope.
   if (II)
     PushOnScopeChains(ExDecl, S);
diff --git a/clang/test/AST/ast-dump-stmt-json.cpp b/clang/test/AST/ast-dump-stmt-json.cpp
index 667a12a0120244..082a6c68f6d805 100644
--- a/clang/test/AST/ast-dump-stmt-json.cpp
+++ b/clang/test/AST/ast-dump-stmt-json.cpp
@@ -755,10 +755,10 @@ void TestDependentGenericSelectionExpr(Ty T) {
 // CHECK-NEXT:        "kind": "CXXCatchStmt",
 // CHECK-NEXT:        "range": {
 // CHECK-NEXT:         "begin": {
-// CHECK-NEXT:          "offset": 352,
+// CHECK-NEXT:          "offset": 359,
 // CHECK-NEXT:          "line": 24,
-// CHECK-NEXT:          "col": 3,
-// CHECK-NEXT:          "tokLen": 5
+// CHECK-NEXT:          "col": 10,
+// CHECK-NEXT:          "tokLen": 3
 // CHECK-NEXT:         },
 // CHECK-NEXT:         "end": {
 // CHECK-NEXT:          "offset": 368,
@@ -769,7 +769,26 @@ void TestDependentGenericSelectionExpr(Ty T) {
 // CHECK-NEXT:        },
 // CHECK-NEXT:        "inner": [
 // CHECK-NEXT:         {
-// CHECK-NEXT:          "id": "0x0"
+// CHECK-NEXT:                      "id": "0x{{.*}}",
+// CHECK-NEXT:                      "kind": "VarDecl",
+// CHECK-NEXT:                      "loc": {
+// CHECK-NEXT:                        "offset": 362,
+// CHECK-NEXT:                        "line": 24,
+// CHECK-NEXT:                        "col": 13,
+// CHECK-NEXT:                        "tokLen": 1
+// CHECK-NEXT:                      },
+// CHECK-NEXT:                      "range": {
+// CHECK-NEXT:                        "begin": {},
+// CHECK-NEXT:                        "end": {
+// CHECK-NEXT:                          "offset": 362,
+// CHECK-NEXT:                          "col": 13,
+// CHECK-NEXT:                          "tokLen": 1
+// CHECK-NEXT:                        }
+// CHECK-NEXT:                      },
+// CHECK-NEXT:                      "catch_all": true,
+// CHECK-NEXT:                      "type": {
+// CHECK-NEXT:                        "qualType": "<unknown type>"
+// CHECK-NEXT:                      }
 // CHECK-NEXT:         },
 // CHECK-NEXT:         {
 // CHECK-NEXT:          "id": "0x{{.*}}",
@@ -777,7 +796,6 @@ void TestDependentGenericSelectionExpr(Ty T) {
 // CHECK-NEXT:          "range": {
 // CHECK-NEXT:           "begin": {
 // CHECK-NEXT:            "offset": 364,
-// CHECK-NEXT:            "line": 24,
 // CHECK-NEXT:            "col": 15,
 // CHECK-NEXT:            "tokLen": 1
 // CHECK-NEXT:           },



More information about the cfe-commits mailing list