aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2015-12-20 13:38:37 -0500
committerJason Merrill <jason@gcc.gnu.org>2015-12-20 13:38:37 -0500
commit72013ec51a97b6a709ac96845a247119e4602254 (patch)
tree59fd6f52890fff5dd866d968ff4681528d076072 /gcc
parentb6b990219342543d804a269a5409091a93e6d2ea (diff)
downloadgcc-72013ec51a97b6a709ac96845a247119e4602254.zip
gcc-72013ec51a97b6a709ac96845a247119e4602254.tar.gz
gcc-72013ec51a97b6a709ac96845a247119e4602254.tar.bz2
re PR c++/67411 (internal compiler error: in tsubst_copy, at cp/pt.c:13473)
PR c++/67411 * lambda.c (generic_lambda_fn_p): Split out from... (maybe_add_lambda_conv_op): ...here. * semantics.c (process_outer_var_ref): Don't defer maybe-constant variables in a generic lambda. * pt.c (instantiate_non_dependent_or_null): New. * init.c (constant_value_1): Use it. * cp-tree.h: Declare it and generic_lambda_fn_p. From-SVN: r231863
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog9
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/init.c2
-rw-r--r--gcc/cp/lambda.c14
-rw-r--r--gcc/cp/pt.c22
-rw-r--r--gcc/cp/semantics.c54
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-const2.C19
7 files changed, 98 insertions, 24 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 40ae390..e7adad3 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,6 +1,15 @@
2015-12-20 Jason Merrill <jason@redhat.com>
PR c++/67411
+ * lambda.c (generic_lambda_fn_p): Split out from...
+ (maybe_add_lambda_conv_op): ...here.
+ * semantics.c (process_outer_var_ref): Don't defer maybe-constant
+ variables in a generic lambda.
+ * pt.c (instantiate_non_dependent_or_null): New.
+ * init.c (constant_value_1): Use it.
+ * cp-tree.h: Declare it and generic_lambda_fn_p.
+
+ PR c++/67411
* decl2.c (decl_maybe_constant_var_p): A proxy isn't constant.
2015-12-18 Patrick Palka <ppalka@gcc.gnu.org>
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 058324f..f0f7e36c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6158,6 +6158,7 @@ extern bool reregister_specialization (tree, tree, tree);
extern tree instantiate_non_dependent_expr (tree);
extern tree instantiate_non_dependent_expr_sfinae (tree, tsubst_flags_t);
extern tree instantiate_non_dependent_expr_internal (tree, tsubst_flags_t);
+extern tree instantiate_non_dependent_or_null (tree);
extern bool variable_template_specialization_p (tree);
extern bool alias_type_or_template_p (tree);
extern bool alias_template_specialization_p (const_tree);
@@ -6473,6 +6474,7 @@ extern tree maybe_resolve_dummy (tree, bool);
extern tree current_nonlambda_function (void);
extern tree nonlambda_method_basetype (void);
extern tree current_nonlambda_scope (void);
+extern bool generic_lambda_fn_p (tree);
extern void maybe_add_lambda_conv_op (tree);
extern bool is_lambda_ignored_entity (tree);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 1d5cc65..09c1183 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2080,6 +2080,8 @@ constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p)
&& TREE_CODE (init) == TREE_LIST
&& TREE_CHAIN (init) == NULL_TREE)
init = TREE_VALUE (init);
+ /* Instantiate a non-dependent initializer. */
+ init = instantiate_non_dependent_or_null (init);
if (!init
|| !TREE_TYPE (init)
|| !TREE_CONSTANT (init)
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 8d1ee14..d50e48d 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -851,6 +851,16 @@ prepare_op_call (tree fn, int nargs)
return t;
}
+/* Return true iff CALLOP is the op() for a generic lambda. */
+
+bool
+generic_lambda_fn_p (tree callop)
+{
+ return (LAMBDA_FUNCTION_P (callop)
+ && DECL_TEMPLATE_INFO (callop)
+ && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (callop)));
+}
+
/* If the closure TYPE has a static op(), also add a conversion to function
pointer. */
@@ -867,9 +877,7 @@ maybe_add_lambda_conv_op (tree type)
if (processing_template_decl)
return;
- bool const generic_lambda_p
- = (DECL_TEMPLATE_INFO (callop)
- && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop);
+ bool const generic_lambda_p = generic_lambda_fn_p (callop);
if (!generic_lambda_p && DECL_INITIAL (callop) == NULL_TREE)
{
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index da57fb2..209e65f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5661,6 +5661,28 @@ instantiate_non_dependent_expr (tree expr)
return instantiate_non_dependent_expr_sfinae (expr, tf_error);
}
+/* Like instantiate_non_dependent_expr, but return NULL_TREE rather than
+ an uninstantiated expression. */
+
+tree
+instantiate_non_dependent_or_null (tree expr)
+{
+ if (expr == NULL_TREE)
+ return NULL_TREE;
+ if (processing_template_decl)
+ {
+ if (instantiation_dependent_expression_p (expr)
+ || !potential_constant_expression (expr))
+ expr = NULL_TREE;
+ else
+ {
+ processing_template_decl_sentinel s;
+ expr = instantiate_non_dependent_expr_internal (expr, tf_error);
+ }
+ }
+ return expr;
+}
+
/* True iff T is a specialization of a variable template. */
bool
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index b8f4e8f..ab9989a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3231,27 +3231,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)
if (!mark_used (decl, complain) && !(complain & tf_error))
return error_mark_node;
- /* Core issue 696: "[At the July 2009 meeting] the CWG expressed
- support for an approach in which a reference to a local
- [constant] automatic variable in a nested class or lambda body
- would enter the expression as an rvalue, which would reduce
- the complexity of the problem"
-
- FIXME update for final resolution of core issue 696. */
- if (decl_maybe_constant_var_p (decl))
- {
- if (processing_template_decl)
- /* In a template, the constant value may not be in a usable
- form, so wait until instantiation time. */
- return decl;
- else if (decl_constant_var_p (decl))
- {
- tree t = maybe_constant_value (convert_from_reference (decl));
- if (TREE_CONSTANT (t))
- return t;
- }
- }
-
+ bool saw_generic_lambda = false;
if (parsing_nsdmi ())
containing_function = NULL_TREE;
else
@@ -3265,6 +3245,9 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)
tree closure = DECL_CONTEXT (containing_function);
lambda_expr = CLASSTYPE_LAMBDA_EXPR (closure);
+ if (generic_lambda_fn_p (containing_function))
+ saw_generic_lambda = true;
+
if (TYPE_CLASS_SCOPE_P (closure))
/* A lambda in an NSDMI (c++/64496). */
break;
@@ -3281,6 +3264,35 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)
= decl_function_context (containing_function);
}
+ /* Core issue 696: "[At the July 2009 meeting] the CWG expressed
+ support for an approach in which a reference to a local
+ [constant] automatic variable in a nested class or lambda body
+ would enter the expression as an rvalue, which would reduce
+ the complexity of the problem"
+
+ FIXME update for final resolution of core issue 696. */
+ if (decl_maybe_constant_var_p (decl))
+ {
+ if (processing_template_decl && !saw_generic_lambda)
+ /* In a non-generic lambda within a template, wait until instantiation
+ time to decide whether to capture. For a generic lambda, we can't
+ wait until we instantiate the op() because the closure class is
+ already defined at that point. FIXME to get the semantics exactly
+ right we need to partially-instantiate the lambda body so the only
+ dependencies left are on the generic parameters themselves. This
+ probably means moving away from our current model of lambdas in
+ templates (instantiating the closure type) to one based on creating
+ the closure type when instantiating the lambda context. That is
+ probably also the way to handle lambdas within pack expansions. */
+ return decl;
+ else if (decl_constant_var_p (decl))
+ {
+ tree t = maybe_constant_value (convert_from_reference (decl));
+ if (TREE_CONSTANT (t))
+ return t;
+ }
+ }
+
if (lambda_expr && VAR_P (decl)
&& DECL_ANON_UNION_VAR_P (decl))
{
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const2.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const2.C
new file mode 100644
index 0000000..9a00e22
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const2.C
@@ -0,0 +1,19 @@
+// PR c++/67411
+// { dg-do compile { target c++14 } }
+
+template <class T>
+void f()
+{
+ int i = 42;
+ [=] {
+ const int x = i;
+ [&](auto) {
+ [=] { return x; }();
+ }(1);
+ }();
+}
+
+int main()
+{
+ f<int>();
+}