diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c66c9dc8d73..72aa0513d96 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,77 @@ +2011-11-07 Jason Merrill + Dodji Seketeli + + Support C++11 alias-declaration + PR c++/45114 + * cp-tree.h (TYPE_DECL_ALIAS_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_type_name): Update comment. Support simple-template-id + representing alias template specializations in c++0x mode. + (cp_parser_qualifying_entity): Update comment. Use + cp_parser_type_name. + (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. Support alias-declarations. + (cp_parser_template_declaration_after_export): Handle alias + templates in c++11. + * decl.c (make_typename_type, make_unbound_class_template): Accept + alias templates. + (grokdeclarator): Set TYPE_DECL_ALIAS_P on alias + declarations. + * decl2.c (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 (alias_type_or_template_p) + (alias_template_specialization_p): Define new public functions. + (maybe_process_partial_specialization): Reject partial + specializations of alias templates. + (primary_template_instantiation_p): Consider alias template + instantiations. + (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. + Handle substituting UNBOUND_CLASS_TEMPLATE into + BOUND_TEMPLATE_TEMPLATE_PARM. + (do_type_instantiation): Better diagnostics when trying to + explicitely instantiate a non-class template. + * search.c (lookup_field_1, lookup_field_r): Support looking up + alias templates. + * semantics.c (finish_template_type): For instantiations of alias + templates, return the TYPE_DECL of the actual alias and not the + one of the aliased type. + * error.c (dump_alias_template_specialization): New static + function. + (dump_type): Handle printing of alias templates and their + specializations. 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;' + (dump_template_decl): Support printing of alias templates. + 2011-11-07 Jason Merrill PR c++/35688 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fd57409dced..177f10084af 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,17 @@ 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)) + +/* 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) \ + && 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 +2609,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)) @@ -3620,12 +3636,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)) @@ -4580,6 +4607,7 @@ typedef enum cp_decl_spec { ds_explicit, ds_friend, ds_typedef, + ds_alias, ds_constexpr, ds_complex, ds_thread, @@ -5283,6 +5311,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 63da51d79d9..e4b91cc533b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3270,7 +3270,7 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, return error_mark_node; } - if (want_template && !DECL_CLASS_TEMPLATE_P (t)) + if (want_template && !DECL_TYPE_TEMPLATE_P (t)) { if (complain & tf_error) error ("% names %q#T, which is not a class template", @@ -3338,7 +3338,7 @@ make_unbound_class_template (tree context, tree name, tree parm_list, if (tmpl && TREE_CODE (tmpl) == TYPE_DECL) tmpl = maybe_get_template_decl_from_type_decl (tmpl); - if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl)) + if (!tmpl || !DECL_TYPE_TEMPLATE_P (tmpl)) { if (complain & tf_error) error ("no class template named %q#T in %q#T", name, context); @@ -9747,6 +9747,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;'. */ + TYPE_DECL_ALIAS_P (decl) = 1; + return decl; } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 17be3ad7137..3dc5a69df54 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -848,9 +848,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; @@ -869,6 +866,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 0bee6b4105c..841366f58fa 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -61,6 +61,7 @@ static const char *op_to_string (enum tree_code); static const char *parm_to_string (int); static const char *type_to_string (tree, int); +static void dump_alias_template_specialization (tree, int); static void dump_type (tree, int); static void dump_typename (tree, int); static void dump_simple_decl (tree, tree, int); @@ -330,6 +331,23 @@ dump_template_bindings (tree parms, tree args, VEC(tree,gc)* typenames) } } +/* Dump a human-readable equivalent of the alias template + specialization of T. */ + +static void +dump_alias_template_specialization (tree t, int flags) +{ + tree name; + + gcc_assert (alias_template_specialization_p (t)); + + name = TYPE_IDENTIFIER (t); + pp_cxx_tree_identifier (cxx_pp, name); + dump_template_parms (TYPE_TEMPLATE_INFO (t), + /*primary=*/false, + flags & ~TFF_TEMPLATE_HEADER); +} + /* Dump a human-readable equivalent of TYPE. FLAGS controls the format. */ @@ -344,10 +362,15 @@ dump_type (tree t, int flags) { tree decl = TYPE_NAME (t); if ((flags & TFF_CHASE_TYPEDEF) - || DECL_SELF_REFERENCE_P (decl) - || (!flag_pretty_templates - && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))) + || DECL_SELF_REFERENCE_P (decl) + || (!flag_pretty_templates + && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))) t = strip_typedefs (t); + else if (alias_template_specialization_p (t)) + { + dump_alias_template_specialization (t, flags); + return; + } else if (same_type_p (t, TREE_TYPE (decl))) t = decl; else @@ -588,7 +611,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 +639,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 +978,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"); @@ -1196,13 +1234,14 @@ dump_template_decl (tree t, int flags) } } - if (DECL_TEMPLATE_RESULT (t) - && TREE_CODE (DECL_TEMPLATE_RESULT (t)) == TYPE_DECL) + if (DECL_CLASS_TEMPLATE_P (t)) dump_type (TREE_TYPE (t), ((flags & ~TFF_CLASS_KEY_OR_ENUM) | TFF_TEMPLATE_NAME | (flags & TFF_DECL_SPECIFIERS ? TFF_CLASS_KEY_OR_ENUM : 0))); else if (DECL_TEMPLATE_RESULT (t) - && TREE_CODE (DECL_TEMPLATE_RESULT (t)) == VAR_DECL) + && (TREE_CODE (DECL_TEMPLATE_RESULT (t)) == VAR_DECL + /* Alias template. */ + || DECL_TYPE_TEMPLATE_P (t))) dump_decl (DECL_TEMPLATE_RESULT (t), flags | TFF_TEMPLATE_NAME); else { diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 2798eb7e7cb..fa0117ec3e4 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" @@ -5135,7 +5138,7 @@ cp_parser_nested_name_specifier (cp_parser *parser, this is either a class-name or a namespace-name (which corresponds to the class-or-namespace-name production in the grammar). For C++0x, it can also be a type-name that refers to an enumeration - type. + type or a simple-template-id. TYPENAME_KEYWORD_P is TRUE iff the `typename' keyword is in effect. TEMPLATE_KEYWORD_P is TRUE iff the `template' keyword is in effect. @@ -5211,8 +5214,8 @@ cp_parser_qualifying_entity (cp_parser *parser, /* Parse tentatively. */ cp_parser_parse_tentatively (parser); - /* Parse a typedef-name or enum-name. */ - scope = cp_parser_nonclass_name (parser); + /* Parse a type-name */ + scope = cp_parser_type_name (parser); /* "If the name found does not designate a namespace or a class, enumeration, or dependent type, the program is ill-formed." @@ -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,14 @@ 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_lexer_peek_nth_token (parser->lexer, 3)->keyword + == RID_ATTRIBUTE))) + cp_parser_alias_declaration (parser); /* Otherwise, it's a using-declaration. */ else cp_parser_using_declaration (parser, @@ -12343,7 +12354,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; @@ -13611,6 +13622,7 @@ cp_parser_simple_type_specifier (cp_parser* parser, class-name enum-name typedef-name + simple-template-id [in c++0x] enum-name: identifier @@ -13638,8 +13650,37 @@ cp_parser_type_name (cp_parser* parser) /* If it's not a class-name, keep looking. */ if (!cp_parser_parse_definitely (parser)) { - /* It must be a typedef-name or an enum-name. */ - return cp_parser_nonclass_name (parser); + if (cxx_dialect < cxx0x) + /* It must be a typedef-name or an enum-name. */ + return cp_parser_nonclass_name (parser); + + cp_parser_parse_tentatively (parser); + /* It is either a simple-template-id representing an + instantiation of an alias template... */ + type_decl = cp_parser_template_id (parser, + /*template_keyword_p=*/false, + /*check_dependency_p=*/false, + /*is_declaration=*/false); + /* Note that this must be an instantiation of an alias template + because [temp.names]/6 says: + + A template-id that names an alias template specialization + is a type-name. + + Whereas [temp.names]/7 says: + + A simple-template-id that names a class template + specialization is a class-name. */ + if (type_decl != NULL_TREE + && TREE_CODE (type_decl) == TYPE_DECL + && TYPE_DECL_ALIAS_P (type_decl)) + gcc_assert (DECL_TEMPLATE_INSTANTIATION (type_decl)); + else + cp_parser_simulate_error (parser); + + if (!cp_parser_parse_definitely (parser)) + /* ... Or a typedef-name or an enum-name. */ + return cp_parser_nonclass_name (parser); } return type_decl; @@ -14835,6 +14876,63 @@ cp_parser_using_declaration (cp_parser* parser, return true; } +/* Parse an alias-declaration. + + alias-declaration: + using identifier attribute-specifier-seq [opt] = type-id */ + +static tree +cp_parser_alias_declaration (cp_parser* parser) +{ + tree id, type, decl, dummy, attributes; + 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); + attributes = cp_parser_attributes_opt (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.attributes = attributes; + ++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, attributes); + else + decl = start_decl (declarator, &decl_specs, 0, + attributes, NULL_TREE, &dummy); + if (decl == error_mark_node) + return decl; + + cp_finish_decl (decl, NULL_TREE, 0, NULL_TREE, 0); + + /* If decl is a template, return its TEMPLATE_DECL so that it gets + added into the symbol table; otherwise, return the TYPE_DECL. */ + if (DECL_LANG_SPECIFIC (decl) + && DECL_TEMPLATE_INFO (decl) + && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl))) + decl = DECL_TI_TEMPLATE (decl); + return decl; +} + /* Parse a using-directive. using-directive: @@ -18532,6 +18630,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 @@ -18599,10 +18698,25 @@ cp_parser_member_declaration (cp_parser* parser) /* Check for a using-declaration. */ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING)) { - /* Parse the using-declaration. */ - cp_parser_using_declaration (parser, - /*access_declaration_p=*/false); - return; + if (cxx_dialect < cxx0x) + { + /* Parse the using-declaration. */ + cp_parser_using_declaration (parser, + /*access_declaration_p=*/false); + return; + } + else + { + tree decl; + cp_parser_parse_tentatively (parser); + decl = cp_parser_alias_declaration (parser); + if (cp_parser_parse_definitely (parser)) + finish_member_declaration (decl); + else + cp_parser_using_declaration (parser, + /*access_declaration_p=*/false); + return; + } } /* Check for @defs. */ @@ -20893,6 +21007,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 52f4d4730e3..c8c8d91b930 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -814,7 +814,13 @@ maybe_process_partial_specialization (tree type) context = TYPE_CONTEXT (type); - if (CLASS_TYPE_P (type) && CLASSTYPE_USE_TEMPLATE (type)) + if ((CLASS_TYPE_P (type) && CLASSTYPE_USE_TEMPLATE (type)) + /* Consider non-class instantiations of alias templates as + well. */ + || (TYPE_P (type) + && TYPE_TEMPLATE_INFO (type) + && DECL_LANG_SPECIFIC (TYPE_NAME (type)) + && DECL_USE_TEMPLATE (TYPE_NAME (type)))) { /* This is for ordinary explicit specialization and partial specialization of a template class such as: @@ -827,7 +833,8 @@ maybe_process_partial_specialization (tree type) Make sure that `C' and `C' are implicit instantiations. */ - if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) + if (CLASS_TYPE_P (type) + && CLASSTYPE_IMPLICIT_INSTANTIATION (type) && !COMPLETE_TYPE_P (type)) { check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (type)); @@ -839,8 +846,16 @@ maybe_process_partial_specialization (tree type) return error_mark_node; } } - else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)) + else if (CLASS_TYPE_P (type) + && CLASSTYPE_TEMPLATE_INSTANTIATION (type)) error ("specialization of %qT after instantiation", type); + + if (DECL_ALIAS_TEMPLATE_P (TYPE_TI_TEMPLATE (type))) + { + error ("partial specialization of alias template %qD", + TYPE_TI_TEMPLATE (type)); + return error_mark_node; + } } else if (CLASS_TYPE_P (type) && !CLASSTYPE_USE_TEMPLATE (type) @@ -2842,8 +2857,8 @@ make_ith_pack_parameter_name (tree name, int i) return get_identifier (newname); } -/* Return true if T is a primary function - or class template instantiation. */ +/* Return true if T is a primary function, class or alias template + instantiation. */ bool primary_template_instantiation_p (const_tree t) @@ -2858,6 +2873,11 @@ primary_template_instantiation_p (const_tree t) else if (CLASS_TYPE_P (t)) return CLASSTYPE_TEMPLATE_INSTANTIATION (t) && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)); + else if (TYPE_P (t) + && TYPE_TEMPLATE_INFO (t) + && PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (t)) + && DECL_TEMPLATE_INSTANTIATION (TYPE_NAME (t))) + return true; return false; } @@ -4831,6 +4851,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 +5119,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 +5288,32 @@ 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_NAME (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, @@ -7355,7 +7410,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 +7457,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. */ @@ -7393,14 +7474,17 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, else type_decl = TYPE_NAME (t); - TREE_PRIVATE (type_decl) - = TREE_PRIVATE (TYPE_STUB_DECL (template_type)); - TREE_PROTECTED (type_decl) - = TREE_PROTECTED (TYPE_STUB_DECL (template_type)); - if (CLASSTYPE_VISIBILITY_SPECIFIED (template_type)) + if (CLASS_TYPE_P (template_type)) { - DECL_VISIBILITY_SPECIFIED (type_decl) = 1; - DECL_VISIBILITY (type_decl) = CLASSTYPE_VISIBILITY (template_type); + TREE_PRIVATE (type_decl) + = TREE_PRIVATE (TYPE_STUB_DECL (template_type)); + TREE_PROTECTED (type_decl) + = TREE_PROTECTED (TYPE_STUB_DECL (template_type)); + if (CLASSTYPE_VISIBILITY_SPECIFIED (template_type)) + { + DECL_VISIBILITY_SPECIFIED (type_decl) = 1; + DECL_VISIBILITY (type_decl) = CLASSTYPE_VISIBILITY (template_type); + } } /* Let's consider the explicit specialization of a member @@ -7456,7 +7540,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, ++processing_template_decl; partial_inst_args = tsubst (INNERMOST_TEMPLATE_ARGS - (CLASSTYPE_TI_ARGS (TREE_TYPE (gen_tmpl))), + (TYPE_TI_ARGS (TREE_TYPE (gen_tmpl))), arglist, complain, NULL_TREE); --processing_template_decl; TREE_VEC_LENGTH (arglist)++; @@ -7480,7 +7564,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)); @@ -7508,7 +7600,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, the instantiation and exit above. */ tsubst_enum (template_type, t, arglist); - if (is_dependent_type) + if (CLASS_TYPE_P (template_type) && is_dependent_type) /* If the type makes use of template parameters, the code that generates debugging information will crash. */ DECL_IGNORED_P (TYPE_STUB_DECL (t)) = 1; @@ -9845,7 +9937,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_TEMPLATE_INFO (r) = build_template_info (t, args); - if (TREE_CODE (decl) == TYPE_DECL) + if (TREE_CODE (decl) == TYPE_DECL + && !TYPE_DECL_ALIAS_P (decl)) { tree new_type; ++processing_template_decl; @@ -10378,8 +10471,15 @@ 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 a member template; in which + case our caller can be willing to create a + specialization of that template represented + by T. */ + || !(DECL_TI_TEMPLATE (t) + && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (t))))) spec = t; } @@ -10860,7 +10960,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 @@ -10892,10 +10992,21 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) && typedef_variant_p (t)) { tree decl = TYPE_NAME (t); - - if (DECL_CLASS_SCOPE_P (decl) - && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl)) - && uses_template_parms (DECL_CONTEXT (decl))) + + if (TYPE_DECL_ALIAS_P (decl) + && DECL_LANG_SPECIFIC (decl) + && DECL_TEMPLATE_INFO (decl) + && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl))) + { + /* DECL represents an alias template and we want to + instantiate it. Let's substitute our arguments for the + template parameters into the declaration and get the + resulting type. */ + r = tsubst (decl, args, complain, decl); + } + else if (DECL_CLASS_SCOPE_P (decl) + && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl)) + && uses_template_parms (DECL_CONTEXT (decl))) { tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl)); tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl); @@ -11045,6 +11156,46 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (argvec == error_mark_node) return error_mark_node; + gcc_assert (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM + || TREE_CODE (arg) == TEMPLATE_DECL + || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE); + + if (TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE) + /* Consider this code: + + template