Commit 0ef811d7 by Jason Merrill Committed by Jason Merrill

re PR c++/51494 (Legal program rejection - capturing "this" when using static method inside lambda)

	PR c++/51494
	PR c++/51884
	PR c++/56222
	* tree.c (maybe_dummy_object): Don't capture 'this'.
	* semantics.c (maybe_resolve_dummy): New.
	(finish_non_static_data_member): Use it.
	(finish_qualified_id_expr): Don't test is_dummy_object.
	* cp-tree.h: Declare maybe_resolve_dummy.
	* call.c (build_new_method_call_1): Use it.

From-SVN: r196549
parent e48243d8
2013-03-08 Jason Merrill <jason@redhat.com>
PR c++/51494
PR c++/51884
PR c++/56222
* tree.c (maybe_dummy_object): Don't capture 'this'.
* semantics.c (maybe_resolve_dummy): New.
(finish_non_static_data_member): Use it.
(finish_qualified_id_expr): Don't test is_dummy_object.
* cp-tree.h: Declare maybe_resolve_dummy.
* call.c (build_new_method_call_1): Use it.
PR c++/56567
* semantics.c (apply_deduced_return_type): Don't allow returning
std::initializer_list.
......
......@@ -7627,6 +7627,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
else
{
fn = cand->fn;
call = NULL_TREE;
if (!(flags & LOOKUP_NONVIRTUAL)
&& DECL_PURE_VIRTUAL_P (fn)
......@@ -7644,12 +7645,26 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
&& is_dummy_object (instance_ptr))
{
if (complain & tf_error)
error ("cannot call member function %qD without object",
fn);
call = error_mark_node;
instance = maybe_resolve_dummy (instance);
if (instance == error_mark_node)
call = error_mark_node;
else if (!is_dummy_object (instance))
{
/* We captured 'this' in the current lambda now that
we know we really need it. */
instance_ptr = build_this (instance);
cand->first_arg = instance_ptr;
}
else
{
if (complain & tf_error)
error ("cannot call member function %qD without object",
fn);
call = error_mark_node;
}
}
else
if (call != error_mark_node)
{
/* Optimize away vtable lookup if we know that this
function can't be overridden. We need to check if
......
......@@ -5722,6 +5722,7 @@ extern bool is_capture_proxy (tree);
extern bool is_normal_capture_proxy (tree);
extern void register_capture_members (tree);
extern tree lambda_expr_this_capture (tree);
extern tree maybe_resolve_dummy (tree);
extern tree nonlambda_method_basetype (void);
extern void maybe_add_lambda_conv_op (tree);
extern bool is_lambda_ignored_entity (tree);
......
......@@ -1544,6 +1544,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
object = maybe_dummy_object (scope, NULL);
}
object = maybe_resolve_dummy (object);
if (object == error_mark_node)
return error_mark_node;
......@@ -1778,15 +1779,14 @@ finish_qualified_id_expr (tree qualifying_class,
}
else if (BASELINK_P (expr) && !processing_template_decl)
{
tree ob;
/* See if any of the functions are non-static members. */
/* If so, the expression may be relative to 'this'. */
if (!shared_member_p (expr)
&& (ob = maybe_dummy_object (qualifying_class, NULL),
!is_dummy_object (ob)))
&& current_class_ptr
&& DERIVED_FROM_P (qualifying_class,
current_nonlambda_class_type ()))
expr = (build_class_member_access_expr
(ob,
(maybe_dummy_object (qualifying_class, NULL),
expr,
BASELINK_ACCESS_BINFO (expr),
/*preserve_reference=*/false,
......@@ -9534,6 +9534,34 @@ lambda_expr_this_capture (tree lambda)
return result;
}
/* We don't want to capture 'this' until we know we need it, i.e. after
overload resolution has chosen a non-static member function. At that
point we call this function to turn a dummy object into a use of the
'this' capture. */
tree
maybe_resolve_dummy (tree object)
{
if (!is_dummy_object (object))
return object;
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (object));
gcc_assert (TREE_CODE (type) != POINTER_TYPE);
if (type != current_class_type
&& current_class_type
&& LAMBDA_TYPE_P (current_class_type))
{
/* In a lambda, need to go through 'this' capture. */
tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type);
tree cap = lambda_expr_this_capture (lam);
object = build_x_indirect_ref (EXPR_LOCATION (object), cap,
RO_NULL, tf_warning_or_error);
}
return object;
}
/* Returns the method basetype of the innermost non-lambda function, or
NULL_TREE if none. */
......
......@@ -2863,13 +2863,6 @@ maybe_dummy_object (tree type, tree* binfop)
&& (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (current_class_ref), context)))
decl = current_class_ref;
else if (current != current_class_type
&& context == nonlambda_method_basetype ())
/* In a lambda, need to go through 'this' capture. */
decl = (build_x_indirect_ref
(input_location, (lambda_expr_this_capture
(CLASSTYPE_LAMBDA_EXPR (current_class_type))),
RO_NULL, tf_warning_or_error));
else
decl = build_dummy_object (context);
......
// PR c++/51494, c++/56222
// Uses of static members and creating pointers to members aren't odr-uses
// of 'this'.
// { dg-do compile { target c++11 } }
struct A
{
static void f() {}
static int i;
int j;
void f(int);
void foo()
{
[] () {
++i;
f();
&A::j;
(void(*)())&A::f;
};
}
};
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