re PR c++/63207 (ICE in expand_expr_real_l when instantiating a template with a lambda that captures a const variable with a dependent initializer)
PR c++/63207 * semantics.c (outer_var_p): Non-static. (process_outer_var_ref): Split out from finish_id_expression. * pt.c (tsubst_copy_and_build): Call them. * cp-tree.h: Declare them. From-SVN: r216056
This commit is contained in:
parent
018e891a75
commit
548cb3d77c
5 changed files with 129 additions and 85 deletions
|
@ -1,3 +1,11 @@
|
|||
2014-10-09 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/63207
|
||||
* semantics.c (outer_var_p): Non-static.
|
||||
(process_outer_var_ref): Split out from finish_id_expression.
|
||||
* pt.c (tsubst_copy_and_build): Call them.
|
||||
* cp-tree.h: Declare them.
|
||||
|
||||
2014-10-09 Paolo Carlini <paolo.carlini@oracle.com>
|
||||
|
||||
* semantics.c (check_constexpr_ctor_body_1): New.
|
||||
|
|
|
@ -5879,6 +5879,8 @@ extern void finish_template_decl (tree);
|
|||
extern tree finish_template_type (tree, tree, int);
|
||||
extern tree finish_base_specifier (tree, tree, bool);
|
||||
extern void finish_member_declaration (tree);
|
||||
extern bool outer_automatic_var_p (tree);
|
||||
extern tree process_outer_var_ref (tree, tsubst_flags_t);
|
||||
extern tree finish_id_expression (tree, tree, tree,
|
||||
cp_id_kind *,
|
||||
bool, bool, bool *,
|
||||
|
|
|
@ -15460,6 +15460,7 @@ tsubst_copy_and_build (tree t,
|
|||
case PARM_DECL:
|
||||
{
|
||||
tree r = tsubst_copy (t, args, complain, in_decl);
|
||||
/* ??? We're doing a subset of finish_id_expression here. */
|
||||
if (VAR_P (r)
|
||||
&& !processing_template_decl
|
||||
&& !cp_unevaluated_operand
|
||||
|
@ -15471,6 +15472,8 @@ tsubst_copy_and_build (tree t,
|
|||
a call to its wrapper. */
|
||||
r = build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
|
||||
}
|
||||
else if (outer_automatic_var_p (r))
|
||||
r = process_outer_var_ref (r, complain);
|
||||
|
||||
if (TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
|
||||
/* If the original type was a reference, we'll be wrapped in
|
||||
|
|
|
@ -3067,13 +3067,105 @@ outer_var_p (tree decl)
|
|||
|
||||
/* As above, but also checks that DECL is automatic. */
|
||||
|
||||
static bool
|
||||
bool
|
||||
outer_automatic_var_p (tree decl)
|
||||
{
|
||||
return (outer_var_p (decl)
|
||||
&& !TREE_STATIC (decl));
|
||||
}
|
||||
|
||||
/* DECL satisfies outer_automatic_var_p. Possibly complain about it or
|
||||
rewrite it for lambda capture. */
|
||||
|
||||
tree
|
||||
process_outer_var_ref (tree decl, tsubst_flags_t complain)
|
||||
{
|
||||
if (cp_unevaluated_operand)
|
||||
/* It's not a use (3.2) if we're in an unevaluated context. */
|
||||
return decl;
|
||||
|
||||
tree context = DECL_CONTEXT (decl);
|
||||
tree containing_function = current_function_decl;
|
||||
tree lambda_stack = NULL_TREE;
|
||||
tree lambda_expr = NULL_TREE;
|
||||
tree initializer = convert_from_reference (decl);
|
||||
|
||||
/* Mark it as used now even if the use is ill-formed. */
|
||||
mark_used (decl);
|
||||
|
||||
/* 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))
|
||||
return integral_constant_value (decl);
|
||||
}
|
||||
|
||||
if (parsing_nsdmi ())
|
||||
containing_function = NULL_TREE;
|
||||
else
|
||||
/* If we are in a lambda function, we can move out until we hit
|
||||
1. the context,
|
||||
2. a non-lambda function, or
|
||||
3. a non-default capturing lambda function. */
|
||||
while (context != containing_function
|
||||
&& LAMBDA_FUNCTION_P (containing_function))
|
||||
{
|
||||
lambda_expr = CLASSTYPE_LAMBDA_EXPR
|
||||
(DECL_CONTEXT (containing_function));
|
||||
|
||||
if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr)
|
||||
== CPLD_NONE)
|
||||
break;
|
||||
|
||||
lambda_stack = tree_cons (NULL_TREE,
|
||||
lambda_expr,
|
||||
lambda_stack);
|
||||
|
||||
containing_function
|
||||
= decl_function_context (containing_function);
|
||||
}
|
||||
|
||||
if (lambda_expr && TREE_CODE (decl) == VAR_DECL
|
||||
&& DECL_ANON_UNION_VAR_P (decl))
|
||||
{
|
||||
if (complain & tf_error)
|
||||
error ("cannot capture member %qD of anonymous union", decl);
|
||||
return error_mark_node;
|
||||
}
|
||||
if (context == containing_function)
|
||||
{
|
||||
decl = add_default_capture (lambda_stack,
|
||||
/*id=*/DECL_NAME (decl),
|
||||
initializer);
|
||||
}
|
||||
else if (lambda_expr)
|
||||
{
|
||||
if (complain & tf_error)
|
||||
error ("%qD is not captured", decl);
|
||||
return error_mark_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (complain & tf_error)
|
||||
error (VAR_P (decl)
|
||||
? G_("use of local variable with automatic storage from containing function")
|
||||
: G_("use of parameter from containing function"));
|
||||
inform (input_location, "%q+#D declared here", decl);
|
||||
return error_mark_node;
|
||||
}
|
||||
return decl;
|
||||
}
|
||||
|
||||
/* ID_EXPRESSION is a representation of parsed, but unprocessed,
|
||||
id-expression. (See cp_parser_id_expression for details.) SCOPE,
|
||||
if non-NULL, is the type or namespace used to explicitly qualify
|
||||
|
@ -3179,90 +3271,8 @@ finish_id_expression (tree id_expression,
|
|||
|
||||
/* Disallow uses of local variables from containing functions, except
|
||||
within lambda-expressions. */
|
||||
if (!outer_var_p (decl))
|
||||
/* OK */;
|
||||
else if (TREE_STATIC (decl)
|
||||
/* It's not a use (3.2) if we're in an unevaluated context. */
|
||||
|| cp_unevaluated_operand)
|
||||
/* OK */;
|
||||
else
|
||||
{
|
||||
tree context = DECL_CONTEXT (decl);
|
||||
tree containing_function = current_function_decl;
|
||||
tree lambda_stack = NULL_TREE;
|
||||
tree lambda_expr = NULL_TREE;
|
||||
tree initializer = convert_from_reference (decl);
|
||||
|
||||
/* Mark it as used now even if the use is ill-formed. */
|
||||
mark_used (decl);
|
||||
|
||||
/* 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))
|
||||
return integral_constant_value (decl);
|
||||
}
|
||||
|
||||
if (parsing_nsdmi ())
|
||||
containing_function = NULL_TREE;
|
||||
/* If we are in a lambda function, we can move out until we hit
|
||||
1. the context,
|
||||
2. a non-lambda function, or
|
||||
3. a non-default capturing lambda function. */
|
||||
else while (context != containing_function
|
||||
&& LAMBDA_FUNCTION_P (containing_function))
|
||||
{
|
||||
lambda_expr = CLASSTYPE_LAMBDA_EXPR
|
||||
(DECL_CONTEXT (containing_function));
|
||||
|
||||
if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr)
|
||||
== CPLD_NONE)
|
||||
break;
|
||||
|
||||
lambda_stack = tree_cons (NULL_TREE,
|
||||
lambda_expr,
|
||||
lambda_stack);
|
||||
|
||||
containing_function
|
||||
= decl_function_context (containing_function);
|
||||
}
|
||||
|
||||
if (lambda_expr && TREE_CODE (decl) == VAR_DECL
|
||||
&& DECL_ANON_UNION_VAR_P (decl))
|
||||
{
|
||||
error ("cannot capture member %qD of anonymous union", decl);
|
||||
return error_mark_node;
|
||||
}
|
||||
if (context == containing_function)
|
||||
{
|
||||
decl = add_default_capture (lambda_stack,
|
||||
/*id=*/DECL_NAME (decl),
|
||||
initializer);
|
||||
}
|
||||
else if (lambda_expr)
|
||||
{
|
||||
error ("%qD is not captured", decl);
|
||||
return error_mark_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
error (VAR_P (decl)
|
||||
? G_("use of local variable with automatic storage from containing function")
|
||||
: G_("use of parameter from containing function"));
|
||||
inform (input_location, "%q+#D declared here", decl);
|
||||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
if (outer_automatic_var_p (decl))
|
||||
decl = process_outer_var_ref (decl, tf_warning_or_error);
|
||||
|
||||
/* Also disallow uses of function parameters outside the function
|
||||
body, except inside an unevaluated context (i.e. decltype). */
|
||||
|
|
21
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const4.C
Normal file
21
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const4.C
Normal file
|
@ -0,0 +1,21 @@
|
|||
// PR c++/63207
|
||||
// { dg-do run { target c++11 } }
|
||||
|
||||
template <typename T>
|
||||
struct Base {
|
||||
T value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Test : Base<T> {
|
||||
T test() {
|
||||
const int x = this->value;
|
||||
return ([&]{ return x; })();
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
Test<int> t;
|
||||
t.value = 0;
|
||||
return t.test();
|
||||
}
|
Loading…
Add table
Reference in a new issue