Bug 107457 - ICE when template lambda alias used as default template argument
Summary: ICE when template lambda alias used as default template argument
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 12.2.0
: P3 normal
Target Milestone: 14.0
Assignee: Patrick Palka
URL:
Keywords: c++-lambda, ice-on-valid-code
Depends on:
Blocks: c++-lambda-decltype
  Show dependency treegraph
 
Reported: 2022-10-29 13:41 UTC by Aleksandras Andrejevas
Modified: 2024-04-12 19:21 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-10-29 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Aleksandras Andrejevas 2022-10-29 13:41:36 UTC
The following code causes an ICE with GCC 12.2.0 until trunk, on -std=c++{20,23}:

template<class T>
using lambda = decltype([]() {});

template<class R, class F = lambda<R>>
void test() {}

int main() {
	test<int>();
}


godbolt: https://godbolt.org/z/Mx1z77hTn


Error message:

PS> g++ -std=c++20 "main_ice.cpp" -o"bin\main_ice.exe"
main_ice.cpp: In substitution of 'template<class T> using lambda = decltype (<lambda>) [with T = R]':
main_ice.cpp:4:36:   required from here
main_ice.cpp:2:25: internal compiler error: Segmentation fault
    2 | using lambda = decltype([]() {});
      |                         ^~~~~~~
libbacktrace could not find executable to open
Please submit a full bug report, with preprocessed source (by using -freport-bug).
See <https://github.com/msys2/MINGW-packages/issues> for instructions.
Comment 1 Drea Pinski 2022-10-29 19:35:14 UTC
Confirmed.

GCC has trouble with lambdas inside decltype especially with alias's and that is definitely what is being used here.
Comment 2 Marek Polacek 2024-02-29 16:11:12 UTC
Another test for the same problem:

```
template <typename Type> using LambdaType = decltype([] {});
template <typename Type, typename = LambdaType<Type>> class S;
```

107457.C:3:25: internal compiler error: Segmentation fault
    3 | using lambda = decltype([]() {});
      |                         ^~~~~~~
0x1ac234a crash_signal
	/home/mpolacek/src/gcc/gcc/toplev.cc:319
0x7fd3f489099f ???
	/usr/src/debug/glibc-2.38-16.fc39.x86_64/signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0
0xeda764 begin_function_body()
	/home/mpolacek/src/gcc/gcc/cp/decl.cc:18398
0xf4eb05 start_lambda_function(tree_node*, tree_node*)
	/home/mpolacek/src/gcc/gcc/cp/lambda.cc:1700
0x1106d94 tsubst_lambda_expr(tree_node*, tree_node*, int, tree_node*)
	/home/mpolacek/src/gcc/gcc/cp/pt.cc:19748
0x11119fc tsubst_expr(tree_node*, tree_node*, int, tree_node*)
	/home/mpolacek/src/gcc/gcc/cp/pt.cc:21684
0x10f5523 tsubst(tree_node*, tree_node*, int, tree_node*)
	/home/mpolacek/src/gcc/gcc/cp/pt.cc:16895
0x10ef6e0 tsubst_decl
	/home/mpolacek/src/gcc/gcc/cp/pt.cc:15531
0x1113f4e instantiate_template(tree_node*, tree_node*, int)
	/home/mpolacek/src/gcc/gcc/cp/pt.cc:22100
0x1114a20 instantiate_alias_template
	/home/mpolacek/src/gcc/gcc/cp/pt.cc:22198
0x10f21c7 tsubst(tree_node*, tree_node*, int, tree_node*)
	/home/mpolacek/src/gcc/gcc/cp/pt.cc:16193
0x10cea1f lookup_template_class(tree_node*, tree_node*, tree_node*, tree_node*, int, int)
	/home/mpolacek/src/gcc/gcc/cp/pt.cc:10204
0x116c376 finish_template_type(tree_node*, tree_node*, int)
	/home/mpolacek/src/gcc/gcc/cp/semantics.cc:3948
0x103d7eb cp_parser_template_id
	/home/mpolacek/src/gcc/gcc/cp/parser.cc:19048
0x104d762 cp_parser_class_name
	/home/mpolacek/src/gcc/gcc/cp/parser.cc:26655
0x1023508 cp_parser_qualifying_entity
	/home/mpolacek/src/gcc/gcc/cp/parser.cc:7400
0x10229d6 cp_parser_nested_name_specifier_opt
	/home/mpolacek/src/gcc/gcc/cp/parser.cc:7082
0x1040456 cp_parser_simple_type_specifier
	/home/mpolacek/src/gcc/gcc/cp/parser.cc:20491
0x103f70d cp_parser_type_specifier
	/home/mpolacek/src/gcc/gcc/cp/parser.cc:20142
0x104a146 cp_parser_type_specifier_seq
	/home/mpolacek/src/gcc/gcc/cp/parser.cc:25175
Comment 3 Patrick Palka 2024-04-12 19:20:51 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:081c1e93d56d35c7314ed68e6d87628b430de917

commit r14-9938-081c1e93d56d35c7314ed68e6d87628b430de917
Author: Patrick Palka <ppalka@redhat.com>

c++: templated substitution into lambda-expr [PR114393]

The below testcases use a lambda-expr as a template argument and they
all trip over the below added tsubst_lambda_expr sanity check ultimately
because current_template_parms is empty which causes push_template_decl
to return error_mark_node from the call to begin_lambda_type.  Were it
not for the sanity check this silent error_mark_node result leads to
nonsensical errors down the line, or silent breakage.

In the first testcase, we hit this assert during instantiation of the
dependent alias template-id c1_t<_Data> from instantiate_template, which
clears current_template_parms via push_to_top_level.  Similar story for
the second testcase.  For the third testcase we hit the assert during
partial instantiation of the member template from instantiate_class_template
which similarly calls push_to_top_level.

These testcases illustrate that templated substitution into a lambda-expr
is not always possible, in particular when we lost the relevant template
context.  I experimented with recovering the template context by making
tsubst_lambda_expr fall back to using scope_chain->prev->template_parms if
current_template_parms is empty which worked but seemed like a hack.  I
also experimented with preserving the template context by keeping
current_template_parms set during instantiate_template for a dependent
specialization which also worked but it's at odds with the fact that we
cache dependent specializations (and so they should be independent of
the template context).

So instead of trying to make such substitution work, this patch uses the
extra-args mechanism to defer templated substitution into a lambda-expr
when we lost the relevant template context.

	PR c++/114393
	PR c++/107457
	PR c++/93595

gcc/cp/ChangeLog:

	* cp-tree.h (LAMBDA_EXPR_EXTRA_ARGS): Define.
	(tree_lambda_expr::extra_args): New field.
	* module.cc (trees_out::core_vals) <case LAMBDA_EXPR>: Stream
	LAMBDA_EXPR_EXTRA_ARGS.
	(trees_in::core_vals) <case LAMBDA_EXPR>: Likewise.
	* pt.cc (has_extra_args_mechanism_p): Return true for LAMBDA_EXPR.
	(tree_extra_args): Handle LAMBDA_EXPR.
	(tsubst_lambda_expr): Use LAMBDA_EXPR_EXTRA_ARGS to defer templated
	substitution into a lambda-expr if we lost the template context.
	Add sanity check for error_mark_node result from begin_lambda_type.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/lambda-targ2.C: New test.
	* g++.dg/cpp2a/lambda-targ3.C: New test.
	* g++.dg/cpp2a/lambda-targ4.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
Comment 4 Patrick Palka 2024-04-12 19:21:11 UTC
Fixed for GCC 14.