From patchwork Fri Jan 20 04:41:35 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 717465 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 3v4Sjw2Mg6z9sXx for ; Fri, 20 Jan 2017 15:42:26 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="CEr7cmKs"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=UNUDUH1bXiGUqsh2hood+GNvJk7DwiPXwAMlrAlOuIVuEY ug2A1cTZooFku+Ws9LIQ/2CZTJO2meOJBtZ9Piy5pIXy++js1tMVl4m3eqYjP/qV WzpXlzVwmftUBCJ+iE54snkwQ6OFr10fRDpjfctwDzheZm3NRxt5sF1tqoA7E= 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 :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=KyT+KG4zFtjcJfAc4xCcSspr508=; b=CEr7cmKsRWU0rtZ0+eqj CnmKfyaPY9xwc28PtkO5HQzyI772dRohmmUAwpfxdNntUzMVLV3Cej+R+Jsg3nTT oFhyBkJ0zRAtc5KpokOK7eUoqNwa40y3vO7PDwIc8Zhn3NYL4MUf6EWFAWCzqGPT xSDIG13F+L8qctL3s1hPe5o= Received: (qmail 9488 invoked by alias); 20 Jan 2017 04:42: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 9361 invoked by uid 89); 20 Jan 2017 04:41:57 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-HELO: mail-ot0-f173.google.com Received: from mail-ot0-f173.google.com (HELO mail-ot0-f173.google.com) (74.125.82.173) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 20 Jan 2017 04:41:57 +0000 Received: by mail-ot0-f173.google.com with SMTP id 73so48128059otj.0 for ; Thu, 19 Jan 2017 20:41:57 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=bLbii2kRt0Ql0YIJlfo4sO7GUPcHMaji4hxQngCouEM=; b=dLgCqnKZ7TKv/w412z3EiceGgpPz9qbZwAKHD7PUVlwPxGwJJmC5kuM7fm30ZVqd8O OLDkZIv5uJa0tkv/jNqJm8/VHG0LAXSQ4x+E/LHfFqXgycTkJN070MI0LL4/mZKCC06p gLAJmp9WgBPTuFUBqJX+jxHF2HFVid2+CgiGKP67hGDY87UzhxRdK9rIV61hxmJSmKV9 3yLXjzBPS0zkiaBZPnwUuUpJTJRYM7tR5X/H0eEJAl6Kf61mJGeP9VBlHqckLq5PDlkF I2wBId/NpjbSzG3aOi2yoTEGuUwbj3Kmolz48Hfwq/QduieD0mrAGpv6WGUaNytR9VZO wZLw== X-Gm-Message-State: AIkVDXJm7YkvOIU5LwXG0I+MsV9C49brq/T4bWfQ0tUXbJWYSSzXwp32b5CzkqurXhPRyTGQa1vghQ4U5ITRlBpy X-Received: by 10.157.35.20 with SMTP id j20mr5513609otb.241.1484887315843; Thu, 19 Jan 2017 20:41:55 -0800 (PST) MIME-Version: 1.0 Received: by 10.182.173.104 with HTTP; Thu, 19 Jan 2017 20:41:35 -0800 (PST) From: Jason Merrill Date: Thu, 19 Jan 2017 23:41:35 -0500 Message-ID: Subject: C++ PATCH for C++17 class deduction issues US 19/20 To: gcc-patches List X-IsSubscribed: yes wg21.link/p0512r0 proposes resolutions for some issues with class template argument deduction raised in national body comments against the C++17 draft; the paper hasn't been accepted yet, but the proposals seem sensible, so I'm implementing them here. The first makes deduction guides take priority over constructors, to make deduction guides more useful. The second clarifies the "forwarding reference" rules to not apply to class template argument deduction; we don't want a constructor like A(T&&) to lead to deduction of A. Tested x86_64-pc-linux-gnu, applying to trunk. commit d3b00e36dc65288897c39cbedb5b570fe937ae23 Author: Jason Merrill Date: Thu Jan 19 14:47:56 2017 -0500 US 19 - deduction guides and constructors * call.c (joust): Prefer deduction guides to constructors. * pt.c (build_deduction_guide): Set DECL_ARTIFICIAL. (deduction_guide_p): Check DECL_P. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 88d83dd..0059a39 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9633,6 +9633,18 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, return winner; } + /* F1 is generated from a deduction-guide (13.3.1.8) and F2 is not */ + if (deduction_guide_p (cand1->fn)) + { + gcc_assert (deduction_guide_p (cand2->fn)); + /* We distinguish between candidates from an explicit deduction guide and + candidates built from a constructor based on DECL_ARTIFICIAL. */ + int art1 = DECL_ARTIFICIAL (cand1->fn); + int art2 = DECL_ARTIFICIAL (cand2->fn); + if (art1 != art2) + return art2 - art1; + } + /* or, if not that, F1 is a non-template function and F2 is a template function specialization. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index c679133..f683727 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -24776,8 +24776,9 @@ dguide_name_p (tree name) bool deduction_guide_p (tree fn) { - if (tree name = DECL_NAME (fn)) - return dguide_name_p (name); + if (DECL_P (fn)) + if (tree name = DECL_NAME (fn)) + return dguide_name_p (name); return false; } @@ -24981,7 +24982,9 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) FUNCTION_DECL, dguide_name (type), fntype); DECL_ARGUMENTS (ded_fn) = fargs; + DECL_ARTIFICIAL (ded_fn) = true; tree ded_tmpl = build_template_decl (ded_fn, tparms, /*member*/false); + DECL_ARTIFICIAL (ded_tmpl) = true; DECL_TEMPLATE_RESULT (ded_tmpl) = ded_fn; TREE_TYPE (ded_tmpl) = TREE_TYPE (ded_fn); DECL_TEMPLATE_INFO (ded_fn) = build_template_info (ded_tmpl, targs); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction25.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction25.C new file mode 100644 index 0000000..07ab5f5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction25.C @@ -0,0 +1,24 @@ +// Testcase from P0512R0 for C++17 NB comment US 19 +// { dg-options -std=c++1z } + +template struct remove_ref; +template struct remove_ref { typedef _Tp type; }; +template struct remove_ref<_Tp&> { typedef _Tp type; }; +template struct remove_ref<_Tp&&> { typedef _Tp type; }; +template using remove_ref_t = typename remove_ref<_Tp>::type; + +template struct A { + A(T, int*); // #1 + A(A&, int*); // #2 + enum { value }; +}; +template::value> A(T&&, int*) -> A; //#3 + +A a{1,0}; // uses #1 to deduce A and initializes with #1 +A b{a,0}; // uses #3 (not #2) to deduce A&> and initializes with #1 + +template struct same; +template struct same {}; + +same> s1; +same&>> s2; commit 0709587b7c94c96b56d3d303e86fc65cee762ce3 Author: Jason Merrill Date: Thu Jan 19 15:17:38 2017 -0500 US 20 - forwarding references and class template argument deduction * cp-tree.h (TEMPLATE_TYPE_PARM_FOR_CLASS): New. * pt.c (push_template_decl_real): Set it. (maybe_adjust_types_for_deduction): Check it. (rewrite_template_parm): Copy it. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9c44367..f7c7a35 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -146,6 +146,7 @@ operator == (const cp_expr &lhs, tree rhs) BLOCK_OUTER_CURLY_BRACE_P (in BLOCK) FOLD_EXPR_MODOP_P (*_FOLD_EXPR) IF_STMT_CONSTEXPR_P (IF_STMT) + TEMPLATE_TYPE_PARM_FOR_CLASS (TEMPLATE_TYPE_PARM) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -5207,6 +5208,11 @@ enum auto_deduction_context adc_decomp_type /* Decomposition declaration initializer deduction */ }; +/* True if this type-parameter belongs to a class template, used by C++17 + class template argument deduction. */ +#define TEMPLATE_TYPE_PARM_FOR_CLASS(NODE) \ + (TREE_LANG_FLAG_0 (TEMPLATE_TYPE_PARM_CHECK (NODE))) + /* True iff this TEMPLATE_TYPE_PARM represents decltype(auto). */ #define AUTO_IS_DECLTYPE(NODE) \ (TYPE_LANG_FLAG_5 (TEMPLATE_TYPE_PARM_CHECK (NODE))) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f683727..8c920c3 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5263,7 +5263,18 @@ push_template_decl_real (tree decl, bool is_friend) } else if (DECL_IMPLICIT_TYPEDEF_P (decl) && CLASS_TYPE_P (TREE_TYPE (decl))) - /* OK */; + { + /* Class template, set TEMPLATE_TYPE_PARM_FOR_CLASS. */ + tree parms = INNERMOST_TEMPLATE_PARMS (current_template_parms); + for (int i = 0; i < TREE_VEC_LENGTH (parms); ++i) + { + tree t = TREE_VALUE (TREE_VEC_ELT (parms, i)); + if (TREE_CODE (t) == TYPE_DECL) + t = TREE_TYPE (t); + if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) + TEMPLATE_TYPE_PARM_FOR_CLASS (t) = true; + } + } else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_ALIAS_P (decl)) /* alias-declaration */ @@ -18649,12 +18660,16 @@ maybe_adjust_types_for_deduction (unification_kind_t strict, *arg = TYPE_MAIN_VARIANT (*arg); } - /* From C++0x [14.8.2.1/3 temp.deduct.call] (after DR606), "If P is - of the form T&&, where T is a template parameter, and the argument - is an lvalue, T is deduced as A& */ + /* [14.8.2.1/3 temp.deduct.call], "A forwarding reference is an rvalue + reference to a cv-unqualified template parameter that does not represent a + template parameter of a class template (during class template argument + deduction (13.3.1.8)). If P is a forwarding reference and the argument is + an lvalue, the type "lvalue reference to A" is used in place of A for type + deduction. */ if (TREE_CODE (*parm) == REFERENCE_TYPE && TYPE_REF_IS_RVALUE (*parm) && TREE_CODE (TREE_TYPE (*parm)) == TEMPLATE_TYPE_PARM + && !TEMPLATE_TYPE_PARM_FOR_CLASS (TREE_TYPE (*parm)) && cp_type_quals (TREE_TYPE (*parm)) == TYPE_UNQUALIFIED && (arg_expr ? lvalue_p (arg_expr) /* try_one_overload doesn't provide an arg_expr, but @@ -24798,8 +24813,12 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level, if (TREE_CODE (olddecl) == TYPE_DECL || TREE_CODE (olddecl) == TEMPLATE_DECL) { - newtype = cxx_make_type (TREE_CODE (TREE_TYPE (olddecl))); + tree oldtype = TREE_TYPE (olddecl); + newtype = cxx_make_type (TREE_CODE (oldtype)); TYPE_MAIN_VARIANT (newtype) = newtype; + if (TREE_CODE (oldtype) == TEMPLATE_TYPE_PARM) + TEMPLATE_TYPE_PARM_FOR_CLASS (newtype) + = TEMPLATE_TYPE_PARM_FOR_CLASS (oldtype); } else newtype = tsubst (TREE_TYPE (olddecl), tsubst_args, diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction26.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction26.C new file mode 100644 index 0000000..ea58af7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction26.C @@ -0,0 +1,23 @@ +// Testcase from P0512R0 for C++17 NB comment US 20 +// { dg-options -std=c++1z } + +template struct same; +template struct same {}; + +template struct A { + template + A(T&&, U&&, int*); // #1: T&& is not a forwarding reference + // U&& is a forwarding reference + A(T&&, int*); // #2 +}; +template +A(T&&, int*) -> A; // #3: T&& is a forwarding reference + +int i; +int *ip; +A a0{0, 0, ip}; // uses #1 to deduce A and #1 to initialize +same> s1; +A a2{i, ip}; // uses #3 to deduce A and #2 to initialize +same> s2; + +A a{i, 0, ip}; // { dg-error "" } cannot deduce from #1