llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Akash Manna (akash-manna-sky)

<details>
<summary>Changes</summary>

Fixes #<!-- -->175713
Fixes #<!-- -->150733

Sema numbers a lambda for mangling as soon as its declarator is parsed, before 
the signature is known to be valid. Under the Itanium ABI that number comes 
from mangling the whole `&lt;lambda-sig&gt;`, so a parameter type such as 
`decltype(g(this))` with an invalid operand, or `decltype(a)` naming an invalid 
declaration, handed the mangler a `RecoveryExpr` and hit 
`llvm_unreachable("unexpected statement kind")`. Template parameter types and 
the requires-clause of a generic lambda reach the same place.

`handleLambdaNumbering` now skips the numbering when the call operator's type, 
a template parameter type or the requires-clause contains errors, leaving the 
lambda in the same state as one in a context that needs no numbering. Invalid 
code is never emitted, so no mangled name is ever needed for it, and the 
mangler keeps its invariant of never seeing erroneous AST.

LLM tools were used for this contribution.


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


7 Files Affected:

- (modified) clang/docs/ReleaseNotes.md (+3) 
- (modified) clang/lib/Sema/SemaLambda.cpp (+27) 
- (modified) clang/test/CodeGenCXX/mangle-lambdas.cpp (+14) 
- (modified) clang/test/SemaCXX/cxx11-crashes.cpp (+7) 
- (modified) clang/test/SemaCXX/cxx2a-template-lambdas.cpp (+12) 
- (modified) clang/test/SemaCXX/cxx2b-deducing-this.cpp (+14) 
- (modified) clang/test/SemaCXX/recovery-expr-type.cpp (+46) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 3f0c48cf36644d..330d45b8b14c8e 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -929,6 +929,9 @@ features cannot lower the translation-unit ABI level;
 - Fixed merging of lambdas across modules in the case where neither lambda is
   imported from an AST file. (#GH214560)
 
+- Fixed a crash when a parameter or template parameter of a lambda had a
+  `decltype` of an erroneous expression as its type. (#GH175713, #GH150733)
+
 - Fixed a crash when a non-type template parameter of reference type is bound
   to a subobject and is used in a context that requires an implicit conversion.
   (#GH215900)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 0c9a92cdd0c320..774a95eb5a8920 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -486,6 +486,29 @@ bool Sema::DiagnoseInvalidExplicitObjectParameterInLambda(
   return false;
 }
 
+static bool templateParameterContainsErrors(const NamedDecl *Param) {
+  if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
+    return NTTP->getType()->containsErrors();
+  if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param))
+    return llvm::any_of(*TTP->getTemplateParameters(),
+                        templateParameterContainsErrors);
+  return false;
+}
+
+/// Whether any part of the lambda's <lambda-sig> contains errors.
+static bool lambdaSignatureContainsErrors(const CXXRecordDecl *Class,
+                                          const CXXMethodDecl *Method) {
+  if (Method->isInvalidDecl() || Method->getType()->containsErrors())
+    return true;
+  const TemplateParameterList *TPL =
+      Class->getGenericLambdaTemplateParameterList();
+  if (!TPL)
+    return false;
+  const Expr *RequiresClause = TPL->getRequiresClause();
+  return (RequiresClause && RequiresClause->containsErrors()) ||
+         llvm::any_of(*TPL, templateParameterContainsErrors);
+}
+
 void Sema::handleLambdaNumbering(
     CXXRecordDecl *Class, CXXMethodDecl *Method,
     std::optional<CXXRecordDecl::LambdaNumbering> NumberingOverride) {
@@ -517,6 +540,10 @@ void Sema::handleLambdaNumbering(
   if (ContextDecl)
     Class->setLambdaContextDecl(ContextDecl);
 
+  // Erroneous signatures cannot be mangled, and invalid code is never emitted.
+  if (lambdaSignatureContainsErrors(Class, Method))
+    return;
+
   CXXRecordDecl::LambdaNumbering Numbering;
   if (!MCtx && (getLangOpts().CUDA || getLangOpts().SYCLIsDevice ||
                 getLangOpts().SYCLIsHost)) {
diff --git a/clang/test/CodeGenCXX/mangle-lambdas.cpp 
b/clang/test/CodeGenCXX/mangle-lambdas.cpp
index d9ac0d39956e94..b464c74eb3ceb6 100644
--- a/clang/test/CodeGenCXX/mangle-lambdas.cpp
+++ b/clang/test/CodeGenCXX/mangle-lambdas.cpp
@@ -436,3 +436,17 @@ struct TestNestedInstantiation {
 void test_NestedInstantiation() {
   TestNestedInstantiation()();
 }
+
+template <typename T> void decltype_sig(T t) {
+  [](decltype(t) x) { side_effect(); }(t);
+  [](decltype(t) x) { side_effect(); }(t);
+  [](decltype(t) x, T y) { side_effect(); }(t, t);
+  [](auto x, decltype(t) y) { side_effect(); }(t, t);
+}
+
+void use_decltype_sig() { decltype_sig(1); }
+
+// CHECK-LABEL: define linkonce_odr void @_ZZ12decltype_sigIiEvT_ENKUliE_clEi(
+// CHECK-LABEL: define linkonce_odr void @_ZZ12decltype_sigIiEvT_ENKUliE0_clEi(
+// CHECK-LABEL: define linkonce_odr void 
@_ZZ12decltype_sigIiEvT_ENKUliiE_clEii(
+// CHECK-LABEL: define linkonce_odr void 
@_ZZ12decltype_sigIiEvT_ENKUlS0_iE_clIiEEDaS0_i(
diff --git a/clang/test/SemaCXX/cxx11-crashes.cpp 
b/clang/test/SemaCXX/cxx11-crashes.cpp
index 11bc42315421d6..00a2b69606d181 100644
--- a/clang/test/SemaCXX/cxx11-crashes.cpp
+++ b/clang/test/SemaCXX/cxx11-crashes.cpp
@@ -121,3 +121,10 @@ struct Bar {
 // This used to crash when trying to get the layout of B.
 Bar x;
 }
+
+namespace GH150733 {
+auto L = [](auto a) { // expected-error {{'auto' not allowed in lambda 
parameter before C++14}}
+  auto M = [](decltype(a)) -> { // expected-error {{expected a type}}
+  };
+};
+}
diff --git a/clang/test/SemaCXX/cxx2a-template-lambdas.cpp 
b/clang/test/SemaCXX/cxx2a-template-lambdas.cpp
index 45d265e2cdc2b2..7a8011701214c8 100644
--- a/clang/test/SemaCXX/cxx2a-template-lambdas.cpp
+++ b/clang/test/SemaCXX/cxx2a-template-lambdas.cpp
@@ -132,3 +132,15 @@ void f() {
 }
 }
 #endif
+
+#if __cplusplus >= 202002L
+namespace GH175713 {
+template <typename T> concept C = true;
+inline void f() {
+  auto a = []<decltype(1()) N>() {}; // expected-error {{called object type 
'int' is not a function or function pointer}}
+  auto b = []<template <decltype(1()) N> class TT>() {}; // expected-error 
{{called object type 'int' is not a function or function pointer}}
+  auto c = []<typename T> requires (sizeof(T) == 1()) (T) {}; // 
expected-error {{called object type 'int' is not a function or function 
pointer}}
+  auto d = []<C<decltype(1())> T>(T) {}; // expected-error {{called object 
type 'int' is not a function or function pointer}}
+}
+}
+#endif
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp 
b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 5dfc5bbf50abd3..a1526d05d70eca 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -1484,3 +1484,17 @@ void foo() {
 }
 
 }
