[clang] [Clang] [Sema] Don't crash on unexpanded pack in invalid block literal (PR #110762)

via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 2 18:46:46 PDT 2024


https://github.com/Sirraide updated https://github.com/llvm/llvm-project/pull/110762

>From a471d32c94bfcbd10291053bb6ce0541ea2e626c Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Wed, 2 Oct 2024 00:59:37 +0200
Subject: [PATCH 1/4] [Clang] [Sema] Don't crash on unexpanded pack in invalid
 block literal

---
 clang/docs/ReleaseNotes.rst                  |  2 +
 clang/include/clang/Sema/ScopeInfo.h         | 10 ++++
 clang/lib/Sema/Sema.cpp                      |  8 +++-
 clang/lib/Sema/SemaExpr.cpp                  | 11 +++++
 clang/test/SemaCXX/block-unexpanded-pack.cpp | 48 ++++++++++++++++++++
 5 files changed, 77 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/SemaCXX/block-unexpanded-pack.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 34d2b584274a5f..ed4a7affcf6919 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -457,6 +457,8 @@ Bug Fixes to C++ Support
   containing outer unexpanded parameters were not correctly expanded. (#GH101754)
 - Fixed a bug in constraint expression comparison where the ``sizeof...`` expression was not handled properly
   in certain friend declarations. (#GH93099)
+- Clang no longer crashes when a lambda contains an invalid block declaration that contains an unexpanded
+  parameter pack. (#GH109148)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index 700e361ef83f13..a943f2edc51fba 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -793,6 +793,16 @@ class BlockScopeInfo final : public CapturingScopeInfo {
   /// Its return type may be BuiltinType::Dependent.
   QualType FunctionType;
 
+  /// We sometimes diagnose unexpanded parameter packs in block literals,
+  /// but an error while the block is parsed causes it to be discarded, in
+  /// which case we need to reset the enclosing lambda's
+  /// ContainsUnexpandedParameterPackFlag.
+  ///
+  /// Note: This issue does not exist with lambdas because they push a new
+  /// LambdaScopeInfo, so if the expression is discarded, the 'enclosing
+  /// lambda' is discarded along with it.
+  bool EnclosingLambdaContainsUnexpandedParameterPack = false;
+
   BlockScopeInfo(DiagnosticsEngine &Diag, Scope *BlockScope, BlockDecl *Block)
       : CapturingScopeInfo(Diag, ImpCap_Block), TheDecl(Block),
         TheScope(BlockScope) {
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 4be7dfbc293927..1e72910da27d5e 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -2187,9 +2187,13 @@ void Sema::PushFunctionScope() {
 }
 
 void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
-  FunctionScopes.push_back(new BlockScopeInfo(getDiagnostics(),
-                                              BlockScope, Block));
+  auto *BSI = new BlockScopeInfo(getDiagnostics(), BlockScope, Block);
+  FunctionScopes.push_back(BSI);
   CapturingFunctionScopes++;
+
+  LambdaScopeInfo *Enclosing = getEnclosingLambda();
+  BSI->EnclosingLambdaContainsUnexpandedParameterPack =
+      Enclosing && Enclosing->ContainsUnexpandedParameterPack;
 }
 
 LambdaScopeInfo *Sema::PushLambdaScope() {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 2db9d1fc69ed1e..29745b1f3edff1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -16187,6 +16187,15 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
 }
 
 void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
+  // If the enclosing lambda did not contain any unexpanded parameter
+  // packs before this block, then reset the unexpanded parameter pack
+  // flag, otherwise, we might end up crashing trying to find a pack
+  // that we are about to discard along with the rest of the block.
+  if (!getCurBlock()->EnclosingLambdaContainsUnexpandedParameterPack) {
+    LambdaScopeInfo *L = getEnclosingLambda();
+    if (L) L->ContainsUnexpandedParameterPack = false;
+  }
+
   // Leave the expression-evaluation context.
   DiscardCleanupsInEvaluationContext();
   PopExpressionEvaluationContext();
@@ -16379,6 +16388,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
   if (getCurFunction())
     getCurFunction()->addBlock(BD);
 
+  // This can happen if the block's return type is deduced, but
+  // the return expression is invalid.
   if (BD->isInvalidDecl())
     return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(),
                               {Result}, Result->getType());
diff --git a/clang/test/SemaCXX/block-unexpanded-pack.cpp b/clang/test/SemaCXX/block-unexpanded-pack.cpp
new file mode 100644
index 00000000000000..c1435b8e314a81
--- /dev/null
+++ b/clang/test/SemaCXX/block-unexpanded-pack.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -fsyntax-only -verify %s -frecovery-ast -frecovery-ast-type
+
+// This checks that when a block is discarded, the enclosing lambda’s
+// unexpanded parameter pack flag is reset to what it was before the
+// block is parsed so we don't crash when trying to diagnose unexpanded
+// parameter packs in the lambda.
+
+template <typename ...Ts>
+void gh109148() {
+  (^Ts); // expected-error {{expected expression}} expected-error {{unexpanded parameter pack 'Ts'}}
+
+  [] {
+    (^Ts); // expected-error {{expected expression}}
+    ^Ts;   // expected-error {{expected expression}}
+    ^(Ts); // expected-error {{expected expression}}
+    ^ Ts); // expected-error {{expected expression}}
+  };
+
+  ([] {
+    (^Ts); // expected-error {{expected expression}}
+    ^Ts;   // expected-error {{expected expression}}
+    ^(Ts); // expected-error {{expected expression}}
+    ^ Ts); // expected-error {{expected expression}}
+  }, ...); // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
+
+  [] { // expected-error {{unexpanded parameter pack 'Ts'}}
+    ^ (Ts) {};
+  };
+
+  [] { // expected-error {{unexpanded parameter pack 'Ts'}}
+    (void) ^ { Ts x; };
+  };
+
+  [] { // expected-error {{unexpanded parameter pack 'Ts'}}
+    Ts s;
+    (^Ts); // expected-error {{expected expression}}
+  };
+
+  ([] {
+    Ts s;
+    (^Ts); // expected-error {{expected expression}}
+  }, ...)
+
+  [] { // expected-error {{unexpanded parameter pack 'Ts'}}
+    ^ { Ts s; return not_defined; }; // expected-error {{use of undeclared identifier 'not_defined'}}
+  };
+}

