diff mbox

[C++] PR c++/45114 - Support alias templates

Message ID m34nyuz1vt.fsf@redhat.com
State New
Headers show

Commit Message

Dodji Seketeli Oct. 27, 2011, 7:10 p.m. UTC
Hello,

This patch adds support for the alias-declaration feature of the c++11
specification, introduced by the paper N2258[1] and voted into in the
standard.  It's a derivative work of a preliminary patch attached by
Jason Merrill to PR C++/45114[2].

alias-declaration introduces a new syntax for declaring an alias for a
type.  Exactly like a typedef.  E.g:

    template<class T> struct Vector {};
    using IntVect = Vector<int>;

The concept generalizes to families of types as well.  That is, you
can define an alias for a family of types -- dubbed alias template.
E.g:

    template<class Elements, class Allocator> struct Vector {};
    template<class T> struct MyAllocactor {};
    template<class T> using Vec = Vector<T, MyAllocator<T> >;

    Vec<int> v; // <-- this is equivalent to
		// Vector<int, MyAllocator<int> > v; Neat heh? :-)

The approach taken by the patch is to represent the alias of a type the
same way we represent a typedef today and mark it as type alias using a
flag.  An alias for a type T is thus a variant of T with a new type
name.

By extension an alias template is represented almost like a class
template except that its pattern is a variant of the type at the right
hand side of the '=' of the alias template declaration.

To represent a specialization of an alias template it's important to
notice that there are two "template info" at stake, unlike with normal
template specializations.  There is the template info of the alias
specialization itself and the one of the underlying type we are
aliasing.  The latter has been historically stored in
CLASSTYPE_TEMPLATE_INFO; now we hang the former off of the type name
of the alias.  Using the right template info helps here.  :-)

Substituting into an alias template means substituting for the
parameters of the alias template itself, but also for the parameters
of the type it aliases.  This part was easy as it's already mostly
handled by the typedef handling code we are based on.

Instantiating an alias template means just instantiating the type it
aliases.  This part is also taken care of by construction as the
alias*ed* type is the main variant of the alias type.  And we already
instantiate only the main variant type of a given type.

