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
This commit is contained in:
Jason Merrill 2015-12-20 13:38:37 -05:00 committed by Jason Merrill
parent b6b9902193
commit 72013ec51a
7 changed files with 98 additions and 24 deletions

View File

@ -1,5 +1,14 @@
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.

View File

@ -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);

View File

@ -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)

View File

@ -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)
{

View File

@ -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

View File

@ -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))
{

View File

@ -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>();
}