From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3834 invoked by alias); 7 Nov 2011 15:54:47 -0000 Received: (qmail 3815 invoked by uid 22791); 7 Nov 2011 15:54:40 -0000 X-SWARE-Spam-Status: No, hits=-6.6 required=5.0 tests=AWL,BAYES_00,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; Mon, 07 Nov 2011 15:54:21 +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 pA7FsLuf016430 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 7 Nov 2011 10:54:21 -0500 Received: from localhost (ovpn-116-53.ams2.redhat.com [10.36.116.53]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id pA7FsI7I009916 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 7 Nov 2011 10:54:20 -0500 Received: by localhost (Postfix, from userid 500) id 4A6FF29C12B; Mon, 7 Nov 2011 16:54:18 +0100 (CET) From: Dodji Seketeli To: Jason Merrill Cc: GCC Patches , Benjamin De Kosnik Subject: Re: [C++ PATCH] PR c++/45114 - Support alias templates References: <4EA9CB03.5060708@redhat.com> <4EB61005.5020001@redhat.com> X-URL: http://www.redhat.com Date: Mon, 07 Nov 2011 15:57:00 -0000 In-Reply-To: <4EB61005.5020001@redhat.com> (Jason Merrill's message of "Sun, 06 Nov 2011 00:41:41 -0400") 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-11/txt/msg00968.txt.bz2 > On 11/05/2011 07:36 PM, Dodji Seketeli wrote: > > +#define TYPE_DECL_NAMES_ALIAS_TEMPLATE_P(NODE) \ > > This doesn't seem to be needed anymore. Removed, thanks. > > > +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); > > + } > > Why do you treat class and non-class aliases differently? In both > cases I think we want alias specializations to be printed as > scope::name. We don't want to print 'class' since such a > specialization cannot be used in an > elaborated-type-specifier. I didn't realize the elaborated-type-specifier case. Fixed now. > > > + 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); > > The order of these two should be reversed. We want TFF_CHASE_TYPEDEF > and -fno-pretty-templates to strip alias-templates as well as > non-template typedefs. Fixed. > > > - /* If the next keyword is `namespace', we have a > > + /* If the next keyword is `namespace', we have either a > > namespace-alias-definition. */ > > This change seems unintended. Oops, fixed. Thanks. > > > + 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); > > I think the TYPE_DECL_ALIAS_P and DECL_TEMPLATE_INSTANTIATION checks > should be an assert instead; at this point any TYPE_DECL we get should > satisfy those. I did that initially and it revealed that the assertion can be violated by erroneous input code, e.g (in the test g++.dg/cpp0x/vt-34055.C): template struct B; template struct B // { dg-error "parameter packs|T" } { void foo(); }; Hence the recoverable error approach here. So I am now just asserting the DECL_TEMPLATE_INSTANTIATION when the TYPE_DECL is for an alias declaration. Is that better? > > > - || (TYPE_P (t) && TYPE_DECL_ALIAS_P (TYPE_NAME (t))) > > + || (TYPE_P (t) > > + && TYPE_NAME (t) > > + && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL > > + && TYPE_DECL_ALIAS_P (TYPE_NAME (t))) > > In C++ I think a non-null TYPE_NAME is always a TYPE_DECL. I wonder why I added that check there. Removed now. > > >> 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. > > Hmm. With this code we end up substituting into a non-template alias > declaration at file scope. Ah, I see. > I think if you check alias_template_specialization_p before checking > for class/function scope that should handle the cases you need. alias_template_specialization_p wouldn't work as we'd miss the case where we precisely want to build an instantiation from an alias template. So maybe the below is better? Thinking about that part of the code, I realized that the former patch didn't support (GNU extension) attributes so that part of the code wasn't tested enough. I have thus added new tests that are a slight modification of the g++.dg/cpp0x/ext/tmplattr*.C tests to use the alias-template syntax and exercise that part of the code. Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk. From: Dodji Seketeli 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_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. 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. * g++.dg/ext/alias-decl-attr1.C: Likewise. * g++.dg/ext/alias-decl-attr2.C: Likewise. * g++.dg/ext/alias-decl-attr3.C: Likewise. * g++.dg/ext/alias-decl-attr4.C: Likewise. --- gcc/cp/cp-tree.h | 46 +++++- gcc/cp/decl.c | 9 +- gcc/cp/decl2.c | 9 +- gcc/cp/error.c | 55 ++++++- gcc/cp/parser.c | 141 ++++++++++++++++-- gcc/cp/pt.c | 210 +++++++++++++++++++++++---- 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 + gcc/testsuite/g++.dg/ext/alias-decl-attr1.C | 19 +++ gcc/testsuite/g++.dg/ext/alias-decl-attr2.C | 42 ++++++ gcc/testsuite/g++.dg/ext/alias-decl-attr3.C | 21 +++ gcc/testsuite/g++.dg/ext/alias-decl-attr4.C | 34 +++++ 23 files changed, 806 insertions(+), 69 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 create mode 100644 gcc/testsuite/g++.dg/ext/alias-decl-attr1.C create mode 100644 gcc/testsuite/g++.dg/ext/alias-decl-attr2.C create mode 100644 gcc/testsuite/g++.dg/ext/alias-decl-attr3.C create mode 100644 gcc/testsuite/g++.dg/ext/alias-decl-attr4.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7ff1491..02ee289 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)) @@ -3619,12 +3635,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 +4606,7 @@ typedef enum cp_decl_spec { ds_explicit, ds_friend, ds_typedef, + ds_alias, ds_constexpr, ds_complex, ds_thread, @@ -5282,6 +5310,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 ("% 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..b592daa 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 090482c..00d6b02 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; @@ -14831,6 +14872,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: @@ -18528,6 +18626,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 +18694,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 +21003,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..2576483 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; @@ -9843,7 +9935,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 +10469,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 +10958,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 @@ -10890,10 +10990,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); @@ -11043,6 +11154,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