[1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf
[2]: http://gcc.gnu.org/PR45114

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

gcc/cp/

	* cp-tree.h (TYPE_DECL_ALIAS_P, SET_TYPE_DECL_ALIAS_P)
	(TYPE_DECL_NAMES_ALIAS_TEMPLATE_P, TYPE_ALIAS_P)
	(DECL_TYPE_TEMPLATE_P, DECL_ALIAS_TEMPLATE_P): New accessor macros.
	(TYPE_TEMPLATE_INFO): Get template info of an alias template
	specializations from its TYPE_DECL.
	(SET_TYPE_TEMPLATE_INFO): Set template info of alias template
	specializations into its TYPE_DECL.
	(DECL_CLASS_TEMPLATE_P): Re-write using the new
	DECL_TYPE_TEMPLATE_P.
	(enum cp_decl_spec): Add new ds_alias enumerator.
	(alias_type_or_template_p, alias_template_specialization_p):
	Declare new functions.
	* parser.c (cp_parser_alias_declaration): New static function.
	(cp_parser_check_decl_spec): Add "using" name for the `alias'
	declspec.
	(cp_parser_block_declaration): Handle alias-declaration in c++11.
	Update comment.
	(cp_parser_template_id): Handle specializations of alias
	templates.
	(cp_parser_member_declaration): Add alias-declaration production
	to comment.
	(cp_parser_template_declaration_after_export): Handle alias
	templates in c++11.
	* decl.c (grokdeclarator): Set TYPE_DECL_ALIAS_P on alias
	declarations.
	(grokfield): Move template creation after setting up the TYPE_DECL
	of the alias, so that the TEMPLATE_DECL of the alias template
	actually carries the right type-id of the alias declaration.
	* pt.c (get_aliased_type, strip_alias): New static functions.
	(alias_type_or_template_p)
	(alias_template_specialization_p): Define new public functions.
	(maybe_process_partial_specialization): Reject partial
	specializations of alias template.
	(push_template_decl_real): Assert that TYPE_DECLs of alias
	templates are different from those of class template.  Store
	template info onto the TYPE_DECL of the alias template.
	(convert_template_argument): Strip aliases from template
	arguments.
	(lookup_template_class_1): Handle the creation of the
	specialization of an alias template.
	(tsubst_decl): Create a substituted copy of the TYPE_DECL of an
	member alias template.
	(tsubst): Handle substituting into the type of an alias template.
	* semantics.c (finish_template_type): For alias templates, return
	the TYPE_DECL of the actual alias and not the one of the aliased
	type.
	* error.c (dump_type):  Print specialization of alias templates
	like we print specializations of class templates.  Also, handle
	the printing of alias templates.
	(dump_aggr_type): For specialization of alias templates, fetch
	arguments from the right place.
	(dump_decl): Print an alias-declaration like `using decl = type;'

gcc/testsuite/

	* g++.dg/cpp0x/alias-decl-0.C: New test case.
	* g++.dg/cpp0x/alias-decl-1.C: Likewise.
	* g++.dg/cpp0x/alias-decl-3.C: Likewise.
	* g++.dg/cpp0x/alias-decl-4.C: Likewise.
	* g++.dg/cpp0x/alias-decl-5.C: Likewise.
---
 gcc/cp/cp-tree.h                          |   70 ++++++++++++--
 gcc/cp/decl.c                             |    5 +
 gcc/cp/decl2.c                            |    9 +-
 gcc/cp/error.c                            |   31 +++++-
 gcc/cp/parser.c                           |   71 +++++++++++++-
 gcc/cp/pt.c                               |  153 +++++++++++++++++++++++++++--
 gcc/cp/semantics.c                        |   14 ++-
 gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C |   33 ++++++
 gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C |    5 +
 gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C |   33 ++++++
 gcc/testsuite/g++.dg/cpp0x/alias-decl-3.C |   29 ++++++
 gcc/testsuite/g++.dg/cpp0x/alias-decl-4.C |   14 +++
 gcc/testsuite/g++.dg/cpp0x/alias-decl-5.C |   34 +++++++
 13 files changed, 470 insertions(+), 31 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-3.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-4.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-5.C

Comments

Gabriel Dos Reis Oct. 27, 2011, 8:37 p.m. UTC | #1
On Thu, Oct 27, 2011 at 2:10 PM, Dodji Seketeli <dodji@redhat.com> wrote:
> Hello,
>
> This patch adds support for the alias-declaration feature of the c++11
> specification, introduced by the paper N2258[1] and voted into in the
> standard.  It's a derivative work of a preliminary patch attached by
> Jason Merrill to PR C++/45114[2].

Thanks for doing this.  Jason told me your were working on it.
As of this morning, I was wondering whether I should ping you :-).
The patch just printed; I will look over and give you my feedback.
There were a couple of things that were inadvertently changed
(at least that is what I was told when I spotted the change), and I would
like to make sure we have the specification as i was voted on.

Thanks,

-- Gaby
Jason Merrill Oct. 27, 2011, 9:20 p.m. UTC | #2
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.

> +#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)

?

> +#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?

> +      /*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.

> -      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.

Also, I would think we would want to handle the uninstantiated alias the 
same as instantiations.

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.

> +  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.

> +      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;

> +               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?  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.

> +      else if (TYPE_DECL_ALIAS_P (decl))
> +       /* fall through.  */;

Why not set r here, as for the other cases?  It seems like this way you 
will lose cv-quals added to an alias.

Jason
diff mbox

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7ff1491..98971a5 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -139,6 +139,7 @@  c-common.h, not after.
    5: DECL_INTERFACE_KNOWN.
    6: DECL_THIS_STATIC (in VAR_DECL or FUNCTION_DECL).
       DECL_FIELD_IS_BASE (in FIELD_DECL)
+      TYPE_DECL_ALIAS_P (in TYPE_DECL)
    7: DECL_DEAD_FOR_LOCAL (in VAR_DECL).
       DECL_THUNK_P (in a member FUNCTION_DECL)
       DECL_NORMAL_CAPTURE_P (in FIELD_DECL)
@@ -2541,6 +2542,41 @@  extern void decl_shadowed_for_var_insert (tree, tree);
 #define DECL_PENDING_INLINE_INFO(NODE) \
   (LANG_DECL_FN_CHECK (NODE)->u.pending_inline_info)
 