+
+namespace GH175713 {
+
+struct A {
+  void f(this A&) {
+    auto l = [](auto g, decltype(g(this))){}; // expected-error {{invalid use 
of 'this' in a function with an explicit object parameter}}
+  }
+};
+
+inline void g() {
+  auto l = [](this decltype(1()) self) {}; // expected-error {{called object 
type 'int' is not a function or function pointer}}
+}
+
+}
diff --git a/clang/test/SemaCXX/recovery-expr-type.cpp 
b/clang/test/SemaCXX/recovery-expr-type.cpp
index 101d0155e3b987..6e3226e56e654d 100644
--- a/clang/test/SemaCXX/recovery-expr-type.cpp
+++ b/clang/test/SemaCXX/recovery-expr-type.cpp
@@ -222,3 +222,49 @@ B x;
 static_assert(x.a == 0); // expected-error {{static assertion expression is 
not an integral constant expression}} \
                            ref-note {{read of non-constexpr variable 'a' is 
not allowed in a constant expression}}
 } // namespace test18
+
+namespace GH175713 {
+struct A {
+  void f() {
+    auto l = [](int g, decltype(g(this))){}; // expected-error {{called object 
type 'int' is not a function or function pointer}}
+  }
+};
+
+inline void inline_function() {
+  auto l = [](decltype(1()) x) {}; // expected-error {{called object type 
'int' is not a function or function pointer}}
+}
+
+template <typename T> struct S {
+  void f() {
+    auto l = [](decltype(1()) x) {}; // expected-error {{called object type 
'int' is not a function or function pointer}}
+  }
+};
+void instantiate() { S<int>().f(); }
+
+void nested() {
+  auto outer = [](auto x) {
+    auto inner = [](decltype(1()) y) {}; // expected-error {{called object 
type 'int' is not a function or function pointer}}
+  };
+}
+
+struct DefaultArgument {
+  void f(int = ((void)[](decltype(1()) x) {}, 0)); // expected-error {{called 
object type 'int' is not a function or function pointer}}
+};
+
+inline auto inline_variable = [](decltype(1()) x) {}; // expected-error 
{{called object type 'int' is not a function or function pointer}}
+auto variable = [](decltype(1()) x) {}; // expected-error {{called object type 
'int' is not a function or function pointer}}
+
+inline void trailing_return_type() {
+  auto l = [](int) -> decltype(1()) {}; // expected-error {{called object type 
'int' is not a function or function pointer}}
+}
+
+inline void default_argument() {
+  auto l = [](int x = 1()) {}; // expected-error {{called object type 'int' is 
not a function or function pointer}}
+}
+
+template <typename T> void dependent(T t) {
+  auto l = [](decltype(t) x, decltype(t + 1) y) {};
+  l(t, t);
+}
+void instantiate_dependent() { dependent(0); }
+} // namespace GH175713

``````````

</details>


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

Reply via email to