From patchwork Fri Mar 8 16:03:47 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 226161 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 057AE2C0307 for ; Sat, 9 Mar 2013 03:04:42 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1363363483; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Message-ID:Date:From:User-Agent:MIME-Version:To:Subject: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=OPhUKj1 WAj3iUVMA2G5vESjclwQ=; b=g3A/MTQZ1oMet9bef496TRnLoCxYiwzn2RW+t5y /zkgbWSds3RTkvvbeA/aLcIPHq4NS+51OunHuHievmAFupZqI0qLSuHV3Zwou0R0 fKzTjH4KFBt94jtPnHAyy20k2YhUpZxMwOvRiHySSE4YOnlUZgUZqVpN2Vx7ZkmP ZZ8k= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Message-ID:Date:From:User-Agent:MIME-Version:To:Subject:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=Kgdk4wlayr7iG2YMrSGPmdgiz3BV0ZOusvbKfoljJO0E4JeH6ilb7xbSdxrPbj o0s1Z0NCcJ2Xb2cQrfep1TvkvWLE7OYLy9v9h3qkN9b/lRB12NJNaSZd3iG/2hkL mTdzJnqeY6VAeDxjKhcCIo5CdA0aWSpZOx/1Jqj6GCz9E=; Received: (qmail 10100 invoked by alias); 8 Mar 2013 16:04:13 -0000 Received: (qmail 10042 invoked by uid 22791); 8 Mar 2013 16:04:11 -0000 X-SWARE-Spam-Status: No, hits=-6.6 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, KHOP_SPAMHAUS_DROP, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_W, RP_MATCHES_RCVD, SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 08 Mar 2013 16:03:48 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r28G3m2F019337 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 8 Mar 2013 11:03:48 -0500 Received: from [10.3.113.56] (ovpn-113-56.phx2.redhat.com [10.3.113.56]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r28G3lrn005161 for ; Fri, 8 Mar 2013 11:03:47 -0500 Message-ID: <513A0BE3.8000501@redhat.com> Date: Fri, 08 Mar 2013 11:03:47 -0500 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux i686; rv:21.0) Gecko/20100101 Thunderbird/21.0a2 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for various lambda bugs (51494, 51884, 56222, 51884) Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org The first two patches deal with issues with 'this' capture; we were inappropriately capturing 'this' for uses of static members and forming pointers to members, and for uses in unevaluated context. The last patch avoids a crash from recursive use of dfs_walk when instantiating a class with virtual functions using a local class whose scope involves a qualified-id. Tested x86_64-pc-linux-gnu, applying to trunk. 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(); +}