From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28108 invoked by alias); 27 Oct 2011 19:11:20 -0000 Received: (qmail 28062 invoked by uid 22791); 27 Oct 2011 19:11:13 -0000 X-SWARE-Spam-Status: No, hits=-4.9 required=5.0 tests=AWL,BAYES_50,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_CX,TW_YP 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; Thu, 27 Oct 2011 19:10:50 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p9RJAoKf016746 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 27 Oct 2011 15:10:50 -0400 Received: from localhost (ovpn-113-61.phx2.redhat.com [10.3.113.61]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p9RJAmRU011900 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 27 Oct 2011 15:10:49 -0400 Received: by localhost (Postfix, from userid 500) id B953829C129; Thu, 27 Oct 2011 21:10:46 +0200 (CEST) From: Dodji Seketeli To: GCC Patches Cc: Jason Merrill , Benjamin De Kosnik Subject: [C++ PATCH] PR c++/45114 - Support alias templates X-URL: http://www.redhat.com Date: Thu, 27 Oct 2011 19:26:00 -0000 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2011-10/txt/msg02499.txt.bz2 Hello, This patch adds support for the alias-declaration feature of the c++11 specification, introduced by the paper N2258[1] and voted into in the standard. It's a derivative work of a preliminary patch attached by Jason Merrill to PR C++/45114[2]. alias-declaration introduces a new syntax for declaring an alias for a type. Exactly like a typedef. E.g: template struct Vector {}; using IntVect = Vector; The concept generalizes to families of types as well. That is, you can define an alias for a family of types -- dubbed alias template. E.g: template struct Vector {}; template struct MyAllocactor {}; template using Vec = Vector >; Vec v; // <-- this is equivalent to // Vector > v; Neat heh? :-) The approach taken by the patch is to represent the alias of a type the same way we represent a typedef today and mark it as type alias using a flag. An alias for a type T is thus a variant of T with a new type name. By extension an alias template is represented almost like a class template except that its pattern is a variant of the type at the right hand side of the '=' of the alias template declaration. To represent a specialization of an alias template it's important to notice that there are two "template info" at stake, unlike with normal template specializations. There is the template info of the alias specialization itself and the one of the underlying type we are aliasing. The latter has been historically stored in CLASSTYPE_TEMPLATE_INFO; now we hang the former off of the type name of the alias. Using the right template info helps here. :-) Substituting into an alias template means substituting for the parameters of the alias template itself, but also for the parameters of the type it aliases. This part was easy as it's already mostly handled by the typedef handling code we are based on. Instantiating an alias template means just instantiating the type it aliases. This part is also taken care of by construction as the alias*ed* type is the main variant of the alias type. And we already instantiate only the main variant type of a given type. [1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf [2]: http://gcc.gnu.org/PR45114 Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk. gcc/cp/ * cp-tree.h (TYPE_DECL_ALIAS_P, SET_TYPE_DECL_ALIAS_P) (TYPE_DECL_NAMES_ALIAS_TEMPLATE_P, TYPE_ALIAS_P) (DECL_TYPE_TEMPLATE_P, DECL_ALIAS_TEMPLATE_P): New accessor macros. (TYPE_TEMPLATE_INFO): Get template info of an alias template specializations from its TYPE_DECL. (SET_TYPE_TEMPLATE_INFO): Set template info of alias template specializations into its TYPE_DECL. (DECL_CLASS_TEMPLATE_P): Re-write using the new DECL_TYPE_TEMPLATE_P. (enum cp_decl_spec): Add new ds_alias enumerator. (alias_type_or_template_p, alias_template_specialization_p): Declare new functions. * parser.c (cp_parser_alias_declaration): New static function. (cp_parser_check_decl_spec): Add "using" name for the `alias' declspec. (cp_parser_block_declaration): Handle alias-declaration in c++11. Update comment. (cp_parser_template_id): Handle specializations of alias templates. (cp_parser_member_declaration): Add alias-declaration production to comment. (cp_parser_template_declaration_after_export): Handle alias templates in c++11. * decl.c (grokdeclarator): Set TYPE_DECL_ALIAS_P on alias declarations. (grokfield): Move template creation after setting up the TYPE_DECL of the alias, so that the TEMPLATE_DECL of the alias template actually carries the right type-id of the alias declaration. * pt.c (get_aliased_type, strip_alias): New static functions. (alias_type_or_template_p) (alias_template_specialization_p): Define new public functions. (maybe_process_partial_specialization): Reject partial specializations of alias template. (push_template_decl_real): Assert that TYPE_DECLs of alias templates are different from those of class template. Store template info onto the TYPE_DECL of the alias template. (convert_template_argument): Strip aliases from template arguments. (lookup_template_class_1): Handle the creation of the specialization of an alias template. (tsubst_decl): Create a substituted copy of the TYPE_DECL of an member alias template. (tsubst): Handle substituting into the type of an alias template. * semantics.c (finish_template_type): For alias templates, return the TYPE_DECL of the actual alias and not the one of the aliased type. * error.c (dump_type): Print specialization of alias templates like we print specializations of class templates. Also, handle the printing of alias templates. (dump_aggr_type): For specialization of alias templates, fetch arguments from the right place. (dump_decl): Print an alias-declaration like `using decl = type;' gcc/testsuite/ * g++.dg/cpp0x/alias-decl-0.C: New test case. * g++.dg/cpp0x/alias-decl-1.C: Likewise. * g++.dg/cpp0x/alias-decl-3.C: Likewise. * g++.dg/cpp0x/alias-decl-4.C: Likewise. * g++.dg/cpp0x/alias-decl-5.C: Likewise. --- gcc/cp/cp-tree.h | 70 ++++++++++++-- gcc/cp/decl.c | 5 + gcc/cp/decl2.c | 9 +- gcc/cp/error.c | 31 +++++- gcc/cp/parser.c | 71 +++++++++++++- gcc/cp/pt.c | 153 +++++++++++++++++++++++++++-- gcc/cp/semantics.c | 14 ++- gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C | 33 ++++++ gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C | 5 + gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C | 33 ++++++ gcc/testsuite/g++.dg/cpp0x/alias-decl-3.C | 29 ++++++ gcc/testsuite/g++.dg/cpp0x/alias-decl-4.C | 14 +++ gcc/testsuite/g++.dg/cpp0x/alias-decl-5.C | 34 +++++++ 13 files changed, 470 insertions(+), 31 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-3.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-4.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-5.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7ff1491..98971a5 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -139,6 +139,7 @@ c-common.h, not after. 5: DECL_INTERFACE_KNOWN. 6: DECL_THIS_STATIC (in VAR_DECL or FUNCTION_DECL). DECL_FIELD_IS_BASE (in FIELD_DECL) + TYPE_DECL_ALIAS_P (in TYPE_DECL) 7: DECL_DEAD_FOR_LOCAL (in VAR_DECL). DECL_THUNK_P (in a member FUNCTION_DECL) DECL_NORMAL_CAPTURE_P (in FIELD_DECL) @@ -2541,6 +2542,41 @@ extern void decl_shadowed_for_var_insert (tree, tree); #define DECL_PENDING_INLINE_INFO(NODE) \ (LANG_DECL_FN_CHECK (NODE)->u.pending_inline_info) +/* Nonzero for TYPE_DECL means that it was written 'using name = type'. */ +#define TYPE_DECL_ALIAS_P(NODE) \ + DECL_LANG_FLAG_6 (TYPE_DECL_CHECK (NODE)) + +/* Setter for the TYPE_DECL_ALIAS_P proprety above. */ +#define SET_TYPE_DECL_ALIAS_P(NODE, VAL) \ + (DECL_LANG_FLAG_6 (TYPE_DECL_CHECK (NODE)) = (VAL)) + +/* Nonzero if NODE is a TYPE_DECL for an instantiation that names an + alias template. For instance: + + template struct S {}; + template using A = S; + + template + struct C + { + typedef A name_of_A; + }; + A is just "names A" because its list of argument is the + same a the list of parameters of the template A. */ +#define TYPE_DECL_NAMES_ALIAS_TEMPLATE_P(NODE) \ + (TYPE_DECL_ALIAS_P (NODE) \ + && DECL_LANG_SPECIFIC (NODE) \ + && DECL_TI_TEMPLATE (NODE) \ + && same_type_p (TREE_TYPE (NODE), TREE_TYPE (DECL_TI_TEMPLATE (NODE)))) + +/* Nonzero for a type which is an alias for another type; i.e, a type + which declaration was written 'using name-of-type = + another-type'. */ +#define TYPE_ALIAS_P(NODE) \ + (TYPE_P (NODE) \ + && DECL_LANG_SPECIFIC (TYPE_NAME (NODE)) \ + && TYPE_DECL_ALIAS_P (TYPE_NAME (NODE))) + /* For a class type: if this structure has many fields, we'll sort them and put them into a TREE_VEC. */ #define CLASSTYPE_SORTED_FIELDS(NODE) \ @@ -2597,16 +2633,20 @@ extern void decl_shadowed_for_var_insert (tree, tree); ? ENUM_TEMPLATE_INFO (NODE) : \ (TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM \ ? TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (NODE) : \ - (TYPE_LANG_SPECIFIC (NODE) \ + ((CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE)) \ ? CLASSTYPE_TEMPLATE_INFO (NODE) \ - : NULL_TREE))) + : (DECL_LANG_SPECIFIC (TYPE_NAME (NODE)) \ + ? (DECL_TEMPLATE_INFO (TYPE_NAME (NODE))) \ + : NULL_TREE)))) /* Set the template information for an ENUMERAL_, RECORD_, or UNION_TYPE to VAL. */ -#define SET_TYPE_TEMPLATE_INFO(NODE, VAL) \ - (TREE_CODE (NODE) == ENUMERAL_TYPE \ - ? (ENUM_TEMPLATE_INFO (NODE) = (VAL)) \ - : (CLASSTYPE_TEMPLATE_INFO (NODE) = (VAL))) +#define SET_TYPE_TEMPLATE_INFO(NODE, VAL) \ + (TREE_CODE (NODE) == ENUMERAL_TYPE \ + ? (ENUM_TEMPLATE_INFO (NODE) = (VAL)) \ + : ((CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE)) \ + ? (CLASSTYPE_TEMPLATE_INFO (NODE) = (VAL)) \ + : (DECL_TEMPLATE_INFO (TYPE_NAME (NODE)) = (VAL)))) #define TI_TEMPLATE(NODE) TREE_TYPE (TEMPLATE_INFO_CHECK (NODE)) #define TI_ARGS(NODE) TREE_CHAIN (TEMPLATE_INFO_CHECK (NODE)) @@ -3619,12 +3659,23 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) && !DECL_UNBOUND_CLASS_TEMPLATE_P (NODE) \ && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == FUNCTION_DECL) -/* Nonzero for a DECL that represents a template class. */ -#define DECL_CLASS_TEMPLATE_P(NODE) \ +/* Nonzero for a DECL that represents a class template or alias + template. */ +#define DECL_TYPE_TEMPLATE_P(NODE) \ (TREE_CODE (NODE) == TEMPLATE_DECL \ && DECL_TEMPLATE_RESULT (NODE) != NULL_TREE \ + && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == TYPE_DECL) + +/* Nonzero for a DECL that represents a class template. */ +#define DECL_CLASS_TEMPLATE_P(NODE) \ + (DECL_TYPE_TEMPLATE_P (NODE) \ && DECL_IMPLICIT_TYPEDEF_P (DECL_TEMPLATE_RESULT (NODE))) +/* Nonzero for a TEMPLATE_DECL that represents an alias template. */ +#define DECL_ALIAS_TEMPLATE_P(NODE) \ + (DECL_TYPE_TEMPLATE_P (NODE) \ + && !DECL_ARTIFICIAL (DECL_TEMPLATE_RESULT (NODE))) + /* Nonzero for a NODE which declares a type. */ #define DECL_DECLARES_TYPE_P(NODE) \ (TREE_CODE (NODE) == TYPE_DECL || DECL_CLASS_TEMPLATE_P (NODE)) @@ -4579,6 +4630,7 @@ typedef enum cp_decl_spec { ds_explicit, ds_friend, ds_typedef, + ds_alias, ds_constexpr, ds_complex, ds_thread, @@ -5282,6 +5334,8 @@ extern tree build_non_dependent_expr (tree); extern void make_args_non_dependent (VEC(tree,gc) *); extern bool reregister_specialization (tree, tree, tree); extern tree fold_non_dependent_expr (tree); +extern bool alias_type_or_template_p (tree); +extern bool alias_template_specialization_p (tree); extern bool explicit_class_specialization_p (tree); extern int push_tinst_level (tree); extern void pop_tinst_level (void); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 860556c..8e84f3d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -9790,6 +9790,11 @@ grokdeclarator (const cp_declarator *declarator, memfn_quals != TYPE_UNQUALIFIED, inlinep, friendp, raises != NULL_TREE); + if (declspecs->specs[(int)ds_alias]) + /* Acknowledge that this was written: + `using analias = atype;'. */ + SET_TYPE_DECL_ALIAS_P (decl, 1); + return decl; } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 9851ece..b230d95 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -847,9 +847,6 @@ grokfield (const cp_declarator *declarator, DECL_NONLOCAL (value) = 1; DECL_CONTEXT (value) = current_class_type; - if (processing_template_decl) - value = push_template_decl (value); - if (attrlist) { int attrflags = 0; @@ -868,6 +865,12 @@ grokfield (const cp_declarator *declarator, && TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (value))) != value) set_underlying_type (value); + /* It's important that push_template_decl below follows + set_underlying_type above so that the created template + carries the properly set type of VALUE. */ + if (processing_template_decl) + value = push_template_decl (value); + record_locally_defined_typedef (value); return value; } diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 544c4d1..1e8f2e4 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -340,7 +340,11 @@ dump_type (tree t, int flags) return; /* Don't print e.g. "struct mytypedef". */ - if (TYPE_P (t) && typedef_variant_p (t)) + if (TYPE_P (t) && typedef_variant_p (t) + /*If T is a specialization of an alias template, then we don't + want to take this 'if' branch; we want to print it as if it + was a specialization of class template. */ + && !alias_template_specialization_p (t)) { tree decl = TYPE_NAME (t); if ((flags & TFF_CHASE_TYPEDEF) @@ -348,7 +352,11 @@ dump_type (tree t, int flags) || (!flag_pretty_templates && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))) t = strip_typedefs (t); - else if (same_type_p (t, TREE_TYPE (decl))) + else if (same_type_p (t, TREE_TYPE (decl)) + && /* If T is the type of an alias template then we + want to let dump_decl print it like an alias + template. */ + TYPE_DECL_NAMES_ALIAS_TEMPLATE_P (decl)) t = decl; else { @@ -588,7 +596,10 @@ dump_aggr_type (tree t, int flags) if (name) { - typdef = !DECL_ARTIFICIAL (name); + typdef = (!DECL_ARTIFICIAL (name) + /* An alias specialization is not considered to be a + typedef. */ + && !alias_template_specialization_p (t)); if ((typdef && ((flags & TFF_CHASE_TYPEDEF) @@ -613,7 +624,7 @@ dump_aggr_type (tree t, int flags) { /* Because the template names are mangled, we have to locate the most general template, and use that name. */ - tree tpl = CLASSTYPE_TI_TEMPLATE (t); + tree tpl = TYPE_TI_TEMPLATE (t); while (DECL_TEMPLATE_INFO (tpl)) tpl = DECL_TI_TEMPLATE (tpl); @@ -952,6 +963,18 @@ dump_decl (tree t, int flags) dump_type (TREE_TYPE (t), flags); break; } + if (TYPE_DECL_ALIAS_P (t) + && (flags & TFF_DECL_SPECIFIERS + || flags & TFF_CLASS_KEY_OR_ENUM)) + { + pp_cxx_ws_string (cxx_pp, "using"); + dump_decl (DECL_NAME (t), flags); + pp_cxx_whitespace (cxx_pp); + pp_cxx_ws_string (cxx_pp, "="); + pp_cxx_whitespace (cxx_pp); + dump_type (DECL_ORIGINAL_TYPE (t), flags); + break; + } if ((flags & TFF_DECL_SPECIFIERS) && !DECL_SELF_REFERENCE_P (t)) pp_cxx_ws_string (cxx_pp, "typedef"); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 090482c..cb8c188 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1935,6 +1935,8 @@ static bool cp_parser_using_declaration (cp_parser *, bool); static void cp_parser_using_directive (cp_parser *); +static tree cp_parser_alias_declaration + (cp_parser *); static void cp_parser_asm_definition (cp_parser *); static void cp_parser_linkage_specification @@ -2509,6 +2511,7 @@ cp_parser_check_decl_spec (cp_decl_specifier_seq *decl_specs, "explicit", "friend", "typedef", + "using", "constexpr", "__complex", "__thread" @@ -10150,8 +10153,8 @@ cp_parser_block_declaration (cp_parser *parser, namespace-alias-definition. */ else if (token1->keyword == RID_NAMESPACE) cp_parser_namespace_alias_definition (parser); - /* If the next keyword is `using', we have either a - using-declaration or a using-directive. */ + /* If the next keyword is `using', we have a + using-declaration, a using-directive, or an alias-declaration. */ else if (token1->keyword == RID_USING) { cp_token *token2; @@ -10163,6 +10166,12 @@ cp_parser_block_declaration (cp_parser *parser, token2 = cp_lexer_peek_nth_token (parser->lexer, 2); if (token2->keyword == RID_NAMESPACE) cp_parser_using_directive (parser); + /* If the second token after 'using' is '=', then we have an + alias-declaration. */ + else if (cxx_dialect >= cxx0x + && token2->type == CPP_NAME + && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ) + cp_parser_alias_declaration (parser); /* Otherwise, it's a using-declaration. */ else cp_parser_using_declaration (parser, @@ -12343,7 +12352,7 @@ cp_parser_template_id (cp_parser *parser, /* Build a representation of the specialization. */ if (TREE_CODE (templ) == IDENTIFIER_NODE) template_id = build_min_nt (TEMPLATE_ID_EXPR, templ, arguments); - else if (DECL_CLASS_TEMPLATE_P (templ) + else if (DECL_TYPE_TEMPLATE_P (templ) || DECL_TEMPLATE_TEMPLATE_PARM_P (templ)) { bool entering_scope; @@ -14831,6 +14840,58 @@ cp_parser_using_declaration (cp_parser* parser, return true; } +/* Parse an alias-declaration. + + alias-declaration: + using identifier = type-id */ + +static tree +cp_parser_alias_declaration (cp_parser* parser) +{ + tree id, type, decl, dummy; + location_t id_location; + cp_declarator *declarator; + cp_decl_specifier_seq decl_specs; + + /* Look for the `using' keyword. */ + cp_parser_require_keyword (parser, RID_USING, RT_USING); + id_location = cp_lexer_peek_token (parser->lexer)->location; + id = cp_parser_identifier (parser); + cp_parser_require (parser, CPP_EQ, RT_EQ); + + type = cp_parser_type_id (parser); + + /* A typedef-name can also be introduced by an alias-declaration. The + identifier following the using keyword becomes a typedef-name. It has + the same semantics as if it were introduced by the typedef + specifier. In particular, it does not define a new type and it shall + not appear in the type-id. */ + + clear_decl_specs (&decl_specs); + decl_specs.type = type; + ++decl_specs.specs[(int) ds_typedef]; + ++decl_specs.specs[(int) ds_alias]; + + declarator = make_id_declarator (NULL_TREE, id, sfk_none); + declarator->id_loc = id_location; + + if (at_class_scope_p ()) + decl = grokfield (declarator, &decl_specs, NULL_TREE, false, + NULL_TREE, NULL_TREE); + else + decl = start_decl (declarator, &decl_specs, 0, + NULL_TREE, NULL_TREE, &dummy); + if (decl == error_mark_node) + return decl; + + cp_finish_decl (decl, NULL_TREE, 0, NULL_TREE, 0); + + if (DECL_LANG_SPECIFIC (decl) + && DECL_TI_TEMPLATE (decl)) + decl = DECL_TI_TEMPLATE (decl); + return decl; +} + /* Parse a using-directive. using-directive: @@ -18528,6 +18589,7 @@ cp_parser_member_specification_opt (cp_parser* parser) :: [opt] nested-name-specifier template [opt] unqualified-id ; using-declaration template-declaration + alias-declaration member-declarator-list: member-declarator @@ -20889,6 +20951,9 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p) if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) cp_parser_template_declaration_after_export (parser, member_p); + else if (cxx_dialect >= cxx0x + && cp_lexer_next_token_is_keyword (parser->lexer, RID_USING)) + decl = cp_parser_alias_declaration (parser); else { /* There are no access checks when parsing a template, as we do not diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7aea72d..01b65fb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -841,6 +841,13 @@ maybe_process_partial_specialization (tree type) } else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)) error ("specialization of %qT after instantiation", type); + + if (DECL_ALIAS_TEMPLATE_P (TI_TEMPLATE (get_template_info (type)))) + { + error ("partial specialization of alias template %qD", + TYPE_NAME (type)); + return error_mark_node; + } } else if (CLASS_TYPE_P (type) && !CLASSTYPE_USE_TEMPLATE (type) @@ -4831,6 +4838,10 @@ push_template_decl_real (tree decl, bool is_friend) else if (DECL_IMPLICIT_TYPEDEF_P (decl) && CLASS_TYPE_P (TREE_TYPE (decl))) /* OK */; + else if (TREE_CODE (decl) == TYPE_DECL + && TYPE_DECL_ALIAS_P (decl)) + /* alias-declaration */ + gcc_assert (!DECL_ARTIFICIAL (decl)); else { error ("template declaration of %q#D", decl); @@ -5095,8 +5106,13 @@ template arguments to %qD do not match original template %qD", if (DECL_IMPLICIT_TYPEDEF_P (decl)) SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info); - else if (DECL_LANG_SPECIFIC (decl)) - DECL_TEMPLATE_INFO (decl) = info; + else + { + if (primary && !DECL_LANG_SPECIFIC (decl)) + retrofit_lang_decl (decl); + if (DECL_LANG_SPECIFIC (decl)) + DECL_TEMPLATE_INFO (decl) = info; + } return DECL_TEMPLATE_RESULT (tmpl); } @@ -5259,6 +5275,30 @@ fold_non_dependent_expr (tree expr) return fold_non_dependent_expr_sfinae (expr, tf_error); } +/* Return TRUE iff T is a type alias, a TEMPLATE_DECL for an alias + template declaration, or a TYPE_DECL for an alias declaration. */ + +bool +alias_type_or_template_p (tree t) +{ + if (t == NULL_TREE) + return false; + return ((TREE_CODE (t) == TYPE_DECL && TYPE_DECL_ALIAS_P (t)) + || (TYPE_P (t) && TYPE_DECL_ALIAS_P (TYPE_NAME (t))) + || DECL_ALIAS_TEMPLATE_P (t)); +} + +/* Return TRUE iff is a specialization of an alias template. */ + +bool +alias_template_specialization_p (tree t) +{ + if (t == NULL_TREE) + return false; + return (primary_template_instantiation_p (t) + && DECL_ALIAS_TEMPLATE_P (TYPE_TI_TEMPLATE (t))); +} + /* Subroutine of convert_nontype_argument. Converts EXPR to TYPE, which must be a function or a pointer-to-function type, as specified in [temp.arg.nontype]: disambiguate EXPR if it is an overload set, @@ -5979,6 +6019,45 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) return expr; } +/* If T represents an alias declaration, return its underlying aliased + type. */ + +static tree +get_aliased_type (tree t) +{ + tree result = t; + + if (t == NULL_TREE) + /* return t */; + else if (TREE_CODE (t) == TYPE_DECL && TYPE_DECL_ALIAS_P (t)) + result = DECL_ORIGINAL_TYPE (t); + else if (TYPE_P (t) && TYPE_DECL_ALIAS_P (TYPE_NAME (t))) + result = DECL_ORIGINAL_TYPE (TYPE_NAME (t)); + else if (DECL_ALIAS_TEMPLATE_P (t)) + { + tree tmpl; + result = get_aliased_type (DECL_TEMPLATE_RESULT (t)); + tmpl = TI_TEMPLATE (get_template_info (result)); + /* If RESULT is just the naming of TMPL, return TMPL. */ + if (same_type_p (result, + TREE_TYPE (DECL_TEMPLATE_RESULT (tmpl)))) + result = tmpl; + } + + return result; +} + +/* Return the most underlying type of a type alias or alias + template. */ + +static tree +strip_alias (tree t) +{ + while (alias_type_or_template_p (t)) + t = get_aliased_type (t); + return t; +} + /* Subroutine of coerce_template_template_parms, which returns 1 if PARM_PARM and ARG_PARM match using the rule for the template parameters of template template parameters. Both PARM and ARG are @@ -6433,6 +6512,11 @@ convert_template_argument (tree parm, themselves also use the typedef. */ if (TYPE_P (val)) val = canonicalize_type_argument (val, complain); + else + /* Strip template aliases from TEMPLATE_DECL nodes, + similarly to what is done by + canonicalize_type_argument for types above. */ + val = strip_alias (val); } else { @@ -7355,7 +7439,31 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, ENUM_FIXED_UNDERLYING_TYPE_P (t) = ENUM_FIXED_UNDERLYING_TYPE_P (template_type); } - else + else if (DECL_ALIAS_TEMPLATE_P (gen_tmpl)) + { + /* The user referred to a specialization of an alias + template represented by GEN_TMPL. + + [temp.alias]/2 says: + + When a template-id refers to the specialization of an + alias template, it is equivalent to the associated + type obtained by substitution of its + template-arguments for the template-parameters in the + type-id of the alias template. */ + + t = tsubst (TREE_TYPE (gen_tmpl), arglist, complain, in_decl); + /* Note that the call above (by indirectly calling + register_specialization in tsubst_decl) registers the + TYPE_DECL representing the specialization of the alias + template. So next time someone substitutes ARGLIST for + the template parms into the alias template (GEN_TMPL), + she'll get that TYPE_DECL back. */ + + if (t == error_mark_node) + return t; + } + else if (CLASS_TYPE_P (template_type)) { t = make_class_type (TREE_CODE (template_type)); CLASSTYPE_DECLARED_CLASS (t) @@ -7378,6 +7486,8 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, structural equality testing. */ SET_TYPE_STRUCTURAL_EQUALITY (t); } + else + gcc_unreachable (); /* If we called start_enum or pushtag above, this information will already be set up. */ @@ -7480,7 +7590,15 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, TREE_VEC_LENGTH (arglist)--; found = tsubst (gen_tmpl, arglist, complain, NULL_TREE); TREE_VEC_LENGTH (arglist)++; - found = CLASSTYPE_TI_TEMPLATE (found); + /* FOUND is either a proper class type, or an alias + template specialization. In the later case, it's a + TYPE_DECL, resulting from the substituting of arguments + for parameters in the TYPE_DECL of the alias template + done earlier. So be careful while getting the template + of FOUND. */ + found = TREE_CODE (found) == TYPE_DECL + ? TYPE_TI_TEMPLATE (TREE_TYPE (found)) + : CLASSTYPE_TI_TEMPLATE (found); } SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist)); @@ -10376,8 +10494,18 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) referencing a static data member within in its own class. We can use pointer equality, rather than same_type_p, because DECL_CONTEXT is always - canonical. */ - if (ctx == DECL_CONTEXT (t)) + canonical... */ + if (ctx == DECL_CONTEXT (t) + && (TREE_CODE (t) != TYPE_DECL + /* ... unless T is an alias declaration; in + which case our caller can be willing to + create a specialization of the alias + template represented by T. If we hand her + T, she is going to clobber it. So we'll + contruct a new T in this case, just like + for the case where T is not a class + member. */ + || !TYPE_DECL_ALIAS_P (t))) spec = t; } @@ -10858,7 +10986,7 @@ tree tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) { enum tree_code code; - tree type, r; + tree type, r = NULL_TREE; if (t == NULL_TREE || t == error_mark_node || t == integer_type_node @@ -10903,6 +11031,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) && DECL_TEMPLATE_INFO (DECL_CONTEXT (decl)) && uses_template_parms (DECL_TI_ARGS (DECL_CONTEXT (decl)))) r = retrieve_local_specialization (decl); + else if (TYPE_DECL_ALIAS_P (decl)) + /* fall through. */; else /* The typedef is from a non-template context. */ return t; @@ -10915,6 +11045,15 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) complain | tf_ignore_bad_quals); return r; } + else if (TYPE_DECL_ALIAS_P (decl)) + { + /* DECL represents an alias declaration, possibly an alias + template. Let's substitute our arguments for the + template parameters into the declaration and get the + resulting type. */ + tree type_decl = tsubst (decl, args, complain, decl); + return TREE_TYPE (type_decl); + } /* Else we must be instantiating the typedef, so fall through. */ } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index fa8ab99..7be828e 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2733,15 +2733,17 @@ finish_template_decl (tree parms) tree finish_template_type (tree name, tree args, int entering_scope) { - tree decl; + tree type; - decl = lookup_template_class (name, args, + type = lookup_template_class (name, args, NULL_TREE, NULL_TREE, entering_scope, tf_warning_or_error | tf_user); - if (decl != error_mark_node) - decl = TYPE_STUB_DECL (decl); - - return decl; + if (type == error_mark_node) + return type; + else if (CLASS_TYPE_P (type) && !alias_type_or_template_p (type)) + return TYPE_STUB_DECL (type); + else + return TYPE_NAME (type); } /* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER. diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C new file mode 100644 index 0000000..abc56ff --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C @@ -0,0 +1,33 @@ +// { dg-options "-std=c++0x" } + +template class TT> struct X { }; +template struct Y { }; +template using Z = Y; + +void f(X); +void g(X); + +void +foo() +{ + X y; + X z; + f(z); + g(y); +} + +template struct A0 {}; +template using AA0 = A0; +template using AAA0 = AA0; + +void f0(A0); +void +g0() +{ + AA0 a; + AAA0 b; + f0(a); + f0(b); +} + + diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C new file mode 100644 index 0000000..f1c4b94 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C @@ -0,0 +1,5 @@ +// { dg-options "-std=c++0x" } + +template struct A0 {}; +template using AA0 = A0; +template struct AA0 {}; // { dg-error "partial specialization" } diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C new file mode 100644 index 0000000..2e03dd8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C @@ -0,0 +1,33 @@ +// { dg-options "-std=c++0x" } + +template struct S0 {}; +template using AS0 = S0; + +template class TT> +void f(TT); + +template class AS0; + +void +foo() +{ + AS0 a; + f(a); +} + +template struct Vector{}; +template struct Alloc {}; + +template using Vec = Vector >; + +template void g(Vector >); + +template class TT> void h(TT); // { dg-error "provided for" } + +void +bar() +{ + Vec a; + g(a); + h(a); // { dg-error "no matching function|wrong number of template arguments" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-3.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-3.C new file mode 100644 index 0000000..b7460f3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-3.C @@ -0,0 +1,29 @@ +// { dg-options "-std=c++0x" } + +template class A0 {}; + +template +struct A1 { + template struct S {}; + template using AA0 = A0; + + void f(A0); + + void + foo() + { + AA0 a; + const AA0 b; + f(a); + f(b); + } +}; + +void +bar() +{ + A1 a1; + a1.foo(); + A1::AA0 a1aa0; + a1.f(a1aa0); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-4.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-4.C new file mode 100644 index 0000000..876944e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-4.C @@ -0,0 +1,14 @@ +// { dg-options "-std=c++0x" } + +// [temp.alias]/3: +// The type-id in an alias template declaration shall not refer +// to the alias template being declared. The type produced by an +// alias template specialization shall not directly or indirectly +// make use of that specialization. + +template struct A; +template using B = typename A::U; // { dg-error "type" } +template struct A { + typedef B U; +}; +B b; // { dg-error "invalid type" } diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-5.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-5.C new file mode 100644 index 0000000..1a4cbd5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-5.C @@ -0,0 +1,34 @@ +// { dg-options "-std=c++0x" } + +// alias template of a partial specialization + +template struct S0 {}; +template struct S0 {}; +template using AS0 = S0; +void foo(S0); + +AS0 a; // OK + +void +f() +{ + foo(a); //OK +} + +// alias template of an explicit specialization of a member template + +template +struct S1 { + template + struct M {}; +}; +template using AM = S1::M; +void bar(S1::M); + +AM b; //OK. + +void +g() +{ + bar(b); //OK +} -- 1.7.6.4 -- Dodji