Jason Merrill <ja...@redhat.com> writes: > On 10/27/2011 03:10 PM, Dodji Seketeli wrote: > > +/* 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)) > > This seems unnecessary.
Removed. > > > +#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)))) > > I don't think same_type_p is the test you want here, as it ignores > typedefs. How about > > DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (NODE)) == (NODE) Right. Changed. > ? > > > +#define TYPE_ALIAS_P(NODE) \ > > + (TYPE_P (NODE) \ > > + && DECL_LANG_SPECIFIC (TYPE_NAME (NODE)) \ > > + && TYPE_DECL_ALIAS_P (TYPE_NAME (NODE))) > > Why check DECL_LANG_SPECIFIC? I removed the check. > > > + /*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. */ > > I think we want to handle them specially within this if. Done. > > > - 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)) > > This change restricts the existing test to only apply to alias > templates. Removed. > > Also, I would think we would want to handle the uninstantiated alias > the same as instantiations. In the updated patch below, uninstantiated aliase types follow the same path as typedefs and are handled specifically by dump_decl, whereas alias instantiations are handled by the new dump_alias_template_specialization that knows how to handle class and non-class alias template instantiations. Is that bad? > > You need some tests for printing of aliases in error messages. Only > one of the current tests prints an alias: > > > /home/jason/gt/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C:5:26: error: > > partial specialization of alias template 'using AA0 = struct A0<int, T>' > > This should have the template header. So here: > > > + 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; > > + } > > We should pass the template to error, rather than the > instantiation. But when I try that I see that it prints > > template<class T, class U> struct AA0<T, U> > > instead, so more fixing is needed. Right. I tried to add more tests for that, and fixed many little things here and there to get better printing. > > > + 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; > > + } > > What is this trying to achieve? When we pass in a template, sometimes > it returns a type and sometimes a template? That seems odd. This is gone now, as it was for stripping aliases and I removed it now, see below. > > > + else > > + /* Strip template aliases from TEMPLATE_DECL nodes, > > + similarly to what is done by > > + canonicalize_type_argument for types above. */ > > + val = strip_alias (val); > > I don't think this is right. Alias templates are never deduced, but > that doesn't seem to mean that they can't be used as template template > arguments. Both clang and EDG accept this testcase: > > template <class T, class U> struct same; > template <class T> struct same<T,T> {}; > > template <class T> using Ptr = T*; > template <template <class> class T> struct A { > template <class U> using X = T<U>; > }; > same<A<Ptr>::X<int>,int*> s; I got confused by the fact that in the initial n2258 paper, the first test case of gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C was meant to pass. I didn't realize that it changed in the final draft. And you are right that the example above ought to pass. Also that example made me realize that I needed to do a bit more to support non-class alias template instantiations as well. I have added more test cases. > > > + 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))) > > I'm guessing that what this is trying to solve is the case of an > instantiation of a member alias template? Correct. > In that case the problem is > that the member is a template, and this code is assuming a > non-template member. Let's check for that instead of > alias-declarations, as the existing code ought to work fine for > regular alias members. Done, thanks. > > > + else if (TYPE_DECL_ALIAS_P (decl)) > > + /* fall through. */; > > Why not set r here, as for the other cases? Because I'd like to handle alias declarations even for cases handled by the other cases where, r is end up being NULL. > It seems like this way you will lose cv-quals added to an alias. Oops. I think I have fixed this now, thanks. Bootstrapped and tested on x86_64-unknown-linux-gnu. From: Dodji Seketeli <do...@redhat.com> Date: Fri, 30 Sep 2011 12:52:52 +0200 Subject: [PATCH] PR c++/45114 - Support alias templates gcc/cp/ * cp-tree.h (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_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 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;' (dump_template_decl): Support printing of alias templates. 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-6.C: Likewise. * g++.dg/cpp0x/alias-decl-7.C: Likewise. * g++.dg/cpp0x/alias-decl-8.C: Likewise. * g++.dg/cpp0x/alias-decl-9.C: Likewise. * g++.dg/cpp0x/alias-decl-10.C: Likewise. --- gcc/cp/cp-tree.h | 66 ++++++++- gcc/cp/decl.c | 9 +- gcc/cp/decl2.c | 9 +- gcc/cp/error.c | 61 +++++++-- gcc/cp/parser.c | 138 +++++++++++++++++-- gcc/cp/pt.c | 203 ++++++++++++++++++++++++--- gcc/cp/search.c | 6 +- gcc/cp/semantics.c | 14 +- gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C | 37 +++++ gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C | 15 ++ gcc/testsuite/g++.dg/cpp0x/alias-decl-10.C | 18 +++ gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C | 33 +++++ gcc/testsuite/g++.dg/cpp0x/alias-decl-3.C | 42 ++++++ gcc/testsuite/g++.dg/cpp0x/alias-decl-4.C | 14 ++ gcc/testsuite/g++.dg/cpp0x/alias-decl-5.C | 34 +++++ gcc/testsuite/g++.dg/cpp0x/alias-decl-6.C | 12 ++ gcc/testsuite/g++.dg/cpp0x/alias-decl-7.C | 23 +++ gcc/testsuite/g++.dg/cpp0x/alias-decl-8.C | 32 +++++ gcc/testsuite/g++.dg/cpp0x/alias-decl-9.C | 9 ++ 19 files changed, 708 insertions(+), 67 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-10.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 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-6.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-7.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-8.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-9.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7ff1491..9300947 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,37 @@ 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 if NODE is a TYPE_DECL for an instantiation that names an + alias template. For instance: + + template<class T, class U> struct S {}; + template<class T> using A = S<T, int>; + + template<class T> + struct C + { + typedef A<T> name_of_A; + }; + A<T> 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_TEMPLATE_INFO (NODE) \ + && DECL_TI_TEMPLATE (NODE) \ + && (DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (NODE)) == (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 +2629,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 +3655,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 +4626,7 @@ typedef enum cp_decl_spec { ds_explicit, ds_friend, ds_typedef, + ds_alias, ds_constexpr, ds_complex, ds_thread, @@ -5282,6 +5330,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..dac6670 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 ("%<typename %T::%D%> 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); @@ -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;'. */ + 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..a27154e 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,27 @@ 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) +{ + gcc_assert (alias_template_specialization_p (t)); + + if (CLASS_TYPE_P (t)) + dump_aggr_type (t, flags); + else + { + tree name; + 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. */ @@ -343,10 +365,15 @@ dump_type (tree t, int flags) if (TYPE_P (t) && typedef_variant_p (t)) { 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))) + if (alias_template_specialization_p (t)) + { + dump_alias_template_specialization (t, flags); + return; + } + else if ((flags & TFF_CHASE_TYPEDEF) + || DECL_SELF_REFERENCE_P (decl) + || (!flag_pretty_templates + && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))) t = strip_typedefs (t); else if (same_type_p (t, TREE_TYPE (decl))) t = decl; @@ -588,7 +615,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 +643,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 +982,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 +1238,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 090482c..c12e8d5 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." @@ -10146,12 +10149,12 @@ cp_parser_block_declaration (cp_parser *parser, cp_parser_commit_to_tentative_parse (parser); cp_parser_asm_definition (parser); } - /* If the next keyword is `namespace', we have a + /* If the next keyword is `namespace', we have either a 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; @@ -13611,6 +13620,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 +13648,36 @@ 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) + && DECL_TEMPLATE_INSTANTIATION (type_decl))) + 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; @@ -14831,6 +14869,61 @@ 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 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: @@ -18528,6 +18621,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 @@ -18595,10 +18689,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. */ @@ -20889,6 +20998,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..3f9cbd3 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<int>' and `C<T*>' 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,33 @@ 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) + && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL + && 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 +7411,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 +7458,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 +7475,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 +7541,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 +7565,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 +7601,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; @@ -9843,7 +9936,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; @@ -10376,8 +10470,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; } @@ -10858,7 +10959,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,10 +11004,21 @@ 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; + if (r == NULL_TREE && 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. */ + r = tsubst (decl, args, complain, decl); + } + if (r) { r = TREE_TYPE (r); @@ -11043,6 +11155,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 <template <class> class Template> + struct Internal { + template <class Arg> using Bind = Template<Arg>; + }; + + template <template <class> class Template, class Arg> + using Instantiate = Template<Arg>; //#0 + + template <template <class> class Template, + class Argument> + using Bind = + Instantiate<Internal<Template>::template Bind, + Argument>; //#1 + + When #1 is parsed, the + BOUND_TEMPLATE_TEMPLATE_PARM representing the + parameter `Template' in #0 matches the + UNBOUND_CLASS_TEMPLATE representing the argument + `Internal<Template>::template Bind'; We then want + to assemble the type `Bind<Argument>' that can't + be fully created right now, because + `Internal<Template>' not being complete, the Bind + template cannot be looked up in that context. So + we need to "store" `Bind<Argument>' for later + when the context of Bind becomes complete. Let's + store that in a TYPENAME_TYPE. */ + return make_typename_type (TYPE_CONTEXT (arg), + build_nt (TEMPLATE_ID_EXPR, + TYPE_IDENTIFIER (arg), + argvec), + typename_type, + complain); + /* We can get a TEMPLATE_TEMPLATE_PARM here when we are resolving nested-types in the signature of a member function templates. Otherwise ARG is a @@ -17608,7 +17760,12 @@ do_type_instantiation (tree t, tree storage, tsubst_flags_t complain) if (! CLASS_TYPE_P (t) || ! CLASSTYPE_TEMPLATE_INFO (t)) { - error ("explicit instantiation of non-template type %qT", t); + tree tmpl = + (TYPE_TEMPLATE_INFO (t)) ? TYPE_TI_TEMPLATE (t) : NULL; + if (tmpl) + error ("explicit instantiation of non-class template %qD", tmpl); + else + error ("explicit instantiation of non-template type %qT", t); return; } diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 97f593c..a59cd07 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -427,7 +427,7 @@ lookup_field_1 (tree type, tree name, bool want_type) field = fields[i--]; while (i >= lo && DECL_NAME (fields[i]) == name); if (TREE_CODE (field) != TYPE_DECL - && !DECL_CLASS_TEMPLATE_P (field)) + && !DECL_TYPE_TEMPLATE_P (field)) field = NULL_TREE; } else @@ -478,7 +478,7 @@ lookup_field_1 (tree type, tree name, bool want_type) if (DECL_NAME (field) == name && (!want_type || TREE_CODE (field) == TYPE_DECL - || DECL_CLASS_TEMPLATE_P (field))) + || DECL_TYPE_TEMPLATE_P (field))) return field; } /* Not found. */ @@ -1046,7 +1046,7 @@ lookup_field_r (tree binfo, void *data) /* If we're looking up a type (as with an elaborated type specifier) we ignore all non-types we find. */ if (lfi->want_type && TREE_CODE (nval) != TYPE_DECL - && !DECL_CLASS_TEMPLATE_P (nval)) + && !DECL_TYPE_TEMPLATE_P (nval)) { if (lfi->name == TYPE_IDENTIFIER (type)) { 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..c5760cf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C @@ -0,0 +1,37 @@ +// { dg-options "-std=c++0x" } + +template<template<class> class TT> struct X { }; +template<class> struct Y { }; +template<class T> using Z = Y<T>; + +void f(X<Y>); +void g(X<Z>); + +void +foo() +{ + // Below x and y don't have the same type, because Y and Z don't + // designate the same template ... + X<Y> y; + X<Z> z; + + // ... So these must fail to compile. + f(z); // { dg-error "" } + g(y); // { dg-error "" } +} + +template<class> struct A0 {}; +template<class T> using AA0 = A0<T>; +template<class T> using AAA0 = AA0<T>; + +void f0(A0<int>); +void +g0() +{ + AA0<int> a; + AAA0<int> 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..d0eda5f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C @@ -0,0 +1,15 @@ +// { dg-options "-std=c++0x" } + +// These also represent tests for printing alias declarations and +// their instantiations. + +template<class T, class U> struct A0 {}; +template<class T, class U> using AA0 = A0<T, U>; +template<class T> struct AA0<int, T> {}; // { dg-error "partial specialization" } + +template <class U> using Ptr = U*; +template<class U> struct Ptr<U*> {}; // { dg-error "partial specialization" } + +struct A { + using A = int;//{ dg-error "nested|has|same name as|class|in which|declared" } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-10.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-10.C new file mode 100644 index 0000000..856e429 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-10.C @@ -0,0 +1,18 @@ +// { dg-options "-std=c++0x" } + +template <class T> using Ptr = T*; +Ptr<unsigned>; // { dg-error "does not declare anything" } +Ptr<char><int>; // { dg-error "not a template|does not declare anything" } +template class Ptr<int>;//{ dg-error "explicit instantiation|non-class templ|does not decl|anything" } + +template <class T> using Arg = T; +struct A {}; +template class Arg<A>;// { dg-error "explicit instantiation|non-class templ" } + +template <template <class> class TT, class T> using Instantiate = TT<T>; +template <class> struct Vector {}; +template class Instantiate<Vector, int>; // OK Vector<int> can be explicitely instantiated + +template <class T> struct S {}; +template<class T> using SFor = S<T>; +template class SFor<int>; // OK, S<int> can be explicitely instantiated 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<class T> struct S0 {}; +template<class T> using AS0 = S0<T>; + +template<template<class> class TT> +void f(TT<int>); + +template class AS0<char>; + +void +foo() +{ + AS0<int> a; + f(a); +} + +template<class T, class U> struct Vector{}; +template<class T> struct Alloc {}; + +template<class T> using Vec = Vector<T, Alloc<T> >; + +template<class T> void g(Vector<T, Alloc<T> >); + +template<template<class T> class TT> void h(TT<int>); // { dg-error "provided for" } + +void +bar() +{ + Vec<int> 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..5484efc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-3.C @@ -0,0 +1,42 @@ +// { dg-options "-std=c++0x" } + +// Exercise some member alias templates ... + +template<class T, class U> class A0 {}; + +template<class T> +struct A1 { + template<class U> struct S {}; + template<class U> using AA0 = A0<T, U>; + + void f(A0<T, int>); + + void + foo() + { + AA0<int> a; + const AA0<int> b; + f(a); + f(b); + } +}; + +void +bar() +{ + A1<int> a1; + a1.foo(); + A1<int>::AA0<int> a1aa0; + a1.f(a1aa0); +} + +// ... some simple member alias ... +struct B { + using A = int; +}; + +B::A a; + +// ... and some simple alias + +using Int = int; 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 <class T> struct A; +template <class T> using B = typename A<T>::U; // { dg-error "type" } +template <class T> struct A { + typedef B<T> U; +}; +B<short> 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<class T, class U, class W> struct S0 {}; +template<class T, class U> struct S0<T, U, char> {}; +template<class T> using AS0 = S0<T, int, char>; +void foo(S0<bool, int, char>); + +AS0<bool> a; // OK + +void +f() +{ + foo(a); //OK +} + +// alias template of an explicit specialization of a member template + +template<class T> +struct S1 { + template<class U> + struct M {}; +}; +template<class T> using AM = S1<int>::M<T>; +void bar(S1<int>::M<bool>); + +AM<bool> b; //OK. + +void +g() +{ + bar(b); //OK +} diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-6.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-6.C new file mode 100644 index 0000000..f60b2ea --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-6.C @@ -0,0 +1,12 @@ +// { dg-options "-std=c++0x" } + +// Alias template of non-class types. + +template <class T, class U> struct same; +template <class T> struct same<T,T> {}; + +template <class T> using Ptr = T*; +template <template <class> class T> struct A { + template <class U> using X = T<U>; +}; +same<A<Ptr>::X<int>,int*> s; diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-7.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-7.C new file mode 100644 index 0000000..96c349a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-7.C @@ -0,0 +1,23 @@ +// { dg-options "-std=c++0x" } + +// Add arguments to unbound template template parameter. + +template <template <class> class Template> +struct Internal { + template <class Arg> using Bind = Template<Arg>; +}; + +template <template <class> class Template, class Arg> +using Instantiate = Template<Arg>; // After parsing #1, the + // BOUND_TEMPLATE_TEMPLATE_PARM + // parameter Template gets + // the UNBOUND_CLASS_TEMPLATE + // Internal<Template>::template Bind + // as an argument, and the + // parameter Arg gets Argument as + // an argument. And we build + // 'Bind<Argument>'. + +template <template <class> class Template, class Argument> +using Bind = Instantiate<Internal<Template>::template Bind, Argument>; //#1 + diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-8.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-8.C new file mode 100644 index 0000000..c926df7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-8.C @@ -0,0 +1,32 @@ +// { dg-options "-std=c++0x" } + +struct A { + template <class U> using C = U; +}; + +// The particularity of the below struct is to have more than 7 +// fields. In this case, looking up a member here should exercise +// cp/search.c:lookup_field_1 in such a way that it finds it in the +// CLASSTYPE_SORTED_FIELDS of struct A7. +struct A7 { + int f0; + int f1; + int f2; + int f3; + int f4; + int f5; + int f6; + int f7; + template <class U> using C = U; +}; + +template <class T> +struct B { + typename T::template C<int> n; //#0 +}; + +// These should trigger the lookup +// of template C inside class A or +// A7, via #0. +B<A> b; +B<A7> c; diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-9.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-9.C new file mode 100644 index 0000000..dcf642d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-9.C @@ -0,0 +1,9 @@ +// { dg-options "-std=c++0x" } + +template <class T> +struct A { + using Result = T; +}; +template <class A> using Arg = typename A::Result; +Arg<A<int>> b; + -- 1.7.6.4 -- Dodji