From patchwork Fri Mar 3 01:26:36 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 734881 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 3vZBPN5jZ6z9s7j for ; Fri, 3 Mar 2017 12:27:18 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="xlQSTvXR"; 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:in-reply-to:references:from:date:message-id :subject:to:content-type; q=dns; s=default; b=gZ85BJIDyUmrJ3bsdf iNLFaJ+/HgJ9rO3dp172qJMpcfmvHSIcwH1Ayr2lUtg3e8VjhX5D8iIurfg2bOm8 tYD8wMmgqk5O7OV0E3Pt92hpL+8UpeQWIrBaV4xqoWDT/V/IH4sowOm+Qb3dJesi zd4a/OZH35yNw75SgN5T75UWs= 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:in-reply-to:references:from:date:message-id :subject:to:content-type; s=default; bh=IHt0RNyc4puS+Jni+FCYSID9 vRw=; b=xlQSTvXRZLG0X/h/12xu35kzJP3KeqykaXhrqBnsr3A0i0JJ+mJBnqxn xZ2vnUjWHf6EUsjS8Xqvjm6292x6zYTwpDWOCMorpZb9uqhFLr+SU3yB6JZG4xE0 JgWor9gNpkXWJU587gFaoP5BgRsCGkdtp5T8eZou8ARkB4gfArM= Received: (qmail 115976 invoked by alias); 3 Mar 2017 01:27:02 -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 115953 invoked by uid 89); 3 Mar 2017 01:27:01 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-24.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM autolearn=ham version=3.3.2 spammy=Declaration X-HELO: mail-oi0-f47.google.com Received: from mail-oi0-f47.google.com (HELO mail-oi0-f47.google.com) (209.85.218.47) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 03 Mar 2017 01:26:59 +0000 Received: by mail-oi0-f47.google.com with SMTP id 2so48776132oif.0 for ; Thu, 02 Mar 2017 17:26:59 -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:in-reply-to:references:from:date :message-id:subject:to; bh=l/nzGZjRHjae9YwFXTnBXWwAbNNfFkQyPIyhhjX+3kc=; b=iDvuqZw6LRiyoYPo2qz8WsPsjVUZ6dLpMfIGxucZl64IwE9cVdD3O/ObTULEFB6O5k +I8ZctQQ0BjRmYSejA7FWZPfxZfcUOTUgdFdTdLlc4hizDXfibUXztARpRNId77EsWlY bgIs13hkTBWCKdWWY+uyvyuPvb/KnU5uNaGwJvP/9ksw23Q7HiHqhojIRdlUSOzYebLq 229x8xcq68JZdj1HM6iQomtL3c54ZcCSdsxQU43eskEQOY29RS9sZzBJtWW20WMHFni6 Marm4xI9D9UpZ/gKzQcZiqc5O6iR+5OaC5WzhZhoXBVlcQxKENTzNh+suLQ30Knu7Z79 BPlA== X-Gm-Message-State: AMke39lOjLiHGVOvGllspz/X6QHAhF8MaaBxG9hBC+Go8xe+vJC2oRgXYUWlyZwSbDQCAg38GWM2sSQy51C6q+wj X-Received: by 10.202.58.69 with SMTP id h66mr110442oia.30.1488504417503; Thu, 02 Mar 2017 17:26:57 -0800 (PST) MIME-Version: 1.0 Received: by 10.182.187.8 with HTTP; Thu, 2 Mar 2017 17:26:36 -0800 (PST) In-Reply-To: References: From: Jason Merrill Date: Thu, 2 Mar 2017 15:26:36 -1000 Message-ID: Subject: Re: C++ PATCH for C++17 class template argument deduction issues To: gcc-patches List X-IsSubscribed: yes On Wed, Mar 1, 2017 at 3:58 PM, Jason Merrill wrote: > On Tue, Feb 28, 2017 at 1:56 PM, Jason Merrill wrote: >> This patch implements some proposed resolutions to open issues with >> C++17 class template argument deduction. > > And some more: This patch handles the issues of references to members of the class template differently, by also allowing explicit guides to refer to them: commit d32c5f542b7bfe825149fc134b8c5348061f0bfb Author: Jason Merrill Date: Thu Mar 2 13:20:27 2017 -1000 Allow deduction guides to look into primary template. * cp-tree.h (struct saved_scope): Add deduction_guide_type. (struct cp_decl_specifier_seq): Add constructor_p. * parser.c (cp_parser_decl_specifier_seq): Set constructor_p. (cp_parser_init_declarator): Check it. Set ctor_dtor_or_conv_p. Clear deduction_guide_type. Don't handle deduction guide names. (cp_parser_declarator): Don't clear ctor_dtor_or_conv_p. (cp_parser_direct_declarator): Likewise. Handle deduction guides. (cp_parser_member_declaration, cp_parser_cache_defarg) (cp_parser_objc_class_ivars): Set ctor_dtor_or_conv_p. * pt.c (tsubst_copy, tsubst_copy_and_build): Revert last change. (build_deduction_guide): Set deduction_guide_type. (dependent_scope_p): Check deduction_guide_type. * search.c (lookup_member): Likewise. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f53f744..31edc5f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1272,6 +1272,7 @@ struct GTY(()) saved_scope { vec *lang_base; tree lang_name; tree template_parms; + tree deduction_guide_type; cp_binding_level *x_previous_class_level; tree x_saved_tree; @@ -5422,6 +5423,9 @@ struct cp_decl_specifier_seq { BOOL_BITFIELD gnu_thread_keyword_p : 1; /* True iff the type is a decltype. */ BOOL_BITFIELD decltype_p : 1; + /* True iff the declaration declares a constructor or C++17 deduction + guide. */ + BOOL_BITFIELD constructor_p : 1; }; /* The various kinds of declarators. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e684870..fbe864f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -13313,6 +13313,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser, && constructor_possible_p && (cp_parser_constructor_declarator_p (parser, decl_spec_seq_has_spec_p (decl_specs, ds_friend)))); + if (constructor_p) + decl_specs->constructor_p = true; /* If we don't have a DECL_SPEC yet, then we must be looking at a type-specifier. */ @@ -19010,7 +19012,7 @@ cp_parser_init_declarator (cp_parser* parser, enum cpp_ttype initialization_kind; bool is_direct_init = false; bool is_non_constant_init; - int ctor_dtor_or_conv_p; + int ctor_dtor_or_conv_p = decl_specifiers->constructor_p ? -1 : 0; bool friend_p = cp_parser_friend_p (decl_specifiers); tree pushed_scope = NULL_TREE; bool range_for_decl_p = false; @@ -19048,6 +19050,9 @@ cp_parser_init_declarator (cp_parser* parser, parser->default_arg_ok_p = saved_default_arg_ok_p; + if (cxx_dialect >= cxx1z) + scope_chain->deduction_guide_type = NULL_TREE; + /* If the DECLARATOR was erroneous, there's no need to go further. */ if (declarator == cp_error_declarator) @@ -19095,25 +19100,6 @@ cp_parser_init_declarator (cp_parser* parser, if (function_declarator_p (declarator)) { - /* Handle C++17 deduction guides. */ - if (!decl_specifiers->type - && ctor_dtor_or_conv_p <= 0 - && cxx_dialect >= cxx1z) - { - cp_declarator *id = get_id_declarator (declarator); - tree name = id->u.id.unqualified_name; - parser->scope = id->u.id.qualifying_scope; - tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc); - if (tmpl - && (DECL_CLASS_TEMPLATE_P (tmpl) - || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) - { - id->u.id.unqualified_name = dguide_name (tmpl); - id->u.id.sfk = sfk_deduction_guide; - ctor_dtor_or_conv_p = 1; - } - } - /* Check to see if the token indicates the start of a function-definition. */ if (cp_parser_token_starts_function_definition_p (token)) @@ -19432,8 +19418,10 @@ cp_parser_init_declarator (cp_parser* parser, If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is used to detect constructors, destructors, deduction guides, or conversion operators. - It is set to -1 if the declarator is a name, and +1 if it is a - function. Otherwise it is set to zero. Usually you just want to + The caller should set it before the call, to -1 if parsing the + decl-specifier-seq determined that we're declaring a constructor or + deduction guide, or 0 otherwise. This function sets it to -1 if the + declarator is a name, and +1 if it is a function. Usually you just want to test for >0, but internally the negative value is used. (The reason for CTOR_DTOR_OR_CONV_P is that a declaration must have @@ -19464,11 +19452,6 @@ cp_parser_declarator (cp_parser* parser, tree class_type; tree gnu_attributes = NULL_TREE, std_attributes = NULL_TREE; - /* Assume this is not a constructor, destructor, or type-conversion - operator. */ - if (ctor_dtor_or_conv_p) - *ctor_dtor_or_conv_p = 0; - if (cp_parser_allow_gnu_extensions_p (parser)) gnu_attributes = cp_parser_gnu_attributes_opt (parser); @@ -19766,9 +19749,6 @@ cp_parser_direct_declarator (cp_parser* parser, /* Parse an array-declarator. */ tree bounds, attrs; - if (ctor_dtor_or_conv_p) - *ctor_dtor_or_conv_p = 0; - first = false; parser->default_arg_ok_p = false; parser->in_declarator_p = true; @@ -20023,6 +20003,34 @@ cp_parser_direct_declarator (cp_parser* parser, *ctor_dtor_or_conv_p = -1; } } + + if (cxx_dialect >= cxx1z + && sfk == sfk_none + && ctor_dtor_or_conv_p + && *ctor_dtor_or_conv_p == -1) + { + /* If *ctor_dtor_or_conv_p is set and we aren't declaring a + constructor, we must be declaring a deduction guide. */ + tree tmpl; + if (qualifying_scope) + tmpl = (lookup_qualified_name + (qualifying_scope, unqualified_name, + /*prefer_type*/false, /*complain*/true)); + else + tmpl = lookup_name (unqualified_name); + if (tmpl + && (DECL_CLASS_TEMPLATE_P (tmpl) + || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) + { + unqualified_name = dguide_name (tmpl); + scope_chain->deduction_guide_type + = TREE_TYPE (unqualified_name); + sfk = sfk_deduction_guide; + } + else + gcc_checking_assert (false); + } + declarator = make_id_declarator (qualifying_scope, unqualified_name, sfk); @@ -23251,7 +23259,7 @@ cp_parser_member_declaration (cp_parser* parser) cp_declarator *declarator; tree initializer; tree asm_specification; - int ctor_dtor_or_conv_p; + int ctor_dtor_or_conv_p = decl_specifiers.constructor_p ? -1 : 0; /* Parse the declarator. */ declarator @@ -28334,7 +28342,7 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi) declarator. */ do { - int ctor_dtor_or_conv_p; + int ctor_dtor_or_conv_p = 0; cp_lexer_consume_token (parser->lexer); cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, &ctor_dtor_or_conv_p, @@ -29655,7 +29663,7 @@ cp_parser_objc_class_ivars (cp_parser* parser) { tree width = NULL_TREE, attributes, first_attribute, decl; cp_declarator *declarator = NULL; - int ctor_dtor_or_conv_p; + int ctor_dtor_or_conv_p = 0; /* Check for a (possibly unnamed) bitfield declaration. */ token = cp_lexer_peek_token (parser->lexer); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8144ca6..3b320fc 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -14641,15 +14641,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) have to substitute this with one having context `D'. */ tree context = tsubst (DECL_CONTEXT (t), args, complain, in_decl); - if (dependent_scope_p (context)) - { - /* When rewriting a constructor into a deduction guide, a - non-dependent name can become dependent, so memtmpl - becomes context::template memtmpl. */ - tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); - return build_qualified_name (type, context, DECL_NAME (t), - /*template*/true); - } return lookup_field (context, DECL_NAME(t), 0, false); } else @@ -16633,14 +16624,6 @@ tsubst_copy_and_build (tree t, if (targs == error_mark_node) return error_mark_node; - if (TREE_CODE (templ) == SCOPE_REF) - { - tree name = TREE_OPERAND (templ, 1); - tree tid = lookup_template_function (name, targs); - TREE_OPERAND (templ, 1) = tid; - return templ; - } - if (variable_template_p (templ)) RETURN (lookup_and_finish_template_variable (templ, targs, complain)); @@ -23476,6 +23459,9 @@ bool dependent_scope_p (tree scope) { return (scope && TYPE_P (scope) && dependent_type_p (scope) + && !(cxx_dialect >= cxx1z + && scope_chain->deduction_guide_type + && same_type_p (scope, scope_chain->deduction_guide_type)) && !currently_open_class (scope)); } @@ -24997,6 +24983,7 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) if (outer_args) ctor = tsubst (ctor, outer_args, complain, ctor); type = DECL_CONTEXT (ctor); + scope_chain->deduction_guide_type = type; tree fn_tmpl; if (TREE_CODE (ctor) == TEMPLATE_DECL) { @@ -25089,6 +25076,7 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) current_template_parms = save_parms; --processing_template_decl; } + scope_chain->deduction_guide_type = NULL_TREE; } if (!memtmpl) diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 09c1b4e..6eb4124 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1279,6 +1279,13 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type, if (tree t = currently_open_class (type)) type = t; + /* Declaration of a deduction guide can look inside the primary class + template; replace a compatible type with the real one. */ + if (cxx_dialect >= cxx1z + && scope_chain->deduction_guide_type + && same_type_p (type, scope_chain->deduction_guide_type)) + type = scope_chain->deduction_guide_type; + if (!basetype_path) basetype_path = TYPE_BINFO (type); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C new file mode 100644 index 0000000..ee21d14 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C @@ -0,0 +1,16 @@ +// { dg-options -std=c++1z } + +template struct A +{ + using value_t = T; + A(value_t); +}; + +template +A(typename A::value_t) -> A; + +template struct same; +template struct same {}; + +A a(42); +same> s1;