Commit 43b781fa by Jason Merrill Committed by Jason Merrill

re PR c++/60992 (ICE in tsubst_copy, at cp/pt.c:12637)

	PR c++/60992
	* lambda.c (lambda_capture_field_type): Wrap anything dependent
	other than 'this'.
	(add_capture): Check for VLA before calling it.
	* semantics.c (is_this_parameter): Accept any 'this' parameter, not
	just the current one.  Make non-static.
	* cp-tree.h: Declare it.
	* pt.c (tsubst_copy) [VAR_DECL]: Also build a new VAR_DECL if
	the operand was static or constant.

From-SVN: r210017
parent 62da5a07
2014-05-02 Jason Merrill <jason@redhat.com>
PR c++/60992
* lambda.c (lambda_capture_field_type): Wrap anything dependent
other than 'this'.
(add_capture): Check for VLA before calling it.
* semantics.c (is_this_parameter): Accept any 'this' parameter, not
just the current one. Make non-static.
* cp-tree.h: Declare it.
* pt.c (tsubst_copy) [VAR_DECL]: Also build a new VAR_DECL if
the operand was static or constant.
2014-05-02 Marek Polacek <polacek@redhat.com>
* typeck.c (maybe_warn_about_returning_address_of_local): Separate
......
......@@ -5773,6 +5773,7 @@ extern bool is_sub_constant_expr (tree);
extern bool reduced_constant_expression_p (tree);
extern void explain_invalid_constexpr_fn (tree);
extern vec<tree> cx_error_context (void);
extern bool is_this_parameter (tree);
enum {
BCS_NO_SCOPE = 1,
......
......@@ -216,8 +216,8 @@ lambda_capture_field_type (tree expr, bool explicit_init_p)
}
else
type = non_reference (unlowered_expr_type (expr));
if (!type || WILDCARD_TYPE_P (type) || type_uses_auto (type)
|| DECL_PACK_P (expr))
if (type_dependent_expression_p (expr)
&& !is_this_parameter (tree_strip_nop_conversions (expr)))
{
type = cxx_make_type (DECLTYPE_TYPE);
DECLTYPE_TYPE_EXPR (type) = expr;
......@@ -455,7 +455,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
if (TREE_CODE (initializer) == TREE_LIST)
initializer = build_x_compound_expr_from_list (initializer, ELK_INIT,
tf_warning_or_error);
type = lambda_capture_field_type (initializer, explicit_init_p);
type = TREE_TYPE (initializer);
if (array_of_runtime_bound_p (type))
{
vla = true;
......@@ -482,15 +482,19 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
"variable size", TREE_TYPE (type));
type = error_mark_node;
}
else if (by_reference_p)
else
{
type = build_reference_type (type);
if (!real_lvalue_p (initializer))
error ("cannot capture %qE by reference", initializer);
type = lambda_capture_field_type (initializer, explicit_init_p);
if (by_reference_p)
{
type = build_reference_type (type);
if (!real_lvalue_p (initializer))
error ("cannot capture %qE by reference", initializer);
}
else
/* Capture by copy requires a complete type. */
type = complete_type (type);
}
else
/* Capture by copy requires a complete type. */
type = complete_type (type);
/* Add __ to the beginning of the field name so that user code
won't find the field with name lookup. We can't just leave the name
......
......@@ -12629,13 +12629,17 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
}
else
{
/* This can happen for a variable used in a late-specified
return type of a local lambda. Just make a dummy decl
since it's only used for its type. */
if (cp_unevaluated_operand)
return tsubst_decl (t, args, complain);
gcc_assert (errorcount || sorrycount);
return error_mark_node;
/* This can happen for a variable used in a
late-specified return type of a local lambda, or for a
local static or constant. Building a new VAR_DECL
should be OK in all those cases. */
r = tsubst_decl (t, args, complain);
if (decl_constant_var_p (r))
/* A use of a local constant must decay to its value. */
return integral_constant_value (r);
gcc_assert (cp_unevaluated_operand || TREE_STATIC (r)
|| errorcount || sorrycount);
return r;
}
}
}
......
......@@ -8155,10 +8155,11 @@ maybe_initialize_constexpr_call_table (void)
/* Return true if T designates the implied `this' parameter. */
static inline bool
bool
is_this_parameter (tree t)
{
return t == current_class_ptr;
return (TREE_CODE (t) == PARM_DECL
&& DECL_NAME (t) == this_identifier);
}
/* We have an expression tree T that represents a call, either CALL_EXPR
......
// PR c++/60992
// { dg-do compile { target c++11 } }
struct ScopeGuardGenerator { };
struct FF
{
template < class F, class ... Ts >
void
operator () (F & ...)
{
const int n = sizeof ... (Ts) + 1;
void *mutexes[n];
auto _on_scope_exit_var_0 =
ScopeGuardGenerator () + [&mutexes] { };
}
};
template < class F >
int operator+ (ScopeGuardGenerator, F) { return 1; }
struct D
{
template < class T0, class T1, class T2, class ... T >
void
operator () (T0, T1, const T2 & t2, T & ... t)
{
base (t2, t ...);
}
FF base;
};
D run_with_locks;
void Fn ()
{
run_with_locks ([] { }, 0, 0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment