From c5dc46e037e9fc61a6acb3db13588d92bfb304ac Mon Sep 17 00:00:00 2001 From: Christof Meerwald Date: Mon, 9 Nov 2026 15:39:49 +0000 Subject: [PATCH] Empty enclosing packs in generic lambdas [GH #500] --- src/expr.c | 5 +++ src/pending_changes/gh-500.txt | 14 ++++++ src/scope_stk.c | 7 ++- src/scope_stk.h | 2 + .../default.1.1.txt | 12 +----- .../edg_x86_32_cp.1.1.txt | 12 +----- .../edg_x86_64_cp.1.1.txt | 12 +----- .../.constexpr-if-lambda5.rto/default.1.1.txt | 8 +++- .../cpp1z/.fold-lambda4.rto/default.1.1.txt | 3 +- .../.gh-500-warnings.rto/default.1.1.txt | 8 ++++ .../.gh-500-warnings.rto/default.2.1.txt | 8 ++++ .../.gh-500-warnings.rto/default.3.1.txt | 8 ++++ .../.gh-500-warnings.rto/default.4.1.txt | 8 ++++ .../regressions/.gh-500.rto/default.1.1.txt | 1 + .../regressions/.gh-500.rto/default.2.1.txt | 1 + .../regressions/.gh-500.rto/default.3.1.txt | 1 + .../regressions/.gh-500.rto/default.4.1.txt | 1 + .../tests/regressions/gh-500-warnings.sft.cpp | 22 ++++++++++ tests/tests/regressions/gh-500.sft.cpp | 43 +++++++++++++++++++ 19 files changed, 139 insertions(+), 37 deletions(-) create mode 100644 src/pending_changes/gh-500.txt create mode 100644 tests/tests/regressions/.gh-500-warnings.rto/default.1.1.txt create mode 100644 tests/tests/regressions/.gh-500-warnings.rto/default.2.1.txt create mode 100644 tests/tests/regressions/.gh-500-warnings.rto/default.3.1.txt create mode 100644 tests/tests/regressions/.gh-500-warnings.rto/default.4.1.txt create mode 100644 tests/tests/regressions/.gh-500.rto/default.1.1.txt create mode 100644 tests/tests/regressions/.gh-500.rto/default.2.1.txt create mode 100644 tests/tests/regressions/.gh-500.rto/default.3.1.txt create mode 100644 tests/tests/regressions/.gh-500.rto/default.4.1.txt create mode 100644 tests/tests/regressions/gh-500-warnings.sft.cpp create mode 100644 tests/tests/regressions/gh-500.sft.cpp diff --git a/src/expr.c b/src/expr.c index 8986d35f0c..9e8533799e 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1454,6 +1454,11 @@ changed below to be TRUE for certain kinds of expressions and/or contexts. #endif /* MICROSOFT_EXTENSIONS_ALLOWED */ if (suppress_warning) { /* The caller has requested that warnings be suppressed. */ + } else if (in_generic_lambda_in_real_instantiation()) { + /* A hybrid expansion can collapse to an expression with no effect in + this prototype instantiation. Wait for the real instantiation rather + than diagnosing that transient form. */ + suppress_warning = TRUE; } else if (expr_stack->is_type_operator_arg_expression) { /* decltype expressions are sometimes written to check SFINAE conditions, so do not warn inside them. */ diff --git a/src/pending_changes/gh-500.txt b/src/pending_changes/gh-500.txt new file mode 100644 index 0000000000..9f0a059afb --- /dev/null +++ b/src/pending_changes/gh-500.txt @@ -0,0 +1,14 @@ +[GH #500] +Empty enclosing packs in generic lambdas + +A pack expansion in a generic lambda nested in a template instantiation could +produce an error node in the IL when it referenced a lambda parameter pack +before an empty enclosing parameter pack. Empty enclosing packs are now +handled correctly regardless of the order of the pack references. Spurious +warnings from prototype instantiations in such cases are also suppressed. For +example, with --c++20 -tused: + + template void f() { + []() { ((Js * Is) * ... * 1); }; + } + template void f<>(); // Previously produced an error node in the IL. diff --git a/src/scope_stk.c b/src/scope_stk.c index da3c269657..05ba713ed7 100644 --- a/src/scope_stk.c +++ b/src/scope_stk.c @@ -12548,7 +12548,7 @@ have a pack expansion so that it can be expanded in a rescan context. } /* add_pack_expansion_descr_to_prototype_arg */ -static a_boolean in_generic_lambda_in_real_instantiation(void) +a_boolean in_generic_lambda_in_real_instantiation(void) /* Return TRUE if we are in the definition of a generic lambda that is nested inside a real instantiation. In such contexts, a kind of "hybrid expansion" @@ -12836,6 +12836,11 @@ lengths) *err is set to TRUE, FALSE otherwise. /* Got an expansion from an enclosing real instantiation and an unexpanded pack from a nested generic lambda. */ has_hybrid_pack_expansion = TRUE; + if (elements_for_pack == 0) { + /* An empty enclosing pack makes the expansion empty even if an + unexpanded pack from the lambda was encountered first. */ + elements = 0; + } /* if */ } else if (!is_rescan) { pos_st2_error(ec_pack_length_mismatch, &prp->position, prp->symbol->header->identifier, diff --git a/src/scope_stk.h b/src/scope_stk.h index db3b56d4ee..b8e6848cb9 100644 --- a/src/scope_stk.h +++ b/src/scope_stk.h @@ -2632,6 +2632,8 @@ extern void end_prescan_context( a_boolean saved_in_disambiguation, a_boolean saved_source_sequence_entries_disallowed); +extern a_boolean in_generic_lambda_in_real_instantiation(void); + extern a_boolean in_generic_lambda_in_prototype_instantiation(void); extern a_routine_ptr enclosing_nonlambda_routine_for_lambda_class( diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/default.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/default.1.1.txt index 78dc92c093..ee9074e5fa 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/default.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/default.1.1.txt @@ -54,14 +54,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers baz; ^ -"Test_name.c", line 130: error: template template parameter "" is not compatible with template template parameter "" - baz; - ^ - detected during instantiation of "void GH112352::S::foldExpr2() [with TTPs=<>]" at line 139 - -"Test_name.c", line 131: error: too many arguments for template template parameter "TTPs" - TTPs D; - ^ - detected during instantiation of "void GH112352::S::foldExpr2() [with TTPs=<>]" at line 139 - -5 errors detected in the compilation of "Test_name.c". +3 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/edg_x86_32_cp.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/edg_x86_32_cp.1.1.txt index b14554ea75..273b6f83aa 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/edg_x86_32_cp.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/edg_x86_32_cp.1.1.txt @@ -78,14 +78,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers instantiation of function "lambda []()->void [with Ts=]" at line 55 instantiation of "void GH63677::f<>() [with =int]" at line 58 -"Test_name.c", line 130: error: template template parameter "" is not compatible with template template parameter "" - baz; - ^ - detected during instantiation of "void GH112352::S::foldExpr2() [with TTPs=<>]" at line 139 - -"Test_name.c", line 131: error: too many arguments for template template parameter "TTPs" - TTPs D; - ^ - detected during instantiation of "void GH112352::S::foldExpr2() [with TTPs=<>]" at line 139 - -9 errors detected in the compilation of "Test_name.c". +7 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/edg_x86_64_cp.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/edg_x86_64_cp.1.1.txt index b14554ea75..273b6f83aa 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/edg_x86_64_cp.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.lambda-pack-expansion.rto/edg_x86_64_cp.1.1.txt @@ -78,14 +78,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers instantiation of function "lambda []()->void [with Ts=]" at line 55 instantiation of "void GH63677::f<>() [with =int]" at line 58 -"Test_name.c", line 130: error: template template parameter "" is not compatible with template template parameter "" - baz; - ^ - detected during instantiation of "void GH112352::S::foldExpr2() [with TTPs=<>]" at line 139 - -"Test_name.c", line 131: error: too many arguments for template template parameter "TTPs" - TTPs D; - ^ - detected during instantiation of "void GH112352::S::foldExpr2() [with TTPs=<>]" at line 139 - -9 errors detected in the compilation of "Test_name.c". +7 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/gnu/cpp/cpp1z/.constexpr-if-lambda5.rto/default.1.1.txt b/tests/tests/imported/gnu/cpp/cpp1z/.constexpr-if-lambda5.rto/default.1.1.txt index f9382551f1..30e367d4a0 100644 --- a/tests/tests/imported/gnu/cpp/cpp1z/.constexpr-if-lambda5.rto/default.1.1.txt +++ b/tests/tests/imported/gnu/cpp/cpp1z/.constexpr-if-lambda5.rto/default.1.1.txt @@ -2,10 +2,14 @@ fe_only -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_d "Test_name.c", line 10: warning: expression has no effect (..., ts); ^ - detected during instantiation of "void f(Ts...) [with Ts=]" at line 16 + detected during: + instantiation of function "lambda [](auto)->auto [with =int]" at line 12 + instantiation of "void f(Ts...) [with Ts=]" at line 16 "Test_name.c", line 10: warning: expression has no effect (..., ts); ^ - detected during instantiation of "void f(Ts...) [with Ts=]" at line 16 + detected during: + instantiation of function "lambda [](auto)->auto [with =int]" at line 12 + instantiation of "void f(Ts...) [with Ts=]" at line 16 diff --git a/tests/tests/imported/gnu/cpp/cpp1z/.fold-lambda4.rto/default.1.1.txt b/tests/tests/imported/gnu/cpp/cpp1z/.fold-lambda4.rto/default.1.1.txt index c742b27b0a..3411113824 100644 --- a/tests/tests/imported/gnu/cpp/cpp1z/.fold-lambda4.rto/default.1.1.txt +++ b/tests/tests/imported/gnu/cpp/cpp1z/.fold-lambda4.rto/default.1.1.txt @@ -3,6 +3,7 @@ fe_only -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_d ys; ^ detected during: - instantiation of function "lambda [](auto &...)->auto [with =]" at line 26 + instantiation of function "lambda [](auto)->auto [with =int]" at line 11 + instantiation of "void X::f(F) [with F=lambda [](auto)->auto]" at line 26 instantiation of "void bug(Xs...) [with Xs=]" at line 31 diff --git a/tests/tests/regressions/.gh-500-warnings.rto/default.1.1.txt b/tests/tests/regressions/.gh-500-warnings.rto/default.1.1.txt new file mode 100644 index 0000000000..16fdef5dcb --- /dev/null +++ b/tests/tests/regressions/.gh-500-warnings.rto/default.1.1.txt @@ -0,0 +1,8 @@ +fe_only -DTEST_NUMBER=1 -tused --c++20 Test_name.c +"Test_name.c", line 17: warning: expression has no effect + auto l = []() { ((S * V) * ... * 1); }; + ^ + detected during: + instantiation of function "lambda []()->auto [with S=<3>]" at line 18 + instantiation of "void real_instantiation::f() [with V=<2>]" at line 21 + diff --git a/tests/tests/regressions/.gh-500-warnings.rto/default.2.1.txt b/tests/tests/regressions/.gh-500-warnings.rto/default.2.1.txt new file mode 100644 index 0000000000..d6319c2d01 --- /dev/null +++ b/tests/tests/regressions/.gh-500-warnings.rto/default.2.1.txt @@ -0,0 +1,8 @@ +fe_only -DTEST_NUMBER=2 -tused --c++20 --gnu_version 150200 Test_name.c +"Test_name.c", line 17: warning: expression has no effect + auto l = []() { ((S * V) * ... * 1); }; + ^ + detected during: + instantiation of function "lambda []()->auto [with S=<3>]" at line 18 + instantiation of "void real_instantiation::f() [with V=<2>]" at line 21 + diff --git a/tests/tests/regressions/.gh-500-warnings.rto/default.3.1.txt b/tests/tests/regressions/.gh-500-warnings.rto/default.3.1.txt new file mode 100644 index 0000000000..02476646df --- /dev/null +++ b/tests/tests/regressions/.gh-500-warnings.rto/default.3.1.txt @@ -0,0 +1,8 @@ +fe_only -DTEST_NUMBER=3 -tused --c++20 --clang_version 220100 Test_name.c +"Test_name.c", line 17: warning: expression has no effect + auto l = []() { ((S * V) * ... * 1); }; + ^ + detected during: + instantiation of function "lambda []()->auto [with S=<3>]" at line 18 + instantiation of "void real_instantiation::f() [with V=<2>]" at line 21 + diff --git a/tests/tests/regressions/.gh-500-warnings.rto/default.4.1.txt b/tests/tests/regressions/.gh-500-warnings.rto/default.4.1.txt new file mode 100644 index 0000000000..29bbc8ef7a --- /dev/null +++ b/tests/tests/regressions/.gh-500-warnings.rto/default.4.1.txt @@ -0,0 +1,8 @@ +fe_only -DTEST_NUMBER=4 -tused --ms_c++20 --microsoft_version 1950 Test_name.c +"Test_name.c", line 17: warning: expression has no effect + auto l = []() { ((S * V) * ... * 1); }; + ^ + detected during: + instantiation of function "lambda []()->auto [with S=<3>]" at line 18 + instantiation of "void real_instantiation::f() [with V=<2>]" at line 21 + diff --git a/tests/tests/regressions/.gh-500.rto/default.1.1.txt b/tests/tests/regressions/.gh-500.rto/default.1.1.txt new file mode 100644 index 0000000000..03197e1b69 --- /dev/null +++ b/tests/tests/regressions/.gh-500.rto/default.1.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=1 --il_display -tused --c++20 Test_name.c diff --git a/tests/tests/regressions/.gh-500.rto/default.2.1.txt b/tests/tests/regressions/.gh-500.rto/default.2.1.txt new file mode 100644 index 0000000000..437f901e51 --- /dev/null +++ b/tests/tests/regressions/.gh-500.rto/default.2.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=2 --il_display -tused --c++20 --gn 150200 Test_name.c diff --git a/tests/tests/regressions/.gh-500.rto/default.3.1.txt b/tests/tests/regressions/.gh-500.rto/default.3.1.txt new file mode 100644 index 0000000000..b51b505ea3 --- /dev/null +++ b/tests/tests/regressions/.gh-500.rto/default.3.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=3 --il_display -tused --c++20 --clang_version 220100 Test_name.c diff --git a/tests/tests/regressions/.gh-500.rto/default.4.1.txt b/tests/tests/regressions/.gh-500.rto/default.4.1.txt new file mode 100644 index 0000000000..a3934473d0 --- /dev/null +++ b/tests/tests/regressions/.gh-500.rto/default.4.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=4 --il_display -tused --ms_c++20 --microsoft_version 1950 Test_name.c diff --git a/tests/tests/regressions/gh-500-warnings.sft.cpp b/tests/tests/regressions/gh-500-warnings.sft.cpp new file mode 100644 index 0000000000..1159449630 --- /dev/null +++ b/tests/tests/regressions/gh-500-warnings.sft.cpp @@ -0,0 +1,22 @@ +//type:fp +//options:--c++20:--c++20 --gnu_version 150200:--c++20 --clang_version 220100:--ms_c++20 --microsoft_version 1950 +//options_all:-tused + +namespace suppressed_in_prototype +{ + template void f() { + []() { ((S * V) * ... * 1); }; + } + + template void f<>(); +} + +namespace real_instantiation +{ + template void f() { + auto l = []() { ((S * V) * ... * 1); }; + l.template operator()<3>(); + } + + template void f<2>(); +} diff --git a/tests/tests/regressions/gh-500.sft.cpp b/tests/tests/regressions/gh-500.sft.cpp new file mode 100644 index 0000000000..e46a944d53 --- /dev/null +++ b/tests/tests/regressions/gh-500.sft.cpp @@ -0,0 +1,43 @@ +//type:fp +//options:--c++20:--c++20 --gn 150200:--c++20 --clang_version 220100:--ms_c++20 --microsoft_version 1950 +//options_all:--il_display -tused +//filter:grep -E '(tk_error|enk_error)' + +namespace minimal +{ + template void f() { + []() { ((Js * Is) * ... * 1); }; + } + template void f<>(); +} + +namespace inner_pack_first +{ + template constexpr auto f() { + return []() { return ((S * V) * ... * 1); }; + } + + static_assert(f<>().template operator()<>() == 1); + static_assert(f<2>().template operator()<3>() == 6); + static_assert(f<2, 3>().template operator()<4, 5>() == 120); +} + +namespace outer_pack_first +{ + template constexpr auto f() { + return []() { return ((V * S) * ... * 1); }; + } + + static_assert(f<>().template operator()<>() == 1); + static_assert(f<2>().template operator()<3>() == 6); + static_assert(f<2, 3>().template operator()<4, 5>() == 120); +} + +namespace uninstantiated_lambda +{ + template void f() { + []() { (void)((S * V) * ... * 1); }; + } + + void g() { f<>(); } +}