aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2018-06-15 16:22:44 -0400
committerJason Merrill <jason@gcc.gnu.org>2018-06-15 16:22:44 -0400
commit582f844c6e30e59ac5641a04cfb7fdd1aff78c66 (patch)
treee8d7988ab646f3a4845371fd779e5edee4b9690b /gcc
parent508f1cb51f5872f425a3d4eb3ab8bf5a76a692ac (diff)
downloadgcc-582f844c6e30e59ac5641a04cfb7fdd1aff78c66.zip
gcc-582f844c6e30e59ac5641a04cfb7fdd1aff78c66.tar.gz
gcc-582f844c6e30e59ac5641a04cfb7fdd1aff78c66.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: r261654
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/lambda.c18
-rw-r--r--gcc/cp/name-lookup.c8
-rw-r--r--gcc/cp/pt.c6
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg8.C24
6 files changed, 62 insertions, 1 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 2679ca6..f6c6908 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-14 Marek Polacek <polacek@redhat.com>
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9a50d66..3566668 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 231490f..3776d6b 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 8d1748a..7990029 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 ba78d2e..ed634dd 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 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();
+}