+/* Nonzero for TYPE_DECL means that it was written 'using name = type'.  */
+#define TYPE_DECL_ALIAS_P(NODE) \
+  DECL_LANG_FLAG_6 (TYPE_DECL_CHECK (NODE))
+
+/* Setter for the TYPE_DECL_ALIAS_P proprety above.  */
+#define SET_TYPE_DECL_ALIAS_P(NODE, VAL)		\
+  (DECL_LANG_FLAG_6 (TYPE_DECL_CHECK (NODE)) = (VAL))
+
+/* Nonzero if NODE is a TYPE_DECL for an instantiation that names an
+   alias template.  For instance:
+
+       template<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> is just "names A" because its list of argument is the
+  same a the list of parameters of the template A.  */
+#define TYPE_DECL_NAMES_ALIAS_TEMPLATE_P(NODE)				\
+  (TYPE_DECL_ALIAS_P (NODE)						\
+   && DECL_LANG_SPECIFIC (NODE)						\
+   && DECL_TI_TEMPLATE (NODE)						\
+   && same_type_p (TREE_TYPE (NODE), TREE_TYPE (DECL_TI_TEMPLATE (NODE))))
+
+/* Nonzero for a type which is an alias for another type; i.e, a type
+   which declaration was written 'using name-of-type =
+   another-type'.  */
+#define TYPE_ALIAS_P(NODE) \
+  (TYPE_P (NODE) \
+   && DECL_LANG_SPECIFIC (TYPE_NAME (NODE))	\
+   && TYPE_DECL_ALIAS_P (TYPE_NAME (NODE)))
+
 /* For a class type: if this structure has many fields, we'll sort them
    and put them into a TREE_VEC.  */
 #define CLASSTYPE_SORTED_FIELDS(NODE) \
@@ -2597,16 +2633,20 @@  extern void decl_shadowed_for_var_insert (tree, tree);
    ? ENUM_TEMPLATE_INFO (NODE) :			\
    (TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM	\
     ? TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (NODE) :	\
-    (TYPE_LANG_SPECIFIC (NODE)				\
+    ((CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE))	\
      ? CLASSTYPE_TEMPLATE_INFO (NODE)			\
-     : NULL_TREE)))
+     : (DECL_LANG_SPECIFIC (TYPE_NAME (NODE))		\
+	? (DECL_TEMPLATE_INFO (TYPE_NAME (NODE)))	\
+	: NULL_TREE))))
 
 /* Set the template information for an ENUMERAL_, RECORD_, or
    UNION_TYPE to VAL.  */
-#define SET_TYPE_TEMPLATE_INFO(NODE, VAL)	\
-  (TREE_CODE (NODE) == ENUMERAL_TYPE		\
-   ? (ENUM_TEMPLATE_INFO (NODE) = (VAL))	\
-   : (CLASSTYPE_TEMPLATE_INFO (NODE) = (VAL)))
+#define SET_TYPE_TEMPLATE_INFO(NODE, VAL)				\
+  (TREE_CODE (NODE) == ENUMERAL_TYPE					\
+   ? (ENUM_TEMPLATE_INFO (NODE) = (VAL))				\
+   : ((CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE))			\
+      ? (CLASSTYPE_TEMPLATE_INFO (NODE) = (VAL))			\
+      : (DECL_TEMPLATE_INFO (TYPE_NAME (NODE)) = (VAL))))
 
 #define TI_TEMPLATE(NODE) TREE_TYPE (TEMPLATE_INFO_CHECK (NODE))
 #define TI_ARGS(NODE) TREE_CHAIN (TEMPLATE_INFO_CHECK (NODE))
@@ -3619,12 +3659,23 @@  more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
    && !DECL_UNBOUND_CLASS_TEMPLATE_P (NODE) \
    && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == FUNCTION_DECL)
 
-/* Nonzero for a DECL that represents a template class.  */
-#define DECL_CLASS_TEMPLATE_P(NODE)				\
+/* Nonzero for a DECL that represents a class template or alias
+   template.  */
+#define DECL_TYPE_TEMPLATE_P(NODE)				\
   (TREE_CODE (NODE) == TEMPLATE_DECL				\
    && DECL_TEMPLATE_RESULT (NODE) != NULL_TREE			\
+   && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == TYPE_DECL)
+
+/* Nonzero for a DECL that represents a class template.  */
+#define DECL_CLASS_TEMPLATE_P(NODE)				\
+  (DECL_TYPE_TEMPLATE_P (NODE)					\
    && DECL_IMPLICIT_TYPEDEF_P (DECL_TEMPLATE_RESULT (NODE)))
 
