diff options
author | Jason Merrill <jason@redhat.com> | 2018-06-15 16:23:13 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2018-06-15 16:23:13 -0400 |
commit | 81e209fa51aba11027ed457d7f28e87a6f3d9151 (patch) | |
tree | d679e78c56194c12032e733fefb066e82e9581d3 /gcc | |
parent | a0df74de13ca559f2085f758c377636b18355c1f (diff) | |
download | gcc-81e209fa51aba11027ed457d7f28e87a6f3d9151.zip gcc-81e209fa51aba11027ed457d7f28e87a6f3d9151.tar.gz gcc-81e209fa51aba11027ed457d7f28e87a6f3d9151.tar.bz2 |
PR c++/82882 - ICE with lambda in template default argument.
* lambda.c (record_null_lambda_scope): New.
* pt.c (tsubst_lambda_expr): Use it.
* name-lookup.c (do_pushtag): Don't give a lambda DECL_CONTEXT of a
function that isn't open.
From-SVN: r261658
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/lambda.c | 18 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 8 | ||||
-rw-r--r-- | gcc/cp/pt.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg8.C | 24 |
6 files changed, 62 insertions, 1 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e64c0c0..59f3b46 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2018-06-15 Jason Merrill <jason@redhat.com> + PR c++/82882 - ICE with lambda in template default argument. + * lambda.c (record_null_lambda_scope): New. + * pt.c (tsubst_lambda_expr): Use it. + * name-lookup.c (do_pushtag): Don't give a lambda DECL_CONTEXT of a + function that isn't open. + * tree.c (maybe_warn_parm_abi): Inform the location of the class. 2018-06-13 Jason Merrill <jason@redhat.com> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a327f8c..57e6718 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7036,6 +7036,7 @@ extern tree finish_builtin_launder (location_t, tree, tsubst_flags_t); extern void start_lambda_scope (tree); extern void record_lambda_scope (tree); +extern void record_null_lambda_scope (tree); extern void finish_lambda_scope (void); extern tree start_lambda_function (tree fn, tree lambda_expr); extern void finish_lambda_function (tree body); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 9190b6e..4dbda5b 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -1380,6 +1380,24 @@ record_lambda_scope (tree lambda) LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++; } +/* This lambda is an instantiation of a lambda in a template default argument + that got no LAMBDA_EXPR_EXTRA_SCOPE, so this shouldn't either. But we do + need to use and increment the global count to avoid collisions. */ + +void +record_null_lambda_scope (tree lambda) +{ + if (vec_safe_is_empty (lambda_scope_stack)) + record_lambda_scope (lambda); + else + { + tree_int *p = lambda_scope_stack->begin(); + LAMBDA_EXPR_EXTRA_SCOPE (lambda) = p->t; + LAMBDA_EXPR_DISCRIMINATOR (lambda) = p->i++; + } + gcc_assert (LAMBDA_EXPR_EXTRA_SCOPE (lambda) == NULL_TREE); +} + void finish_lambda_scope (void) { diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 95a07b5..f678cbb 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -6624,6 +6624,14 @@ do_pushtag (tree name, tree type, tag_scope scope) { tree cs = current_scope (); + /* Avoid setting the lambda context to a current_function_decl that + we aren't actually inside, e.g. one set by push_access_scope + during tsubst_default_argument. */ + if (cs && TREE_CODE (cs) == FUNCTION_DECL + && LAMBDA_TYPE_P (type) + && !at_function_scope_p ()) + cs = DECL_CONTEXT (cs); + if (scope == ts_current || (cs && TREE_CODE (cs) == FUNCTION_DECL)) context = cs; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5db4f3c..48e1235 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17529,7 +17529,11 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t); if (LAMBDA_EXPR_EXTRA_SCOPE (t) == NULL_TREE) - LAMBDA_EXPR_EXTRA_SCOPE (r) = NULL_TREE; + /* A lambda in a default argument outside a class gets no + LAMBDA_EXPR_EXTRA_SCOPE, as specified by the ABI. But + tsubst_default_argument calls start_lambda_scope, so we need to + specifically ignore it here, and use the global scope. */ + record_null_lambda_scope (r); else record_lambda_scope (r); diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg8.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg8.C new file mode 100644 index 0000000..cf842ad --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg8.C @@ -0,0 +1,24 @@ +// PR c++/82282 +// { dg-do compile { target c++14 } } + +template<typename = int> +void f(const char* a = + ([](int = []{ static int i; return 42; }()) { + static int i; + return ""; + }())); + +template<typename = int> +struct X { + void f(const char* a = + ([](int = [] { static int i; return 42; }()) { + enum { Size = 42 - 1 }; + return ""; + }())); +}; + +void g() +{ + f(); + X<int>().f(); +} |