From patchwork Thu Jul 31 17:36:05 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Carlini X-Patchwork-Id: 375368 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3E4FE1400E0 for ; Fri, 1 Aug 2014 03:36:38 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; q=dns; s=default; b=q22DCZ/mr7fEHdYAf9R6gvc+SszjqWnIQ2DMqCmZG7p 3d/buFrH9yZi1jkrjq2k9ruascpeCKlbX07lkT5jAYmdF09SN3fX4pS0hrbQFydd m+9tk+Tvh50ksDjE76L7f6U9FpzsbhNCsNnULimFCUvhiwLRmom5xUBvOW+a8FTc = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; s=default; bh=pnUMF9wvcNn3h8KOZu2AQb8Uj8A=; b=PNDjAyblUHvBFnFdl lcc2cy/Zu9tI6xfxamil83X3OKShjFNqoNOkp2WJMfzMRy/N1EOadaV1Gyj0dqHA wcHdpYIHEV6oZ5Bzd0ybn1h0q9SGciYp4GCHidA4s+6L5TJ0Gl45vpLGiAeWIHDi EY8zCxIULQYBMPqNr/+xJYYMwg= Received: (qmail 24732 invoked by alias); 31 Jul 2014 17:36:15 -0000 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 Received: (qmail 24651 invoked by uid 89); 31 Jul 2014 17:36:15 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.6 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 X-HELO: userp1040.oracle.com Received: from userp1040.oracle.com (HELO userp1040.oracle.com) (156.151.31.81) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Thu, 31 Jul 2014 17:36:12 +0000 Received: from ucsinet22.oracle.com (ucsinet22.oracle.com [156.151.31.94]) by userp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id s6VHa9B1015105 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 31 Jul 2014 17:36:10 GMT Received: from aserz7021.oracle.com (aserz7021.oracle.com [141.146.126.230]) by ucsinet22.oracle.com (8.14.5+Sun/8.14.5) with ESMTP id s6VHa8UV014179 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 31 Jul 2014 17:36:09 GMT Received: from abhmp0018.oracle.com (abhmp0018.oracle.com [141.146.116.24]) by aserz7021.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id s6VHa8dZ014369; Thu, 31 Jul 2014 17:36:08 GMT Received: from [192.168.1.4] (/79.12.219.173) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 31 Jul 2014 10:36:08 -0700 Message-ID: <53DA7E85.1000806@oracle.com> Date: Thu, 31 Jul 2014 19:36:05 +0200 From: Paolo Carlini User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.6.0 MIME-Version: 1.0 To: "gcc-patches@gcc.gnu.org" CC: Jason Merrill Subject: [C++ Patch] DR 217 follow up (and more) X-IsSubscribed: yes Hi, today I noticed that when we implemented the resolution we failed to handle static member functions. The below tested x86_64-linux. While working on this I noticed that we don't use the DECL_NONSTATIC_MEMBER_FUNCTION_P macro much, should we apply something like the attached? Finally, if you are wondering instead how I noticed the former ;) I have been working on c++/15339, which seems relatively easy to resolve. Ie, rejecting in duplicate_decls template void fun(int); template void fun(int = 0); however, handling correctly the member case: class A { template void fun(int); }; template void A::fun(int = 0) { } is more tricky because we don't want to start rejecting: class A { void fun(int); }; void A::fun(int = 0) { } which is well formed. The problem is that when grokfndecl calls duplicate_decls in such member cases it looks through TEMPLATE_DECLs, eg: if (TREE_CODE (old_decl) == TEMPLATE_DECL) /* Because grokfndecl is always supposed to return a FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT here. We depend on our callers to figure out that its really a template that's being returned. */ old_decl = DECL_TEMPLATE_RESULT (old_decl); and then telling apart the two cases above is tough, both are FUNCTION_DECLs :( Ideas about the best way to handle that? Anything less delicate than trying *not* to use DECL_TEMPLATE_RESULT that early and passing the TEMPLATE_DECLs as they are to duplicate_decls and then using it only right before returning from grokfndecl? Thanks! Paolo. /////////////////////////// /cp 2014-07-31 Paolo Carlini DR 217 again * decl.c (duplicate_decls): Handle static member functions too. /testsuite 2014-07-31 Paolo Carlini DR 217 again * g++.dg/tc1/dr217-2.C: New. Index: call.c =================================================================== --- call.c (revision 213379) +++ call.c (working copy) @@ -7038,7 +7038,7 @@ build_over_call (struct z_candidate *cand, int fla } } /* Bypass access control for 'this' parameter. */ - else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE) + else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) { tree parmtype = TREE_VALUE (parm); tree arg = build_this (first_arg != NULL_TREE @@ -8026,7 +8026,7 @@ build_new_method_call_1 (tree instance, tree fns, fn); } - if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) && !DECL_CONSTRUCTOR_P (fn) && is_dummy_object (instance)) { @@ -8071,7 +8071,7 @@ build_new_method_call_1 (tree instance, tree fns, /* In an expression of the form `a->f()' where `f' turns out to be a static member function, `a' is none-the-less evaluated. */ - if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE + if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) && !is_dummy_object (instance) && TREE_SIDE_EFFECTS (instance)) call = build2 (COMPOUND_EXPR, TREE_TYPE (call), Index: class.c =================================================================== --- class.c (revision 213379) +++ class.c (working copy) @@ -7306,7 +7306,7 @@ resolve_address_of_overloaded_function (tree targe pointer-to-member types, not the internal POINTER_TYPE to METHOD_TYPE representation. */ gcc_assert (!TYPE_PTR_P (target_type) - || TREE_CODE (TREE_TYPE (target_type)) != METHOD_TYPE); + || !DECL_NONSTATIC_MEMBER_FUNCTION_P (target_type)); gcc_assert (is_overloaded_fn (overload)); @@ -7355,8 +7355,7 @@ resolve_address_of_overloaded_function (tree targe /* We're not looking for templates just yet. */ continue; - if ((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE) - != is_ptrmem) + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) != is_ptrmem) /* We're looking for a non-static member, and this isn't one, or vice versa. */ continue; @@ -7405,8 +7404,7 @@ resolve_address_of_overloaded_function (tree targe /* We're only looking for templates. */ continue; - if ((TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE) - != is_ptrmem) + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) != is_ptrmem) /* We're not looking for a non-static member, and this is one, or vice versa. */ continue; Index: cp-tree.h =================================================================== --- cp-tree.h (revision 213379) +++ cp-tree.h (working copy) @@ -3555,7 +3555,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_a #define TYPE_PTROBV_P(NODE) \ (TYPE_PTR_P (NODE) \ && !(TREE_CODE (TREE_TYPE (NODE)) == FUNCTION_TYPE \ - || TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE)) + || DECL_NONSTATIC_MEMBER_FUNCTION_P (NODE))) /* Returns true if NODE is a pointer to function. */ #define TYPE_PTRFN_P(NODE) \ Index: cvt.c =================================================================== --- cvt.c (revision 213379) +++ cvt.c (working copy) @@ -1475,7 +1475,7 @@ convert_force (tree type, tree expr, int convtype, /* From typeck.c convert_for_assignment */ if (((TYPE_PTR_P (TREE_TYPE (e)) && TREE_CODE (e) == ADDR_EXPR - && TREE_CODE (TREE_TYPE (TREE_TYPE (e))) == METHOD_TYPE) + && DECL_NONSTATIC_MEMBER_FUNCTION_P (TREE_TYPE (e))) || integer_zerop (e) || TYPE_PTRMEMFUNC_P (TREE_TYPE (e))) && TYPE_PTRMEMFUNC_P (type)) Index: decl.c =================================================================== --- decl.c (revision 213379) +++ decl.c (working copy) @@ -7849,7 +7849,7 @@ grokfndecl (tree ctype, old_decl = DECL_TEMPLATE_RESULT (old_decl); if (DECL_STATIC_FUNCTION_P (old_decl) - && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) + && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) { /* Remove the `this' parm added by grokclassfn. */ revert_static_member_fn (decl); @@ -11525,7 +11525,7 @@ grok_op_properties (tree decl, bool complain) { tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl)); tree argtype; - int methodp = (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE); + int methodp = DECL_NONSTATIC_MEMBER_FUNCTION_P (decl); tree name = DECL_NAME (decl); enum tree_code operator_code; int arity; @@ -13205,7 +13205,7 @@ start_preparsed_function (tree decl1, tree attrs, /* Sometimes we don't notice that a function is a static member, and build a METHOD_TYPE for it. Fix that up now. */ gcc_assert (!(ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1) - && TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE)); + && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1))); /* Set up current_class_type, and enter the scope of the class, if appropriate. */ Index: decl2.c =================================================================== --- decl2.c (revision 213379) +++ decl2.c (working copy) @@ -691,7 +691,7 @@ check_classfn (tree ctype, tree function, tree tem /* Get rid of the this parameter on functions that become static. */ if (DECL_STATIC_FUNCTION_P (fndecl) - && TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE) + && DECL_NONSTATIC_MEMBER_FUNCTION_P (function)) p1 = TREE_CHAIN (p1); /* A member template definition only matches a member template @@ -957,7 +957,7 @@ grokfield (const cp_declarator *declarator, } else if (TREE_CODE (init) == DEFAULT_ARG) error ("invalid initializer for member function %qD", value); - else if (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE) + else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (value)) { if (integer_zerop (init)) DECL_PURE_VIRTUAL_P (value) = 1; @@ -4728,7 +4728,7 @@ build_offset_ref_call_from_tree (tree fn, vec { if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE - || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE) + || DECL_NONSTATIC_MEMBER_FUNCTION_P (val)) val = decay_conversion (val, complain); } @@ -5151,7 +5151,7 @@ build_x_unary_op (location_t loc, enum tree_code c /* A pointer to member-function can be formed only by saying &X::mf. */ - if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE + if (!flag_ms_extensions && DECL_NONSTATIC_MEMBER_FUNCTION_P (xarg) && (TREE_CODE (xarg) != OFFSET_REF || !PTRMEM_OK_P (xarg))) { if (TREE_CODE (xarg) != OFFSET_REF @@ -5183,7 +5183,7 @@ build_x_unary_op (location_t loc, enum tree_code c ptrmem = PTRMEM_OK_P (xarg); if (!ptrmem && !flag_ms_extensions - && TREE_CODE (TREE_TYPE (TREE_OPERAND (xarg, 1))) == METHOD_TYPE) + && DECL_NONSTATIC_MEMBER_FUNCTION_P (TREE_OPERAND (xarg, 1))) { /* A single non-static member, make sure we don't allow a pointer-to-member. */ @@ -5545,7 +5545,7 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue } if (TYPE_PTR_P (argtype) - && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE) + && DECL_NONSTATIC_MEMBER_FUNCTION_P (argtype)) { build_ptrmemfunc_type (argtype); val = build_ptrmemfunc (argtype, val, 0, @@ -5937,7 +5937,7 @@ unary_complex_lvalue (enum tree_code code, tree ar } if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE - || TREE_CODE (TREE_TYPE (arg)) == METHOD_TYPE + || DECL_NONSTATIC_MEMBER_FUNCTION_P (arg) || TREE_CODE (arg) == OFFSET_REF) return NULL_TREE; @@ -7473,7 +7473,7 @@ cp_build_modify_expr (tree lhs, enum tree_code mod /* Functions are not modifiable, even though they are lvalues. */ || TREE_CODE (TREE_TYPE (lhs)) == FUNCTION_TYPE - || TREE_CODE (TREE_TYPE (lhs)) == METHOD_TYPE + || DECL_NONSTATIC_MEMBER_FUNCTION_P (lhs) /* If it's an aggregate and any field is const, then it is effectively const. */ || (CLASS_TYPE_P (lhstype) @@ -8245,7 +8245,7 @@ convert_for_initialization (tree exp, tree type, t || TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE)) || (TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE && !TYPE_REFFN_P (type)) - || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE) + || DECL_NONSTATIC_MEMBER_FUNCTION_P (rhs)) rhs = decay_conversion (rhs, complain); rhstype = TREE_TYPE (rhs); Index: typeck2.c =================================================================== --- typeck2.c (revision 213379) +++ typeck2.c (working copy) @@ -338,7 +338,7 @@ abstract_virtuals_error_sfinae (tree decl, tree ty error ("cannot declare field %q+D to be of abstract type %qT", decl, type); else if (TREE_CODE (decl) == FUNCTION_DECL - && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) + && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) error ("invalid abstract return type for member function %q+#D", decl); else if (TREE_CODE (decl) == FUNCTION_DECL) error ("invalid abstract return type for function %q+#D", decl); Index: cp/decl.c =================================================================== --- cp/decl.c (revision 213379) +++ cp/decl.c (working copy) @@ -1710,10 +1710,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool tree t2 = TYPE_ARG_TYPES (TREE_TYPE (newdecl)); int i = 1; - if (TREE_CODE (TREE_TYPE (newdecl)) == METHOD_TYPE) + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (newdecl)) t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2); - if (TREE_CODE (TREE_TYPE (newdecl)) == METHOD_TYPE + if (DECL_FUNCTION_MEMBER_P (newdecl) && CLASSTYPE_TEMPLATE_INFO (CP_DECL_CONTEXT (newdecl))) { /* C++11 8.3.6/6. Index: testsuite/g++.dg/tc1/dr217-2.C =================================================================== --- testsuite/g++.dg/tc1/dr217-2.C (revision 0) +++ testsuite/g++.dg/tc1/dr217-2.C (working copy) @@ -0,0 +1,13 @@ +// { dg-do compile } +// DR217: Default arguments for non-template member functions of class +// templates + +template +struct S +{ + static void foo (int); +}; + +template +void S::foo (int = 0) // { dg-error "" "default arguments for parameters of member functions of class templates can be specified in the initial declaration only" } +{ }