From patchwork Sun Aug 28 15:38:29 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 111910 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 AA2D9B6F81 for ; Mon, 29 Aug 2011 01:39:03 +1000 (EST) Received: (qmail 20105 invoked by alias); 28 Aug 2011 15:38:59 -0000 Received: (qmail 20097 invoked by uid 22791); 28 Aug 2011 15:38:58 -0000 X-SWARE-Spam-Status: No, hits=-6.6 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS, TW_CX 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; Sun, 28 Aug 2011 15:38:31 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p7SFcVlk005713 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Sun, 28 Aug 2011 11:38:31 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p7SFcUfq019884 for ; Sun, 28 Aug 2011 11:38:30 -0400 Received: from [0.0.0.0] (ovpn-113-55.phx2.redhat.com [10.3.113.55]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id p7SFcTxL009389 for ; Sun, 28 Aug 2011 11:38:30 -0400 Message-ID: <4E5A60F5.6010701@redhat.com> Date: Sun, 28 Aug 2011 11:38:29 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux i686; rv:5.0) Gecko/20110719 Thunderbird/5.0 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for c++/48582 (core 342: null pointer values as template non-type arguments) 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 DR 342 allows null pointer values as non-type arguments in C++11; this patch implements that. We mangle such arguments as a cast from 0 like the EDG compiler does. Tested x86_64-pc-linux-gnu, applying to trunk. commit c51119b8511eb6988e59c7decdd4c3817b9074bb Author: Jason Merrill Date: Fri Aug 26 22:38:12 2011 -0400 Core DR 342 PR c++/48582 * pt.c (check_valid_ptrmem_cst_expr): A null member pointer value is valid in C++11. (convert_nontype_argument): Likewise. Implicitly convert nullptr and do constant folding. * mangle.c (write_template_arg_literal): Mangle null member pointer values as 0. * call.c (null_member_pointer_value_p): New. * cp-tree.h: Declare it. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index dc35824..8421260 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -553,6 +553,23 @@ null_ptr_cst_p (tree t) return false; } +/* Returns true iff T is a null member pointer value (4.11). */ + +bool +null_member_pointer_value_p (tree t) +{ + tree type = TREE_TYPE (t); + if (!type) + return false; + else if (TYPE_PTRMEMFUNC_P (type)) + return (TREE_CODE (t) == CONSTRUCTOR + && integer_zerop (CONSTRUCTOR_ELT (t, 0)->value)); + else if (TYPE_PTRMEM_P (type)) + return integer_all_onesp (t); + else + return false; +} + /* Returns nonzero if PARMLIST consists of only default parms, ellipsis, and/or undeduced parameter packs. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8595943..d125642 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4722,6 +4722,7 @@ extern tree build_addr_func (tree); extern tree build_call_a (tree, int, tree*); extern tree build_call_n (tree, int, ...); extern bool null_ptr_cst_p (tree); +extern bool null_member_pointer_value_p (tree); extern bool sufficient_parms_p (const_tree); extern tree type_decays_to (tree); extern tree build_user_type_conversion (tree, tree, int); diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 4c7cc79..1fcd999 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2762,29 +2762,34 @@ write_template_arg_literal (const tree value) write_char ('L'); write_type (TREE_TYPE (value)); - switch (TREE_CODE (value)) - { - case CONST_DECL: - write_integer_cst (DECL_INITIAL (value)); - break; + /* Write a null member pointer value as (type)0, regardless of its + real representation. */ + if (null_member_pointer_value_p (value)) + write_integer_cst (integer_zero_node); + else + switch (TREE_CODE (value)) + { + case CONST_DECL: + write_integer_cst (DECL_INITIAL (value)); + break; - case INTEGER_CST: - gcc_assert (!same_type_p (TREE_TYPE (value), boolean_type_node) - || integer_zerop (value) || integer_onep (value)); - write_integer_cst (value); - break; + case INTEGER_CST: + gcc_assert (!same_type_p (TREE_TYPE (value), boolean_type_node) + || integer_zerop (value) || integer_onep (value)); + write_integer_cst (value); + break; - case REAL_CST: - write_real_cst (value); - break; + case REAL_CST: + write_real_cst (value); + break; - case STRING_CST: - sorry ("string literal in function template signature"); - break; + case STRING_CST: + sorry ("string literal in function template signature"); + break; - default: - gcc_unreachable (); - } + default: + gcc_unreachable (); + } write_char ('E'); } @@ -2845,7 +2850,8 @@ write_template_arg (tree node) /* A template appearing as a template arg is a template template arg. */ write_template_template_arg (node); else if ((TREE_CODE_CLASS (code) == tcc_constant && code != PTRMEM_CST) - || (abi_version_at_least (2) && code == CONST_DECL)) + || (abi_version_at_least (2) && code == CONST_DECL) + || null_member_pointer_value_p (node)) write_template_arg_literal (node); else if (DECL_P (node)) { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3c6b2c5..1f43ff1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5240,6 +5240,8 @@ check_valid_ptrmem_cst_expr (tree type, tree expr, STRIP_NOPS (expr); if (expr && (null_ptr_cst_p (expr) || TREE_CODE (expr) == PTRMEM_CST)) return true; + if (cxx_dialect >= cxx0x && null_member_pointer_value_p (expr)) + return true; if (complain & tf_error) { error ("%qE is not a valid template argument for type %qT", @@ -5550,6 +5552,17 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) else expr = mark_rvalue_use (expr); + /* 14.3.2/5: The null pointer{,-to-member} conversion is applied + to a non-type argument of "nullptr". */ + if (expr == nullptr_node + && (TYPE_PTR_P (type) || TYPE_PTR_TO_MEMBER_P (type))) + expr = convert (type, expr); + + /* In C++11, non-type template arguments can be arbitrary constant + expressions. But don't fold a PTRMEM_CST to a CONSTRUCTOR yet. */ + if (cxx_dialect >= cxx0x && TREE_CODE (expr) != PTRMEM_CST) + expr = maybe_constant_value (expr); + /* HACK: Due to double coercion, we can get a NOP_EXPR(ADDR_EXPR (arg)) here, which is the tree that we built on the first call (see @@ -5658,6 +5671,8 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) if (DECL_P (expr) && DECL_TEMPLATE_PARM_P (expr)) /* Non-type template parameters are OK. */ ; + else if (cxx_dialect >= cxx0x && integer_zerop (expr)) + /* Null pointer values are OK in C++11. */; else if (TREE_CODE (expr) != ADDR_EXPR && TREE_CODE (expr_type) != ARRAY_TYPE) { @@ -5785,6 +5800,10 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) return error_mark_node; } + if (cxx_dialect >= cxx0x && integer_zerop (expr)) + /* Null pointer values are OK in C++11. */ + return perform_qualification_conversions (type, expr); + expr = convert_nontype_argument_function (type, expr); if (!expr || expr == error_mark_node) return expr; diff --git a/gcc/testsuite/g++.dg/abi/mangle50.C b/gcc/testsuite/g++.dg/abi/mangle50.C new file mode 100644 index 0000000..df7afb9 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle50.C @@ -0,0 +1,25 @@ +// DR 342, PR c++/48582 +// { dg-options -std=c++0x } + +struct A; +template < void * = nullptr > void f() { } +template < void (A::*)() = nullptr > void g() { } +template < int A::* = nullptr > void h() { } + +int main() +{ + // { dg-final { scan-assembler "_Z1fILPv0EEvv" } } + f(); + f(); + + // { dg-final { scan-assembler "_Z1gILM1AFvvE0EEvv" } } + g(); + g(); + + // { dg-final { scan-assembler "_Z1fILPv0EEvv" } } + h(); + h(); + + constexpr void * ptr = nullptr; + f(); +}