@@ -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);
@@ -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;
}
@@ -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;
}
@@ -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
{
@@ -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
@@ -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;
}
@@ -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))
{
@@ -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.
new file mode 100644
@@ -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);
+}
+
+
new file mode 100644
@@ -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" }
+};
new file mode 100644
@@ -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
new file mode 100644
@@ -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" }
+}
new file mode 100644
@@ -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;
new file mode 100644
@@ -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" }
new file mode 100644
@@ -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
+}
new file mode 100644
@@ -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;
new file mode 100644
@@ -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
+
new file mode 100644
@@ -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;
new file mode 100644
@@ -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;
+