https://github.com/akashagrwl updated https://github.com/llvm/llvm-project/pull/210718
>From c8616664214149f2a9fdb636499174310430735d Mon Sep 17 00:00:00 2001 From: Akash Agrawal <[email protected]> Date: Mon, 20 Jul 2026 06:28:23 -0700 Subject: [PATCH 1/2] [Clang][Sema] Fix crash on lambda parameter pack with illegal default argument `Sema::ActOnParamDefaultArgument` checked a default-argument expression for unexpanded parameter packs before checking whether the parameter itself is a pack. For a lambda parameter pack given a default argument that is a pack expansion referencing an enclosing function's parameter pack (e.g. `[](Types... = args...) {}`), the first check runs while still inside the lambda's scope and sets `LambdaScopeInfo::ContainsUnexpandedParameterPack` (a mechanism meant for legitimate outer-pack references). The subsequent `isParameterPack()` check then correctly diagnoses the real error and discards the default argument, but the stale flag survives into the built `LambdaExpr`'s dependence bits. A later unexpanded-pack check on that `LambdaExpr` finds nothing to report and hits `assert(!Unexpanded.empty() || LambdaReferencingOuterPacks)`, aborting instead of just diagnosing the error. Fix: check `Param->isParameterPack()` first and return immediately after discarding the default argument, before ever calling `DiagnoseUnexpandedParameterPack` on an expression that is about to be thrown away. [dcl.fct.default]p3 forbids a default argument on a pack parameter unconditionally, so this ordering is also semantically correct, not just a crash workaround. Fixes #210714 --- clang/docs/ReleaseNotes.md | 5 +++++ clang/lib/Sema/SemaDeclCXX.cpp | 14 ++++++++++---- .../dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp | 10 ++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 9301745b9628e..9737e9281e579 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -318,6 +318,11 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the - Fixed a crash when a using-declaration naming an unresolvable member of a dependent base was shadowed by an invalid using-declaration. (#GH209427) +- Fixed a crash when a lambda parameter pack was given a default argument that + is a pack expansion referencing an enclosing function's parameter pack (e.g. + `[](Types... = args...) {}`). Clang now diagnoses the illegal default + argument instead of asserting. (#GH210714) + #### Bug Fixes to AST Handling - Fixed a non-deterministic ordering of unused local typedefs that made diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 37bb69da90b6c..e5a5963db27c2 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -359,13 +359,15 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg); } - // Check for unexpanded parameter packs. - if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument)) - return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg); - // C++11 [dcl.fct.default]p3 // A default argument expression [...] shall not be specified for a // parameter pack. + // + // Check this before looking for unexpanded parameter packs in DefaultArg: + // if DefaultArg references a pack from an enclosing lambda/block, that + // check would (incorrectly) mark the lambda as containing an unexpanded + // pack that never actually appears in the final AST once we discard + // DefaultArg below. if (Param->isParameterPack()) { Diag(EqualLoc, diag::err_param_default_argument_on_parameter_pack) << DefaultArg->getSourceRange(); @@ -374,6 +376,10 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, return; } + // Check for unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument)) + return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg); + ExprResult Result = ConvertParamDefaultArgument(Param, DefaultArg, EqualLoc); if (Result.isInvalid()) return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg); diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp index 11c17f32728a1..eaee2393ed12c 100644 --- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp @@ -17,3 +17,13 @@ struct X0 { template <typename... Ts> void defaultpack(Ts... = 0) {} // expected-error{{parameter pack cannot have a default argument}} + +// A lambda parameter pack whose default argument is a pack expansion +// referencing the enclosing function's parameter pack must be diagnosed +// without crashing. +template <class... Types> void lambda_pack_default_arg(Types... args) { + auto lm = [](Types... = args...) {}; // expected-error{{parameter pack cannot have a default argument}} \ + // expected-warning{{'...' in this location creates a C-style varargs function}} \ + // expected-note{{preceding '...' declares a function parameter pack}} \ + // expected-note{{insert ',' before '...' to silence this warning}} +} >From 21f125c8ce04a14a049631b661b5d4061ebb777a Mon Sep 17 00:00:00 2001 From: Akash Agrawal <[email protected]> Date: Mon, 20 Jul 2026 07:23:09 -0700 Subject: [PATCH 2/2] Nit: added FIXME --- clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp index eaee2393ed12c..594e38854864c 100644 --- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp @@ -22,6 +22,9 @@ void defaultpack(Ts... = 0) {} // expected-error{{parameter pack cannot have a d // referencing the enclosing function's parameter pack must be diagnosed // without crashing. template <class... Types> void lambda_pack_default_arg(Types... args) { + // FIXME: do not produce these diagnostics. The '...' is the parameter + // pack's own ellipsis, not an ambiguous C-style varargs ellipsis, so the + // -Wambiguous-ellipsis warning and its notes should not be emitted here. auto lm = [](Types... = args...) {}; // expected-error{{parameter pack cannot have a default argument}} \ // expected-warning{{'...' in this location creates a C-style varargs function}} \ // expected-note{{preceding '...' declares a function parameter pack}} \ _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