+/* Nonzero for a TEMPLATE_DECL that represents an alias template.  */
+#define DECL_ALIAS_TEMPLATE_P(NODE)			\
+  (DECL_TYPE_TEMPLATE_P (NODE)				\
+   && !DECL_ARTIFICIAL (DECL_TEMPLATE_RESULT (NODE)))
+
 /* Nonzero for a NODE which declares a type.  */
 #define DECL_DECLARES_TYPE_P(NODE) \
   (TREE_CODE (NODE) == TYPE_DECL || DECL_CLASS_TEMPLATE_P (NODE))
@@ -4579,6 +4630,7 @@  typedef enum cp_decl_spec {
   ds_explicit,
   ds_friend,
   ds_typedef,
+  ds_alias,
   ds_constexpr,
   ds_complex,
   ds_thread,
@@ -5282,6 +5334,8 @@  extern tree build_non_dependent_expr		(tree);
 extern void make_args_non_dependent		(VEC(tree,gc) *);
 extern bool reregister_specialization		(tree, tree, tree);
 extern tree fold_non_dependent_expr		(tree);
+extern bool alias_type_or_template_p            (tree);
+extern bool alias_template_specialization_p     (tree);
 extern bool explicit_class_specialization_p     (tree);
 extern int push_tinst_level                     (tree);
 extern void pop_tinst_level                     (void);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 860556c..8e84f3d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -9790,6 +9790,11 @@  grokdeclarator (const cp_declarator *declarator,
 		      memfn_quals != TYPE_UNQUALIFIED,
 		      inlinep, friendp, raises != NULL_TREE);
 
+      if (declspecs->specs[(int)ds_alias])
+	/* Acknowledge that this was written:
+	     `using analias = atype;'.  */
+	SET_TYPE_DECL_ALIAS_P (decl, 1);
+
       return decl;
     }
 
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 9851ece..b230d95 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -847,9 +847,6 @@  grokfield (const cp_declarator *declarator,
       DECL_NONLOCAL (value) = 1;
       DECL_CONTEXT (value) = current_class_type;
 
-      if (processing_template_decl)
-	value = push_template_decl (value);
-
       if (attrlist)
 	{
 	  int attrflags = 0;
@@ -868,6 +865,12 @@  grokfield (const cp_declarator *declarator,
           && TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (value))) != value)
 	set_underlying_type (value);
 
+      /* It's important that push_template_decl below follows
+	 set_underlying_type above so that the created template
+	 carries the properly set type of VALUE.  */
+      if (processing_template_decl)
+	value = push_template_decl (value);
+
       record_locally_defined_typedef (value);
       return value;
     }
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 544c4d1..1e8f2e4 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -340,7 +340,11 @@  dump_type (tree t, int flags)
     return;
 
   /* Don't print e.g. "struct mytypedef".  */
-  if (TYPE_P (t) && typedef_variant_p (t))
+  if (TYPE_P (t) && typedef_variant_p (t)
+      /*If T is a specialization of an alias template, then we don't
+	want to take this 'if' branch; we want to print it as if it
+	was a specialization of class template.  */
+      && !alias_template_specialization_p (t))
     {
       tree decl = TYPE_NAME (t);
       if ((flags & TFF_CHASE_TYPEDEF)
@@ -348,7 +352,11 @@  dump_type (tree t, int flags)
 	  || (!flag_pretty_templates
 	      && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)))
 	t = strip_typedefs (t);
