commit 58322f8d0b0892ac66d184cc933655e135d324af Author: Jason Merrill Date: Tue Mar 5 12:09:52 2013 -0500 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. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4eb38ec..530835b 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 4a597d8..c3b2aec 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 d605de9..d11a4e4 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 b57b44a..178b80a 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 0000000..2618295 --- /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; + }; + } +}; commit 977321fdf969a16e3546e044bc2c1404b0565804 Author: Jason Merrill Date: Tue Mar 5 12:03:06 2013 -0500 * semantics.c (lambda_expr_this_capture): In unevaluated context, just return the nearest 'this'. diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index d11a4e4..233765a 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9513,6 +9513,11 @@ lambda_expr_this_capture (tree lambda) if (!this_capture) { + /* In unevaluated context this isn't an odr-use, so just return the + nearest 'this'. */ + if (cp_unevaluated_operand) + return lookup_name (this_identifier); + error ("% was not captured for this lambda function"); result = error_mark_node; } diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this12.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this12.C new file mode 100644 index 0000000..ef573b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this12.C @@ -0,0 +1,13 @@ +// Uses of 'this' in unevaluated context are not odr-uses. +// { dg-do compile { target c++11 } } + +struct A +{ + int f() {} + int i; + + void foo() + { + [] () { sizeof(i); sizeof(f()); }; + } +}; commit a5f8c7b4fb99d4f02201cd7eaa0bac518b2a4695 Author: Jason Merrill Date: Wed Mar 6 09:27:22 2013 -0500 PR c++/51884 * class.c (modify_all_vtables): Mangle the vtable name before entering dfs_walk. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 2a0351f..746c29d 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2541,6 +2541,10 @@ modify_all_vtables (tree t, tree virtuals) tree binfo = TYPE_BINFO (t); tree *fnsp; + /* Mangle the vtable name before entering dfs_walk (c++/51884). */ + if (TYPE_CONTAINS_VPTR_P (t)) + get_vtable_decl (t, false); + /* Update all of the vtables. */ dfs_walk_once (binfo, dfs_modify_vtables, NULL, t); diff --git a/gcc/testsuite/g++.dg/cpp0x/local-targ1.C b/gcc/testsuite/g++.dg/cpp0x/local-targ1.C new file mode 100644 index 0000000..588149a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/local-targ1.C @@ -0,0 +1,31 @@ +// PR c++/51884 +// { dg-do compile { target c++11 } } +// { dg-final { scan-assembler "_ZN1BIZN3fooIivE3barILb1EEEvvE1CEC1ERKS4_" } } + +template + struct test { static const int value = 0; }; +template + struct enable_if { typedef void type; }; + +struct A { virtual void f() {} }; +template struct B : A { B(); B(const B&); }; +template B::B() { } +template B::B(const B&) { } + +template void g(T) { } + +template struct foo; +template +struct foo::value>::type> +{ + template void bar() { + struct C { } c; + B b; + g(b); + } +}; + +int main() { + foo f; + f.bar(); +}