[clang] [Clang] Recover invalid lambdas without numbering (PR #233375)

via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 19 02:06:14 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Younan Zhang (zyn0217)

<details>
<summary>Changes</summary>

Those DecltypeExprs used to preserve RecoveryExprs which makes things complicated when we need to recover errors from a lambda expression.

This patch stops that, as well as fixes some other error handlings.

I don't think this is worth a release note entry - I just want to stop AI from messing around those things.

Fixes https://github.com/llvm/llvm-project/issues/150733
Fixes https://github.com/llvm/llvm-project/issues/175713
Fixes https://github.com/llvm/llvm-project/issues/170185


---
Full diff: https://github.com/llvm/llvm-project/pull/233375.diff


8 Files Affected:

- (modified) clang/lib/Parse/ParseTemplate.cpp (+2-1) 
- (modified) clang/lib/Sema/SemaExprCXX.cpp (+4) 
- (modified) clang/lib/Sema/SemaLambda.cpp (+1-1) 
- (modified) clang/test/AST/ByteCode/records.cpp (+2-4) 
- (modified) clang/test/AST/ast-dump-expr-errors.cpp (+1-1) 
- (added) clang/test/SemaCXX/invalid-lambda.cpp (+58) 
- (removed) clang/test/SemaCXX/invalid-this-in-lambda.cpp (-4) 
- (modified) clang/test/SemaCXX/recovery-expr-type.cpp (+3-2) 


``````````diff
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index ef6920fdc485c..ff4945f014db1 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -1375,7 +1375,8 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
   else
     ExprArg = ParseConstantExpressionInExprEvalContext(
         TypoCorrectionTypeBehavior::AllowBoth);
-  if (ExprArg.isInvalid() || !ExprArg.get()) {
+  if (ExprArg.isInvalid() || !ExprArg.get() ||
+      ExprArg.get()->containsErrors()) {
     return ParsedTemplateArgument();
   }
 
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index d9bd060f7a0bf..2e717fe05a24e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -6930,6 +6930,10 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
              ExpressionEvaluationContextRecord::EK_Decltype &&
          "not in a decltype expression");
 
+  // Give up here so we don't try to evaluate it later.
+  if (isa<RecoveryExpr>(E))
+    return ExprError();
+
   ExprResult Result = CheckPlaceholderExpr(E);
   if (Result.isInvalid())
     return ExprError();
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 0c9a92cdd0c32..ed2423542d2af 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1488,7 +1488,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
     const auto &FTI = ParamInfo.getFunctionTypeInfo();
     LSI->ExplicitParams = FTI.getLParenLoc().isValid();
     if (!FTIHasSingleVoidParameter(FTI)) {
-      Params.reserve(Params.size());
+      Params.reserve(FTI.NumParams);
       for (unsigned I = 0; I < FTI.NumParams; ++I) {
         auto *Param = cast<ParmVarDecl>(FTI.Params[I].Param);
         Param->setScopeInfo(0, Params.size());
diff --git a/clang/test/AST/ByteCode/records.cpp b/clang/test/AST/ByteCode/records.cpp
index ab79384a10476..4404eb7c6df23 100644
--- a/clang/test/AST/ByteCode/records.cpp
+++ b/clang/test/AST/ByteCode/records.cpp
@@ -2019,15 +2019,13 @@ namespace ErroneousVoidDecl {
 
   template <typename F, typename C, typename N1, typename N2>
   constexpr bool check(const C &c, N1 *n1, N2 *n2) {
-    decltype(f(c, n1, n2)) *chk{}; // both-error {{no matching function}} \
-                                   // ref-note {{destroying object 'chk' whose lifetime has already ended}}
+    decltype(f(c, n1, n2)) *chk{}; // both-error {{no matching function}}
     return true;
   }
 
   template <int N> constexpr M<N> *bar() { return nullptr; }
   static_assert(check<S>([](int n) constexpr {}, bar<1u>(), bar<1u>())); // both-note {{in instantiation}} \
-                                                                         // ref-error {{not an integral constant expression}} \
-                                                                         // ref-note {{in call to}}
+                                                                         // both-error {{not an integral constant expression}}
 #endif
 }
 
diff --git a/clang/test/AST/ast-dump-expr-errors.cpp b/clang/test/AST/ast-dump-expr-errors.cpp
index 5661a41465eb6..1aad414a5c3d8 100644
--- a/clang/test/AST/ast-dump-expr-errors.cpp
+++ b/clang/test/AST/ast-dump-expr-errors.cpp
@@ -42,5 +42,5 @@ int d = static_cast<int>(bar() + 1);
 
 
 // Error type should result in an invalid decl.
-// CHECK: -VarDecl {{.*}} invalid f 'decltype(<recovery-expr>(bar))'
+// CHECK: -VarDecl {{.*}} invalid f 'int'
 decltype(bar()) f;
diff --git a/clang/test/SemaCXX/invalid-lambda.cpp b/clang/test/SemaCXX/invalid-lambda.cpp
new file mode 100644
index 0000000000000..a5ec348dcf439
--- /dev/null
+++ b/clang/test/SemaCXX/invalid-lambda.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++26 %s
+
+decltype([]()->decltype(this) { }) a; // expected-error {{invalid use of 'this' outside of a non-static member function}}
+
+#if __cplusplus >= 202302L
+namespace GH175173 {
+
+struct A {
+  void f(this A&) {
+    auto l = [](auto g, decltype(g(this))){};
+    // expected-error at -1 {{invalid use of 'this'}}
+  }
+};
+
+struct B {
+  void f() {
+    auto l = [](int g, decltype(g(this))){};
+    // expected-error at -1 {{called object type 'int'}}
+  }
+};
+
+}
+#endif
+
+#if __cplusplus == 201103L
+
+namespace GH150733 {
+auto L = [](auto a) {
+  // expected-error at -1 {{'auto' not allowed in lambda}}
+  auto M = [](decltype(a)) -> {
+    // expected-error at -1 {{expected a type}}
+  };
+};
+}
+
+#endif
+
+namespace GH170185 {
+
+struct Foo; // expected-note 2{{forward declaration}}
+
+template <Foo X>
+// expected-error at -1 {{non-type template parameter has incomplete type}}
+struct Arr;
+
+Foo f; // expected-error {{variable has incomplete type}}
+
+void foo() {
+    (void)[]() {
+        (void)[&](Arr<f>) {
+
+        };
+    }();
+}
+
+}
diff --git a/clang/test/SemaCXX/invalid-this-in-lambda.cpp b/clang/test/SemaCXX/invalid-this-in-lambda.cpp
deleted file mode 100644
index ae65bda025e23..0000000000000
--- a/clang/test/SemaCXX/invalid-this-in-lambda.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-
-decltype([]()->decltype(this) { }) a; // expected-error {{invalid use of 'this' outside of a non-static member function}}
-
diff --git a/clang/test/SemaCXX/recovery-expr-type.cpp b/clang/test/SemaCXX/recovery-expr-type.cpp
index 101d0155e3b98..7b6bd8d1699c5 100644
--- a/clang/test/SemaCXX/recovery-expr-type.cpp
+++ b/clang/test/SemaCXX/recovery-expr-type.cpp
@@ -195,8 +195,9 @@ using V = U<S<T>>;
 
 namespace GH202117 {
 template<template<decltype(foo())> typename T> struct S {}; // expected-error {{use of undeclared identifier 'foo'}}
-template<int*> struct P;
-S<P> s;
+template<int*> struct P; // expected-error at -1 {{conversion from 'int' to 'int *' is not allowed}}
+S<P> s; // expected-note {{template template argument has different template parameters}}
+// expected-note at -3 {{previous template template parameter}} expected-note at -2 {{declared here}}
 } // namespace GH202117
 
 namespace test17 {

``````````

</details>


https://github.com/llvm/llvm-project/pull/233375


More information about the cfe-commits mailing list