From 582f844c6e30e59ac5641a04cfb7fdd1aff78c66 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 15 Jun 2018 16:22:44 -0400 Subject: [PATCH] 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: r261654 --- gcc/cp/ChangeLog | 6 +++++ gcc/cp/cp-tree.h | 1 + gcc/cp/lambda.c | 18 ++++++++++++++ gcc/cp/name-lookup.c | 8 +++++++ gcc/cp/pt.c | 6 ++++- .../g++.dg/cpp0x/lambda/lambda-defarg8.C | 24 +++++++++++++++++++ 6 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg8.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2679ca6f1e8..f6c69087ce2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2018-06-15 Jason Merrill + 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-14 Marek Polacek diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9a50d666cad..3566668efef 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7018,6 +7018,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 231490fbe4e..3776d6bcea9 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 8d1748a285a..7990029d70c 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -6542,6 +6542,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 ba78d2e34a5..ed634ddeefb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17530,7 +17530,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 00000000000..cf842ad9dd1 --- /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 +void f(const char* a = + ([](int = []{ static int i; return 42; }()) { + static int i; + return ""; + }())); + +template +struct X { + void f(const char* a = + ([](int = [] { static int i; return 42; }()) { + enum { Size = 42 - 1 }; + return ""; + }())); +}; + +void g() +{ + f(); + X().f(); +} -- 2.30.2