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> 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 PR c++/56567
* semantics.c (apply_deduced_return_type): Don't allow returning * semantics.c (apply_deduced_return_type): Don't allow returning
std::initializer_list. std::initializer_list.
......
...@@ -7627,6 +7627,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args, ...@@ -7627,6 +7627,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
else else
{ {
fn = cand->fn; fn = cand->fn;
call = NULL_TREE;
if (!(flags & LOOKUP_NONVIRTUAL) if (!(flags & LOOKUP_NONVIRTUAL)
&& DECL_PURE_VIRTUAL_P (fn) && DECL_PURE_VIRTUAL_P (fn)
...@@ -7644,12 +7645,26 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args, ...@@ -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 if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
&& is_dummy_object (instance_ptr)) && is_dummy_object (instance_ptr))
{ {
if (complain & tf_error) instance = maybe_resolve_dummy (instance);
error ("cannot call member function %qD without object", if (instance == error_mark_node)
fn); call = 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 /* Optimize away vtable lookup if we know that this
function can't be overridden. We need to check if function can't be overridden. We need to check if
......
...@@ -5722,6 +5722,7 @@ extern bool is_capture_proxy (tree); ...@@ -5722,6 +5722,7 @@ extern bool is_capture_proxy (tree);
extern bool is_normal_capture_proxy (tree); extern bool is_normal_capture_proxy (tree);
extern void register_capture_members (tree); extern void register_capture_members (tree);
extern tree lambda_expr_this_capture (tree); extern tree lambda_expr_this_capture (tree);
extern tree maybe_resolve_dummy (tree);
extern tree nonlambda_method_basetype (void); extern tree nonlambda_method_basetype (void);
extern void maybe_add_lambda_conv_op (tree); extern void maybe_add_lambda_conv_op (tree);
extern bool is_lambda_ignored_entity (tree); extern bool is_lambda_ignored_entity (tree);
......
...@@ -1544,6 +1544,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) ...@@ -1544,6 +1544,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
object = maybe_dummy_object (scope, NULL); object = maybe_dummy_object (scope, NULL);
} }
object = maybe_resolve_dummy (object);
if (object == error_mark_node) if (object == error_mark_node)
return error_mark_node; return error_mark_node;
...@@ -1778,15 +1779,14 @@ finish_qualified_id_expr (tree qualifying_class, ...@@ -1778,15 +1779,14 @@ finish_qualified_id_expr (tree qualifying_class,
} }
else if (BASELINK_P (expr) && !processing_template_decl) else if (BASELINK_P (expr) && !processing_template_decl)
{ {
tree ob;
/* See if any of the functions are non-static members. */ /* See if any of the functions are non-static members. */
/* If so, the expression may be relative to 'this'. */ /* If so, the expression may be relative to 'this'. */
if (!shared_member_p (expr) if (!shared_member_p (expr)
&& (ob = maybe_dummy_object (qualifying_class, NULL), && current_class_ptr
!is_dummy_object (ob))) && DERIVED_FROM_P (qualifying_class,
current_nonlambda_class_type ()))
expr = (build_class_member_access_expr expr = (build_class_member_access_expr
(ob, (maybe_dummy_object (qualifying_class, NULL),
expr, expr,
BASELINK_ACCESS_BINFO (expr), BASELINK_ACCESS_BINFO (expr),
/*preserve_reference=*/false, /*preserve_reference=*/false,
...@@ -9534,6 +9534,34 @@ lambda_expr_this_capture (tree lambda) ...@@ -9534,6 +9534,34 @@ lambda_expr_this_capture (tree lambda)
return result; 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 /* Returns the method basetype of the innermost non-lambda function, or
NULL_TREE if none. */ NULL_TREE if none. */
......
...@@ -2863,13 +2863,6 @@ maybe_dummy_object (tree type, tree* binfop) ...@@ -2863,13 +2863,6 @@ maybe_dummy_object (tree type, tree* binfop)
&& (same_type_ignoring_top_level_qualifiers_p && (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (current_class_ref), context))) (TREE_TYPE (current_class_ref), context)))
decl = current_class_ref; 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 else
decl = build_dummy_object (context); 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