>From 69ce3193bfd0a507f6eac6336bef599c2d6d53e9 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Wed, 2 Oct 2024 01:21:56 +0200
Subject: [PATCH 2/4] clang-format

---
 clang/lib/Sema/SemaExpr.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 29745b1f3edff1..d1c91296a9d468 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -16193,7 +16193,8 @@ void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
   // that we are about to discard along with the rest of the block.
   if (!getCurBlock()->EnclosingLambdaContainsUnexpandedParameterPack) {
     LambdaScopeInfo *L = getEnclosingLambda();
-    if (L) L->ContainsUnexpandedParameterPack = false;
+    if (L)
+      L->ContainsUnexpandedParameterPack = false;
   }
 
   // Leave the expression-evaluation context.

>From 48ca9d63084310087b3d86878b9ae100ccdc3f52 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Wed, 2 Oct 2024 01:22:59 +0200
Subject: [PATCH 3/4] Fix typo in comment

---
 clang/include/clang/Sema/ScopeInfo.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index a943f2edc51fba..3bad1e3bad4312 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -794,9 +794,9 @@ class BlockScopeInfo final : public CapturingScopeInfo {
   QualType FunctionType;
 
   /// We sometimes diagnose unexpanded parameter packs in block literals,
-  /// but an error while the block is parsed causes it to be discarded, in
-  /// which case we need to reset the enclosing lambda's
-  /// ContainsUnexpandedParameterPackFlag.
+  /// but an error while the block is parsed can cause it to be discarded,
+  /// in which case we need to reset the enclosing lambda's
+  /// ContainsUnexpandedParameterPack flag.
   ///
   /// Note: This issue does not exist with lambdas because they push a new
   /// LambdaScopeInfo, so if the expression is discarded, the 'enclosing

>From 06ac9be526b8c9046d9be147f7b6fb733096b7ff Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 3 Oct 2024 03:46:33 +0200
Subject: [PATCH 4/4] Add missing semicolon in test

---
 clang/test/SemaCXX/block-unexpanded-pack.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/SemaCXX/block-unexpanded-pack.cpp b/clang/test/SemaCXX/block-unexpanded-pack.cpp
index c1435b8e314a81..ce88db236d437c 100644
--- a/clang/test/SemaCXX/block-unexpanded-pack.cpp
+++ b/clang/test/SemaCXX/block-unexpanded-pack.cpp
@@ -40,7 +40,7 @@ void gh109148() {
   ([] {
     Ts s;
     (^Ts); // expected-error {{expected expression}}
-  }, ...)
+  }, ...);
 
   [] { // expected-error {{unexpanded parameter pack 'Ts'}}
     ^ { Ts s; return not_defined; }; // expected-error {{use of undeclared identifier 'not_defined'}}



More information about the cfe-commits mailing list