From: Jason Merrill Date: Fri, 8 Mar 2013 16:03:48 +0000 (-0500) Subject: re PR c++/51494 (Legal program rejection - capturing "this" when using static method... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0ef811d71e69f732716e92c81d157aa1c88e7e22;p=gcc.git 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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 14647610e4f..f9731a5538e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,15 @@ 2013-03-08 Jason Merrill + 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. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4eb38ec73e9..530835b87c8 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -7627,6 +7627,7 @@ build_new_method_call_1 (tree instance, tree fns, vec **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 **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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4a597d8b3a6..c3b2aecf3b1 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index d605de9631f..d11a4e4b218 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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. */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index b57b44ad149..178b80aa24f 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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); diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this11.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this11.C new file mode 100644 index 00000000000..2618295662e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this11.C @@ -0,0 +1,22 @@ +// 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; + }; + } +};