-      else if (same_type_p (t, TREE_TYPE (decl)))
+      else if (same_type_p (t, TREE_TYPE (decl))
+	       && /* If T is the type of an alias template then we
+		     want to let dump_decl print it like an alias
+		     template.  */
+	       TYPE_DECL_NAMES_ALIAS_TEMPLATE_P (decl))
 	t = decl;
       else
 	{
@@ -588,7 +596,10 @@  dump_aggr_type (tree t, int flags)
 
   if (name)
     {
-      typdef = !DECL_ARTIFICIAL (name);
+      typdef = (!DECL_ARTIFICIAL (name)
+		/* An alias specialization is not considered to be a
+		   typedef.  */
+		&& !alias_template_specialization_p (t));
 
       if ((typdef
 	   && ((flags & TFF_CHASE_TYPEDEF)
@@ -613,7 +624,7 @@  dump_aggr_type (tree t, int flags)
 	{
 	  /* Because the template names are mangled, we have to locate
 	     the most general template, and use that name.  */
-	  tree tpl = CLASSTYPE_TI_TEMPLATE (t);
+	  tree tpl = TYPE_TI_TEMPLATE (t);
 
 	  while (DECL_TEMPLATE_INFO (tpl))
 	    tpl = DECL_TI_TEMPLATE (tpl);
@@ -952,6 +963,18 @@  dump_decl (tree t, int flags)
 	  dump_type (TREE_TYPE (t), flags);
 	  break;
 	}
+      if (TYPE_DECL_ALIAS_P (t)
+	  && (flags & TFF_DECL_SPECIFIERS
+	      || flags & TFF_CLASS_KEY_OR_ENUM))
+	{
+	  pp_cxx_ws_string (cxx_pp, "using");
+	  dump_decl (DECL_NAME (t), flags);
+	  pp_cxx_whitespace (cxx_pp);
+	  pp_cxx_ws_string (cxx_pp, "=");
+	  pp_cxx_whitespace (cxx_pp);
+	  dump_type (DECL_ORIGINAL_TYPE (t), flags);
+	  break;
+	}
       if ((flags & TFF_DECL_SPECIFIERS)
 	  && !DECL_SELF_REFERENCE_P (t))
 	pp_cxx_ws_string (cxx_pp, "typedef");
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 090482c..cb8c188 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1935,6 +1935,8 @@  static bool cp_parser_using_declaration
   (cp_parser *, bool);
 static void cp_parser_using_directive
   (cp_parser *);
+static tree cp_parser_alias_declaration
+  (cp_parser *);
 static void cp_parser_asm_definition
   (cp_parser *);
 static void cp_parser_linkage_specification
@@ -2509,6 +2511,7 @@  cp_parser_check_decl_spec (cp_decl_specifier_seq *decl_specs,
 	    "explicit",
 	    "friend",
 	    "typedef",
+	    "using",
             "constexpr",
 	    "__complex",
 	    "__thread"
@@ -10150,8 +10153,8 @@  cp_parser_block_declaration (cp_parser *parser,
      namespace-alias-definition.  */
   else if (token1->keyword == RID_NAMESPACE)
     cp_parser_namespace_alias_definition (parser);
-  /* If the next keyword is `using', we have either a
-     using-declaration or a using-directive.  */
+  /* If the next keyword is `using', we have a
+     using-declaration, a using-directive, or an alias-declaration.  */
   else if (token1->keyword == RID_USING)
     {
       cp_token *token2;
@@ -10163,6 +10166,12 @@  cp_parser_block_declaration (cp_parser *parser,
       token2 = cp_lexer_peek_nth_token (parser->lexer, 2);
       if (token2->keyword == RID_NAMESPACE)
 	cp_parser_using_directive (parser);
+      /* If the second token after 'using' is '=', then we have an
+	 alias-declaration.  */
+      else if (cxx_dialect >= cxx0x
+	       && token2->type == CPP_NAME
+	       && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ)
+	cp_parser_alias_declaration (parser);
       /* Otherwise, it's a using-declaration.  */
       else
 	cp_parser_using_declaration (parser,
@@ -12343,7 +12352,7 @@  cp_parser_template_id (cp_parser *parser,
   /* Build a representation of the specialization.  */
   if (TREE_CODE (templ) == IDENTIFIER_NODE)
     template_id = build_min_nt (TEMPLATE_ID_EXPR, templ, arguments);
-  else if (DECL_CLASS_TEMPLATE_P (templ)
+  else if (DECL_TYPE_TEMPLATE_P (templ)
 	   || DECL_TEMPLATE_TEMPLATE_PARM_P (templ))
     {
       bool entering_scope;
@@ -14831,6 +14840,58 @@  cp_parser_using_declaration (cp_parser* parser,
   return true;
 }
 
+/* Parse an alias-declaration.
+
+   alias-declaration:
+     using identifier = type-id  */
+
+static tree
+cp_parser_alias_declaration (cp_parser* parser)
+{
+  tree id, type, decl, dummy;
+  location_t id_location;
+  cp_declarator *declarator;
+  cp_decl_specifier_seq decl_specs;
+
+  /* Look for the `using' keyword.  */
+  cp_parser_require_keyword (parser, RID_USING, RT_USING);
+  id_location = cp_lexer_peek_token (parser->lexer)->location;
+  id = cp_parser_identifier (parser);
+  cp_parser_require (parser, CPP_EQ, RT_EQ);
+
+  type = cp_parser_type_id (parser);
+
+  /* A typedef-name can also be introduced by an alias-declaration. The
+     identifier following the using keyword becomes a typedef-name. It has
+     the same semantics as if it were introduced by the typedef
+     specifier. In particular, it does not define a new type and it shall
+     not appear in the type-id.  */
+
+  clear_decl_specs (&decl_specs);
+  decl_specs.type = type;
+  ++decl_specs.specs[(int) ds_typedef];
+  ++decl_specs.specs[(int) ds_alias];
+
+  declarator = make_id_declarator (NULL_TREE, id, sfk_none);
+  declarator->id_loc = id_location;
+
+  if (at_class_scope_p ())
+    decl = grokfield (declarator, &decl_specs, NULL_TREE, false,
+		      NULL_TREE, NULL_TREE);
+  else
+    decl = start_decl (declarator, &decl_specs, 0,
+		       NULL_TREE, NULL_TREE, &dummy);
+  if (decl == error_mark_node)
+    return decl;
+
+  cp_finish_decl (decl, NULL_TREE, 0, NULL_TREE, 0);
+
+  if (DECL_LANG_SPECIFIC (decl)
+      && DECL_TI_TEMPLATE (decl))
+    decl = DECL_TI_TEMPLATE (decl);
+  return decl;
+}
+
 /* Parse a using-directive.
 
    using-directive:
@@ -18528,6 +18589,7 @@  cp_parser_member_specification_opt (cp_parser* parser)
      :: [opt] nested-name-specifier template [opt] unqualified-id ;
      using-declaration
      template-declaration
+     alias-declaration
 
    member-declarator-list:
      member-declarator
@@ -20889,6 +20951,9 @@  cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
   if (cp_lexer_next_token_is_keyword (parser->lexer,
 				      RID_TEMPLATE))
     cp_parser_template_declaration_after_export (parser, member_p);
+  else if (cxx_dialect >= cxx0x
+	   && cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
+    decl = cp_parser_alias_declaration (parser);
   else
     {
       /* There are no access checks when parsing a template, as we do not
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7aea72d..01b65fb 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -841,6 +841,13 @@  maybe_process_partial_specialization (tree type)
 	}
       else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type))
 	error ("specialization of %qT after instantiation", type);
+
+      if (DECL_ALIAS_TEMPLATE_P (TI_TEMPLATE (get_template_info (type))))
+	{
+	  error ("partial specialization of alias template %qD",
+		 TYPE_NAME (type));
+	  return error_mark_node;
+	}
     }
   else if (CLASS_TYPE_P (type)
 	   && !CLASSTYPE_USE_TEMPLATE (type)
@@ -4831,6 +4838,10 @@  push_template_decl_real (tree decl, bool is_friend)
       else if (DECL_IMPLICIT_TYPEDEF_P (decl)
 	       && CLASS_TYPE_P (TREE_TYPE (decl)))
 	/* OK */;
+      else if (TREE_CODE (decl) == TYPE_DECL
+	       && TYPE_DECL_ALIAS_P (decl))
+	/* alias-declaration */
+	gcc_assert (!DECL_ARTIFICIAL (decl));
       else
 	{
 	  error ("template declaration of %q#D", decl);
@@ -5095,8 +5106,13 @@  template arguments to %qD do not match original template %qD",
 
   if (DECL_IMPLICIT_TYPEDEF_P (decl))
     SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
-  else if (DECL_LANG_SPECIFIC (decl))
-    DECL_TEMPLATE_INFO (decl) = info;
+  else
+    {
+      if (primary && !DECL_LANG_SPECIFIC (decl))
+	retrofit_lang_decl (decl);
+      if (DECL_LANG_SPECIFIC (decl))
+	DECL_TEMPLATE_INFO (decl) = info;
+    }
 
   return DECL_TEMPLATE_RESULT (tmpl);
 }
@@ -5259,6 +5275,30 @@  fold_non_dependent_expr (tree expr)
   return fold_non_dependent_expr_sfinae (expr, tf_error);
 }
 
+/* Return TRUE iff T is a type alias, a TEMPLATE_DECL for an alias
+   template declaration, or a TYPE_DECL for an alias declaration.  */
+
+bool
+alias_type_or_template_p (tree t)
+{
+  if (t == NULL_TREE)
+    return false;
+  return ((TREE_CODE (t) == TYPE_DECL && TYPE_DECL_ALIAS_P (t))
+	  || (TYPE_P (t) && TYPE_DECL_ALIAS_P (TYPE_NAME (t)))
+	  || DECL_ALIAS_TEMPLATE_P (t));
+}
+
+/* Return TRUE iff is a specialization of an alias template.  */
+
+bool
+alias_template_specialization_p (tree t)
+{
+  if (t == NULL_TREE)
+    return false;
+  return (primary_template_instantiation_p (t)
+	  && DECL_ALIAS_TEMPLATE_P (TYPE_TI_TEMPLATE (t)));
+}
+
 /* Subroutine of convert_nontype_argument. Converts EXPR to TYPE, which
    must be a function or a pointer-to-function type, as specified
    in [temp.arg.nontype]: disambiguate EXPR if it is an overload set,
@@ -5979,6 +6019,45 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
   return expr;
 }
 
+/* If T represents an alias declaration, return its underlying aliased
+   type.  */
+
+static tree
+get_aliased_type (tree t)
+{
+  tree result = t;
+
+  if (t == NULL_TREE)
+    /* return t */;
+  else if (TREE_CODE (t) == TYPE_DECL && TYPE_DECL_ALIAS_P (t))
+    result = DECL_ORIGINAL_TYPE (t);
+  else if (TYPE_P (t) && TYPE_DECL_ALIAS_P (TYPE_NAME (t)))
+    result = DECL_ORIGINAL_TYPE (TYPE_NAME (t));
+  else if (DECL_ALIAS_TEMPLATE_P (t))
+    {
+      tree tmpl;
+      result = get_aliased_type (DECL_TEMPLATE_RESULT (t));
+      tmpl = TI_TEMPLATE (get_template_info (result));
+      /* If RESULT is just the naming of TMPL, return TMPL.  */
+      if (same_type_p (result,
+		       TREE_TYPE (DECL_TEMPLATE_RESULT (tmpl))))
+	result = tmpl;
+    }
+
+  return result;
+}
+
+/* Return the most underlying type of a type alias or alias
+   template.  */
+
+static tree
+strip_alias (tree t)
+{
+  while (alias_type_or_template_p (t))
+    t = get_aliased_type (t);
+  return t;
+}
+
 /* Subroutine of coerce_template_template_parms, which returns 1 if
    PARM_PARM and ARG_PARM match using the rule for the template
    parameters of template template parameters. Both PARM and ARG are
@@ -6433,6 +6512,11 @@  convert_template_argument (tree parm,
 	 themselves also use the typedef.  */
       if (TYPE_P (val))
 	val = canonicalize_type_argument (val, complain);
+      else
+	/* Strip template aliases from TEMPLATE_DECL nodes,
+	   similarly to what is done by
+	   canonicalize_type_argument for types above.  */
+	val = strip_alias (val);
     }
   else
     {
@@ -7355,7 +7439,31 @@  lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 	  ENUM_FIXED_UNDERLYING_TYPE_P (t)
 	    = ENUM_FIXED_UNDERLYING_TYPE_P (template_type);
 	}
-      else
+      else if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
+	{
+	  /* The user referred to a specialization of an alias
+	    template represented by GEN_TMPL.
+
+	    [temp.alias]/2 says:
+
+	        When a template-id refers to the specialization of an
+		alias template, it is equivalent to the associated
+		type obtained by substitution of its
+		template-arguments for the template-parameters in the
+		type-id of the alias template.  */
+
+	  t = tsubst (TREE_TYPE (gen_tmpl), arglist, complain, in_decl);
+	  /* Note that the call above (by indirectly calling
+	     register_specialization in tsubst_decl) registers the
+	     TYPE_DECL representing the specialization of the alias
+	     template.  So next time someone substitutes ARGLIST for
+	     the template parms into the alias template (GEN_TMPL),
+	     she'll get that TYPE_DECL back.  */
+
+	  if (t == error_mark_node)
+	    return t;
+	}
+      else if (CLASS_TYPE_P (template_type))
 	{
 	  t = make_class_type (TREE_CODE (template_type));
 	  CLASSTYPE_DECLARED_CLASS (t)
@@ -7378,6 +7486,8 @@  lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 	       structural equality testing. */
 	    SET_TYPE_STRUCTURAL_EQUALITY (t);
 	}
+      else
+	gcc_unreachable ();
 
       /* If we called start_enum or pushtag above, this information
 	 will already be set up.  */
@@ -7480,7 +7590,15 @@  lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 	  TREE_VEC_LENGTH (arglist)--;
 	  found = tsubst (gen_tmpl, arglist, complain, NULL_TREE);
 	  TREE_VEC_LENGTH (arglist)++;
-	  found = CLASSTYPE_TI_TEMPLATE (found);
+	  /* FOUND is either a proper class type, or an alias
+	     template specialization.  In the later case, it's a
+	     TYPE_DECL, resulting from the substituting of arguments
+	     for parameters in the TYPE_DECL of the alias template
+	     done earlier.  So be careful while getting the template
+	     of FOUND.  */
+	  found = TREE_CODE (found) == TYPE_DECL
+	    ? TYPE_TI_TEMPLATE (TREE_TYPE (found))
+	    : CLASSTYPE_TI_TEMPLATE (found);
 	}
 
       SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist));
@@ -10376,8 +10494,18 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 		   referencing a static data member within in its own
 		   class.  We can use pointer equality, rather than
 		   same_type_p, because DECL_CONTEXT is always
-		   canonical.  */
-		if (ctx == DECL_CONTEXT (t))
+		   canonical...  */
+		if (ctx == DECL_CONTEXT (t)
+		    && (TREE_CODE (t) != TYPE_DECL
+			/* ... unless T is an alias declaration; in
+			   which case our caller can be willing to
+			   create a specialization of the alias
+			   template represented by T.  If we hand her
+			   T, she is going to clobber it.  So we'll
+			   contruct a new T in this case, just like
+			   for the case where T is not a class
+			   member.  */
+			|| !TYPE_DECL_ALIAS_P (t)))
 		  spec = t;
 	      }
 
@@ -10858,7 +10986,7 @@  tree
 tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 {
   enum tree_code code;
-  tree type, r;
+  tree type, r = NULL_TREE;
 
   if (t == NULL_TREE || t == error_mark_node
       || t == integer_type_node
@@ -10903,6 +11031,8 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	       && DECL_TEMPLATE_INFO (DECL_CONTEXT (decl))
 	       && uses_template_parms (DECL_TI_ARGS (DECL_CONTEXT (decl))))
 	r = retrieve_local_specialization (decl);
+      else if (TYPE_DECL_ALIAS_P (decl))
+	/* fall through.  */;
       else
 	/* The typedef is from a non-template context.  */
 	return t;
@@ -10915,6 +11045,15 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	     complain | tf_ignore_bad_quals);
 	  return r;
 	}
+      else if (TYPE_DECL_ALIAS_P (decl))
+	{
+	  /* DECL represents an alias declaration, possibly an alias
+	     template.  Let's substitute our arguments for the
+	     template parameters into the declaration and get the
+	     resulting type.  */
+	  tree type_decl = tsubst (decl, args, complain, decl);
+	  return TREE_TYPE (type_decl);
+	}
       /* Else we must be instantiating the typedef, so fall through.  */
     }
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index fa8ab99..7be828e 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2733,15 +2733,17 @@  finish_template_decl (tree parms)
 tree
 finish_template_type (tree name, tree args, int entering_scope)
 {
-  tree decl;
+  tree type;
 
-  decl = lookup_template_class (name, args,
+  type = lookup_template_class (name, args,
 				NULL_TREE, NULL_TREE, entering_scope,
 				tf_warning_or_error | tf_user);
-  if (decl != error_mark_node)
-    decl = TYPE_STUB_DECL (decl);
-
-  return decl;
+  if (type == error_mark_node)
+    return type;
+  else if (CLASS_TYPE_P (type) && !alias_type_or_template_p (type))
+    return TYPE_STUB_DECL (type);
+  else
+    return TYPE_NAME (type);
 }
 
 /* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER.
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C
new file mode 100644
index 0000000..abc56ff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C
@@ -0,0 +1,33 @@ 
+// { dg-options "-std=c++0x" }
+
+template<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()
+{
+  X<Y> y;
+  X<Z> z;
+  f(z);
+  g(y);
+}
+
+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..f1c4b94
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C
@@ -0,0 +1,5 @@ 
+// { dg-options "-std=c++0x" }
+
+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" }
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..b7460f3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-3.C
@@ -0,0 +1,29 @@ 
+// { dg-options "-std=c++0x" }
+
+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);
+}
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
+}