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:
parent
b6b9902193
commit
72013ec51a
|
@ -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.
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
22
gcc/cp/pt.c
22
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
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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>();
|
||||
}
|
Loading…
Reference in New Issue