diff mbox

[1/2] Use TEMPLATE_ID_TYPE in lieu of BOUND_TEMPLATE_TEMPLATE_PARM

Message ID m3k465big3.fsf_-_@redhat.com
State New
Headers show

Commit Message

Dodji Seketeli Dec. 9, 2011, 8:26 p.m. UTC
As presented in the cover message, this patch replaces the
BOUND_TEMPLATE_TEMPLATE_PARM tree with a TEMPLATE_ID_TYPE tree that
represents a template-id whose arguments haven't yet been applied to
its template.  The template itself might have not been resolved to a
TEMPLATE_DECL yet, in which case it's just an IDENTIFIER_NODE.

The functionality of representing BOUND_TEMPLATE_TEMPLATE_PARM then
gets expressed by using a TEMPLATE_ID_TYPE in which the template
validates the DECL_TEMPLATE_TEMPLATE_PARAMETER_P predicate.

Additionally, the TYPENAME_TYPE_FULLNAME of a TYPENAME_TYPE is also
represented using a TEMPLATE_ID_TYPE, rather than a TEMPLATE_ID_EXPR -
even when make_typename_type is passed a TEMPLATE_ID_EXPR.  Note that
the TEMPLATE_ID_TYPE yielded by TYPENAME_TYPE_FULLNAME can either have
a TEMPLATE_DECL or just an IDENTIFIER_NODE, depending on if the
template name of the template-id could be resolved to a template at
the point where the typename was formed or not.

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

gcc/cp/

	PR c++/51239
	* cp_tree.def (TEMPLATE_TYPE_PARM): Rename
	BOUND_TEMPLATE_TEMPLATE_PARM into TEMPLATE_ID_TYPE in comments.
	(TEMPLATE_ID_TYPE): Renamed BOUND_TEMPLATE_TEMPLATE_PARM into
	this.  Update comments.
	* cp-tree.h (build_template_id_type):
	(TEMPLATE_ID_TYPE_TYPE_CHECK): Turn
	BOUND_TEMPLATE_TEMPLATE_PARM_TYPE_CHECK into this.
	(BOUND_TEMPLATE_TEMPLATE_PARM_P): New predicate macro.
	(MAYBE_CLASS_TYPE_P): Rename BOUND_TEMPLATE_TEMPLATE_PARM into
	TEMPLATE_ID_TYPE.
	(TEMPLATE_ID_TYPE_TEMPLATE_INFO): Turn
	TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO into this.
	(TYPE_TEMPLATE_INFO): Support TEMPLATE_ID_TYPE.
	(SET_TYPE_TEMPLATE_INFO): Update to support TEMPLATE_ID_TYPE, and
	to better support type aliases.
	(TYPENAME_TYPE_FULLNAME): Replace TEMPLATE_ID_EXPR with
	TEMPLATE_ID_TYPE in comments.
	(TEMPLATE_TYPE_PARM_INDEX): Rename BOUND_TEMPLATE_TEMPLATE_PARM
	into TEMPLATE_ID_TYPE in the definition of this macro.
	(TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL): Use
	BOUND_TEMPLATE_TEMPLATE_PARM_P instead of
	BOUND_TEMPLATE_TEMPLATE_PARM.
	* cp-objcp-common.c (cp_common_init_ts): Rename
	BOUND_TEMPLATE_TEMPLATE_PARM into TEMPLATE_ID_TYPE.
	* cxx-pretty-print.c (pp_cxx_unqualified_id)<TEMPLATE_ID_TYPE>:
	Renamed BOUND_TEMPLATE_TEMPLATE_PARM into this.
	(pp_cxx_type_specifier_seq)<TEMPLATE_ID_TYPE>: Likewise.
	(pp_cxx_direct_abstract_declarator)<TEMPLATE_ID_TYPE>>: Likewise.
	(pp_cxx_type_id)<TEMPLATE_ID_TYPE>: Likewise.
	(pp_cxx_canonical_template_parameter): Use
	BOUND_TEMPLATE_TEMPLATE_PARM_P instead of
	BOUND_TEMPLATE_TEMPLATE_PARM.
	* decl.c (make_typename_type): Store unbound template-id in a
	TEMPLATE_ID_TYPE instead of in a TEMPLATE_ID_EXPR.
	(check_elaborated_type_specifier): Use
	BOUND_TEMPLATE_TEMPLATE_PARM_P instead of
	BOUND_TEMPLATE_TEMPLATE_PARM.
	* decl2.c (is_late_template_attribute): Use
	BOUND_TEMPLATE_TEMPLATE_PARM_P instead of
	BOUND_TEMPLATE_TEMPLATE_PARM.
	* error.c (dump_type)<TEMPLATE_ID_TYPE>: Replace
	BOUND_TEMPLATE_TEMPLATE_PARM with this.
	(dump_typename): Use dump_type on  TYPENAME_TYPE_FULLNAME rather
	than dump_decl.
	(dump_type_prefix, dump_type_suffix, dump_expr)<TEMPLATE_ID_TYPE>:
	Replace BOUND_TEMPLATE_TEMPLATE_PARM with this.
	* lex.c (cxx_make_type): Replace BOUND_TEMPLATE_TEMPLATE_PARM with
	TEMPLATE_ID_TYPE.
	* mangle.c (CLASSTYPE_TEMPLATE_ID_P): Replace use of
	BOUND_TEMPLATE_TEMPLATE_PARM with BOUND_TEMPLATE_TEMPLATE_PARM_P.
	(write_nested_name, write_prefix): Replace use of TEMPLATE_ID_EXPR
	with TEMPLATE_ID_TYPE.  Use TYPE_TI_ARGS on the
	TYPENAME_TYPE_FULLNAME rather than TREE_OPERAND.
	(write_type)<TEMPLATE_ID_TYPE>: Replace
	BOUND_TEMPLATE_TEMPLATE_PARM with this.  Use TYPE_TI_ARGS rather
	than TI_ARGS of TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO.
	(write_expression): USe BOUND_TEMPLATE_TEMPLATE_PARM_P instead of
	BOUND_TEMPLATE_TEMPLATE_PARM.
	(write_template_param)<TEMPLATE_ID_TYPE>: Replace
	BOUND_TEMPLATE_TEMPLATE_PARM with this.
	(write_template_template_param): Use
	BOUND_TEMPLATE_TEMPLATE_PARM_P instead of
	BOUND_TEMPLATE_TEMPLATE_PARM, TYPE_TEMPLATE_INFO instead of
	TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO.
	* name-lookup.c (arg_assoc_type)<TEMPLATE_ID_TYPE>: Rename
	BOUND_TEMPLATE_TEMPLATE_PARM into this.
	* parser.c (cp_parser_nested_name_specifier_opt): Replace
	TEMPLATE_ID_EXPR with TEMPLATE_ID_TYPE.
	* pt.c (get_template_info): Use TYPE_TEMPLATE_INFO to get
	TEMPLATE_INFO from types in general.
	(maybe_process_partial_specialization): Use
	BOUND_TEMPLATE_TEMPLATE_PARM_P instead of
	BOUND_TEMPLATE_TEMPLATE_PARM.
	(find_parameter_packs_r): Replaced case
	BOUND_TEMPLATE_TEMPLATE_PARM with case TEMPLATE_ID_TYPE.  Check
	for TYPE_TI_TEMPLATE before walking it.
	(lookup_template_class_1): Propagate error if arglist is
	erroneous.
	(for_each_template_parm_r)<TEMPLATE_ID_TYPE>: Replaced
	BOUND_TEMPLATE_TEMPLATE_PARM with this.  Use
	BOUND_TEMPLATE_TEMPLATE_PARM_P.
	(for_each_template_parm): Replace BOUND_TEMPLATE_TEMPLATE_PARM
	with TEMPLATE_ID_TYPE in comments.
	(tsubst)<TEMPLATE_ID_TYPE>: Replace BOUND_TEMPLATE_TEMPLATE_PARM
	with this.  Handle TEMPLATE_ID_TYPE.  Replace use of
	TEMPLATE_ID_EXPR in make_typename_type with
	build_template_id_type.  Use BOUND_TEMPLATE_TEMPLATE_PARM_P.
	(tsubst_copy)<TEMPLATE_ID_TYPE>: Replace use of
	BOUND_TEMPLATE_TEMPLATE_PARM with this.
	(template_parm_level_and_index): Replace use of
	BOUND_TEMPLATE_TEMPLATE_PARM with BOUND_TEMPLATE_TEMPLATE_PARM_P.
	(unify)<TEMPLATE_ID_TYPE>: Replace use of
	BOUND_TEMPLATE_TEMPLATE_PARM with this.  Use
	BOUND_TEMPLATE_TEMPLATE_PARM_P.
	(dependent_type_p_r): Replace use of BOUND_TEMPLATE_TEMPLATE_PARM
	with BOUND_TEMPLATE_TEMPLATE_PARM_P.
	(resolve_typename_type): TYPENAME_TYPE_FULLNAME now yields
	TEMPLATE_ID_TYPE, no more TEMPLATE_ID_EXPR.
	* ptree.c (cxx_print_type)<TEMPLATE_ID_TYPE>: Replace
	BOUND_TEMPLATE_TEMPLATE_PARM with this.
	* search.c (lookup_field_1): Replace use of
	BOUND_TEMPLATE_TEMPLATE_PARM with BOUND_TEMPLATE_TEMPLATE_PARM_P.
	* tree.c (build_template_id_type): Define new function.
	(bind_template_template_parm): Use the new build_template_id_type.
	(cp_walk_tree)<TEMPLATE_ID_TYPE>: Replace
	BOUND_TEMPLATE_TEMPLATE_PARM with this.
	* typeck.c (comp_template_parms_position): Replace use of
	BOUND_TEMPLATE_TEMPLATE_PARM with BOUND_TEMPLATE_TEMPLATE_PARM_P.
	(structural_comptypes): Compare TEMPLATE_ID_TYPE nodes not
	BOUND_TEMPLATE_TEMPLATE_PARM.
	* typeck2.c (cxx_incomplete_type_diagnostic)<TEMPLATE_ID_TYPE>: Replace
	BOUND_TEMPLATE_TEMPLATE_PARM with this.  Adjust diagnostic.
---
 gcc/cp/cp-objcp-common.c  |    2 +-
 gcc/cp/cp-tree.def        |   17 ++++---
 gcc/cp/cp-tree.h          |   55 ++++++++++++++--------
 gcc/cp/cxx-pretty-print.c |   10 ++--
 gcc/cp/decl.c             |   22 ++++++---
 gcc/cp/decl2.c            |    4 +-
 gcc/cp/error.c            |   10 ++--
 gcc/cp/lex.c              |    2 +-
 gcc/cp/mangle.c           |   26 +++++-----
 gcc/cp/name-lookup.c      |    2 +-
 gcc/cp/parser.c           |    2 +-
 gcc/cp/pt.c               |  114 ++++++++++++++++++++++++++++++---------------
 gcc/cp/ptree.c            |    6 ++-
 gcc/cp/search.c           |    2 +-
 gcc/cp/tree.c             |   64 +++++++++++++++++--------
 gcc/cp/typeck.c           |   18 ++++++-
 gcc/cp/typeck2.c          |   13 ++++--
 17 files changed, 237 insertions(+), 132 deletions(-)

Comments

Jason Merrill Dec. 10, 2011, 4:42 p.m. UTC | #1
On 12/09/2011 03:26 PM, Dodji Seketeli wrote:

Two overall comments:

1) Yeah, let's hold this for 4.8.
2) TEMPLATE_ID_TYPE in this patch is too closely related to 
BOUND_TEMPLATE_TEMPLATE_PARM; I'd like to see all the 
BOUND_TEMPLATE_TEMPLATE_PARM_P checks go away so that things know how to 
handle TEMPLATE_ID_TYPE and they know how to handle 
TEMPLATE_TEMPLATE_PARM, but the combination of the two is not handled 
specially.

>   #define TEMPLATE_TYPE_PARM_INDEX(NODE)					\
>     (TYPE_VALUES_RAW (TREE_CHECK3 ((NODE), TEMPLATE_TYPE_PARM,		\
>   				 TEMPLATE_TEMPLATE_PARM,		\
> -				 BOUND_TEMPLATE_TEMPLATE_PARM)))
> +				 TEMPLATE_ID_TYPE)))

A TEMPLATE_ID_TYPE shouldn't have a parm index.

>    /* Brings type template parameters to the canonical forms.  */
>    if (code == TEMPLATE_TYPE_PARM || code == TEMPLATE_TEMPLATE_PARM
> -      || code == BOUND_TEMPLATE_TEMPLATE_PARM)
> +      || BOUND_TEMPLATE_TEMPLATE_PARM_P (parm))
>      parm = TEMPLATE_TYPE_PARM_INDEX (parm);

Do we still need to handle this case here?

>    /* Accept bound template template parameters.  */
>    else if (allow_template_p
> -	   && TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
> +	   && BOUND_TEMPLATE_TEMPLATE_PARM_P (type))

Do we want to allow all TEMPLATE_ID_TYPE here?

>        /* We can't apply any attributes to a completely unknown type until
>  	 instantiation time.  */
>        enum tree_code code = TREE_CODE (type);
> -      if (code == TEMPLATE_TYPE_PARM
> -	  || code == BOUND_TEMPLATE_TEMPLATE_PARM
> +      if (BOUND_TEMPLATE_TEMPLATE_PARM_P (type)
> +	  ||code == TEMPLATE_TYPE_PARM
>  	  || code == TYPENAME_TYPE)

And here?

>    /* Create lang_type structure.  */
>    if (RECORD_OR_UNION_CODE_P (code)
> -      || code == BOUND_TEMPLATE_TEMPLATE_PARM)
> +      || code == TEMPLATE_ID_TYPE)

TEMPLATE_ID_TYPE doesn't need the whole 80 bytes of lang_type; it only 
needs one more tree outside of type_common.  Since currently 
tree_code_size treats all types as being type_non_common, let's use 
TYPE_VALUES_RAW, TYPE_MINVAL, or TYPE_MAXVAL for TYPE_TEMPLATE_INFO of a 
TEMPLATE_ID_TYPE so it doesn't need TYPE_LANG_SPECIFIC at all.

>  #define CLASSTYPE_TEMPLATE_ID_P(NODE)					\
>    (TYPE_LANG_SPECIFIC (NODE) != NULL					\
> -   && (TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM			\
> +   && (BOUND_TEMPLATE_TEMPLATE_PARM_P (NODE)				\
>         || (CLASSTYPE_TEMPLATE_INFO (NODE) != NULL			\
>  	   && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))))))

I think that with alias templates this should be renamed to 
TYPE_TEMPLATE_ID_P, and it should support all TEMPLATE_ID_TYPE.  And the 
first use of CLASSTYPE_TEMPLATE_ID_P should drop the CLASS_TYPE_P check.

>    /* Handle template parameters.  */
>    if (code == TEMPLATE_TYPE_PARM
>        || code == TEMPLATE_TEMPLATE_PARM
> -      || code == BOUND_TEMPLATE_TEMPLATE_PARM
> +      || BOUND_TEMPLATE_TEMPLATE_PARM_P (expr)
>        || code == TEMPLATE_PARM_INDEX)
>      write_template_param (expr);
>    /* Handle literals.  */
> @@ -2995,9 +2995,10 @@ write_template_param (const tree parm)
>
>    switch (TREE_CODE (parm))
>      {
> +    case TEMPLATE_ID_TYPE:
> +      gcc_assert (BOUND_TEMPLATE_TEMPLATE_PARM_P (parm));
>      case TEMPLATE_TYPE_PARM:
>      case TEMPLATE_TEMPLATE_PARM:
> -    case BOUND_TEMPLATE_TEMPLATE_PARM:
>        parm_index = TEMPLATE_TYPE_IDX (parm);
>        break;

We shouldn't need to handle TEMPLATE_ID_TYPE at all here; our normal 
handling of TEMPLATE_ID_TYPE should look through to the underlying 
TEMPLATE_TEMPLATE_PARM, and then that comes here.

> -  if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
> +  if (BOUND_TEMPLATE_TEMPLATE_PARM_P (parm))
>      {
> -      templ
> -	= TI_TEMPLATE (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parm));
> +      templ = TI_TEMPLATE (TYPE_TEMPLATE_INFO (parm));
>        if (find_substitution (templ))
>  	return;
>      }

Likewise.

> @@ -5330,7 +5330,7 @@ arg_assoc_type (struct arg_lookup *k, tree type)
>        /* Associate the return type.  */
>        return arg_assoc_type (k, TREE_TYPE (type));
>      case TEMPLATE_TYPE_PARM:
> -    case BOUND_TEMPLATE_TEMPLATE_PARM:
> +    case TEMPLATE_ID_TYPE:
>        return false;

This code was already wrong; as in arg_assoc_class, we should look at 
the associated namespaces of the template arguments.

> -    case BOUND_TEMPLATE_TEMPLATE_PARM:
> +    case TEMPLATE_ID_TYPE:
>        /* Record template parameters such as `T' inside `TT<T>'.  */
>        if (for_each_template_parm (TYPE_TI_ARGS (t), fn, data, pfd->visited,
>  				  pfd->include_nondeduced_p))
>  	return error_mark_node;
> +
> +      if (!BOUND_TEMPLATE_TEMPLATE_PARM_P (t))
> +	break;
> +
>        /* Fall through.  */

Instead of falling through, the handling of TEMPLATE_ID_TYPE should walk 
into TYPE_TI_TEMPLATE.

>      case TEMPLATE_TYPE_PARM:
>      case TEMPLATE_TEMPLATE_PARM:
> -    case BOUND_TEMPLATE_TEMPLATE_PARM:
> +    case TEMPLATE_ID_TYPE:
>      case TEMPLATE_PARM_INDEX:

TEMPLATE_ID_TYPE should get its own case, and we should be able to 
handle template template parms and other uses the same way.

> @@ -15851,7 +15891,7 @@ template_parm_level_and_index (tree parm, int* level, int* index)
>  {
>    if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
>        || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
> -      || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
> +      || BOUND_TEMPLATE_TEMPLATE_PARM_P (parm))

And we shouldn't need to handle it here.

> @@ -16216,9 +16256,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
>  	 within the nested-name-specifier.  */
>        return unify_success (explain_p);
>
> +    case TEMPLATE_ID_TYPE:
> +      gcc_assert (BOUND_TEMPLATE_TEMPLATE_PARM_P (parm));

And it should get its own code here, since presumably we can deduce 
template arguments from the non-bound-template-template-parm usage as well.

> +    case TEMPLATE_ID_TYPE:
> +      if (BOUND_TEMPLATE_TEMPLATE_PARM_P (node))
> +	/* Fall through.  */;
> +      else
> +	break;

Own code.

>    if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
> -      || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM
> +      || BOUND_TEMPLATE_TEMPLATE_PARM_P (type)
>        || TREE_CODE (type) == TYPENAME_TYPE)

This should allow all TEMPLATE_ID_TYPE.

> @@ -1129,7 +1129,7 @@ comp_template_parms_position (tree t1, tree t2)
>    tree index1, index2;
>    gcc_assert (t1 && t2
>  	      && TREE_CODE (t1) == TREE_CODE (t2)
> -	      && (TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM
> +	      && (BOUND_TEMPLATE_TEMPLATE_PARM_P (t1)
>  		  || TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM
>  		  || TREE_CODE (t1) == TEMPLATE_TYPE_PARM));

Shouldn't need to handle any TEMPLATE_ID_TYPE.

> +    case TEMPLATE_ID_TYPE:
> +      if (!BOUND_TEMPLATE_TEMPLATE_PARM_P (t1))
> +	{
> +	  if (!cp_tree_equal (TYPE_TI_TEMPLATE (t1),
> +			      TYPE_TI_TEMPLATE (t2)))
> +	    return false;
> +	  return comp_template_args (TYPE_TI_ARGS (t1),
> +				     TYPE_TI_ARGS (t2));
> +	}
> +      else
> +	{
> +	  /* Fall through.  */;
> +	}

Should handle all TEMPLATE_ID_TYPE the same.

>      case UNION_TYPE:
>        if (TYPE_TEMPLATE_INFO (t1) && TYPE_TEMPLATE_INFO (t2)
>  	  && (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2)
> -	      || TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM)
> +	      || BOUND_TEMPLATE_TEMPLATE_PARM_P (t1))
>  	  && comp_template_args (TYPE_TI_ARGS (t1), TYPE_TI_ARGS (t2)))

Should handle all TEMPLATE_ID_TYPE.

Jason
diff mbox

Patch

diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index a957a03..719ec77 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -246,7 +246,7 @@  cp_common_init_ts (void)
   MARK_TS_COMMON (TYPE_PACK_EXPANSION);
   MARK_TS_COMMON (TYPE_ARGUMENT_PACK);
   MARK_TS_COMMON (DECLTYPE_TYPE);
-  MARK_TS_COMMON (BOUND_TEMPLATE_TEMPLATE_PARM);
+  MARK_TS_COMMON (TEMPLATE_ID_TYPE);
   MARK_TS_COMMON (UNBOUND_CLASS_TEMPLATE);
 
   MARK_TS_TYPED (EXPR_PACK_EXPANSION);
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 5fc5496..c68274c 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -172,7 +172,7 @@  DEFTREECODE (TEMPLATE_TEMPLATE_PARM, "template_template_parm", tcc_type, 0)
 /* The ordering of the following codes is optimized for the checking
    macros in tree.h.  Changing the order will degrade the speed of the
    compiler.  TEMPLATE_TYPE_PARM, TYPENAME_TYPE, TYPEOF_TYPE,
-   BOUND_TEMPLATE_TEMPLATE_PARM.  */
+   TEMPLATE_ID_TYPE.  */
 
 /* Index into a template parameter list.  This parameter must be a type.
    The type.values field will be a TEMPLATE_PARM_INDEX.  */
@@ -180,7 +180,7 @@  DEFTREECODE (TEMPLATE_TYPE_PARM, "template_type_parm", tcc_type, 0)
 
 /* A type designated by `typename T::t'.  TYPE_CONTEXT is `T',
    TYPE_NAME is an IDENTIFIER_NODE for `t'.  If the type was named via
-   template-id, TYPENAME_TYPE_FULLNAME will hold the TEMPLATE_ID_EXPR.
+   template-id, TYPENAME_TYPE_FULLNAME will hold the TEMPLATE_ID_TYPE.
    TREE_TYPE is always NULL.  */
 DEFTREECODE (TYPENAME_TYPE, "typename_type", tcc_type, 0)
 
@@ -188,12 +188,13 @@  DEFTREECODE (TYPENAME_TYPE, "typename_type", tcc_type, 0)
    expression in question.  */
 DEFTREECODE (TYPEOF_TYPE, "typeof_type", tcc_type, 0)
 
-/* Like TEMPLATE_TEMPLATE_PARM it is used with bound template arguments
-   like TT<int>.
-   In this case, TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO contains the
-   template name and its bound arguments.  TYPE_NAME is a TYPE_DECL.  */
-DEFTREECODE (BOUND_TEMPLATE_TEMPLATE_PARM, "bound_template_template_parm",
-	     tcc_type, 0)
+/* A generic type for a template-id (templatename<arguments>) in which
+   the arguments have not yet been applied to the template.  The
+   TEMPLATE_ID_TYPE_TEMPLATE_INFO accessor returns the TEMPLATE_INFO
+   of the type, TYPE_TI_TEMPLATE returns the TEMPLATE_DECL of the
+   type, and TYPE_TI_ARGS returns the arguments.  TYPE_NAME is a
+   TYPE_DECL.  */
+DEFTREECODE (TEMPLATE_ID_TYPE, "template_id_type", tcc_type, 0)
 
 /* For template template argument of the form `T::template C'.
    TYPE_CONTEXT is `T', the template parameter dependent object.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 955d0eb..fa5bf7f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -206,8 +206,8 @@  c-common.h, not after.
 #define VAR_TEMPL_TYPE_FIELD_OR_FUNCTION_DECL_CHECK(NODE) \
   TREE_CHECK5(NODE,VAR_DECL,FIELD_DECL,FUNCTION_DECL,TYPE_DECL,TEMPLATE_DECL)
 
-#define BOUND_TEMPLATE_TEMPLATE_PARM_TYPE_CHECK(NODE) \
-  TREE_CHECK(NODE,BOUND_TEMPLATE_TEMPLATE_PARM)
+#define TEMPLATE_ID_TYPE_TYPE_CHECK(NODE) \
+  TREE_CHECK(NODE,TEMPLATE_ID_TYPE)
 
 #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
 #define THUNK_FUNCTION_CHECK(NODE) __extension__			\
@@ -1191,11 +1191,11 @@  enum languages { lang_c, lang_cplusplus, lang_java };
    template template parameters.  Keep these checks in ascending code
    order.  */
 #define MAYBE_CLASS_TYPE_P(T)					\
-  (TREE_CODE (T) == TEMPLATE_TYPE_PARM			\
-   || TREE_CODE (T) == TYPENAME_TYPE			\
-   || TREE_CODE (T) == TYPEOF_TYPE			\
-   || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM	\
-   || TREE_CODE (T) == DECLTYPE_TYPE			\
+  (TREE_CODE (T) == TEMPLATE_TYPE_PARM				\
+   || TREE_CODE (T) == TYPENAME_TYPE				\
+   || TREE_CODE (T) == TYPEOF_TYPE				\
+   || TREE_CODE (T) == TEMPLATE_ID_TYPE				\
+   || TREE_CODE (T) == DECLTYPE_TYPE				\
    || CLASS_TYPE_P (T))
 
 /* Set CLASS_TYPE_P for T to VAL.  T must be a class, struct, or
@@ -2604,8 +2604,8 @@  extern void decl_shadowed_for_var_insert (tree, tree);
   (TYPE_LANG_SLOT_1 (ENUMERAL_TYPE_CHECK (NODE)))
 
 /* Template information for a template template parameter.  */
-#define TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO(NODE) \
-  (LANG_TYPE_CLASS_CHECK (BOUND_TEMPLATE_TEMPLATE_PARM_TYPE_CHECK (NODE)) \
+#define TEMPLATE_ID_TYPE_TEMPLATE_INFO(NODE) \
+  (LANG_TYPE_CLASS_CHECK (TEMPLATE_ID_TYPE_TYPE_CHECK (NODE)) \
    ->template_info)
 
 /* Template information for an ENUMERAL_, RECORD_, UNION_TYPE, or
@@ -2620,21 +2620,26 @@  extern void decl_shadowed_for_var_insert (tree, tree);
       : NULL_TREE)							\
    : ((TREE_CODE (NODE) == ENUMERAL_TYPE)				\
       ? ENUM_TEMPLATE_INFO (NODE)					\
-      : ((TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM)		\
-	 ? TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (NODE)			\
+      : ((TREE_CODE (NODE) == TEMPLATE_ID_TYPE)				\
+	 ? TEMPLATE_ID_TYPE_TEMPLATE_INFO (NODE)			\
 	 : (CLASS_TYPE_P (NODE)						\
 	    ? CLASSTYPE_TEMPLATE_INFO (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))				\
-   : ((CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE))			\
-      ? (CLASSTYPE_TEMPLATE_INFO (NODE) = (VAL))			\
-      : (DECL_TEMPLATE_INFO (TYPE_NAME (NODE)) = (VAL))))
+  (TYPE_ALIAS_P (NODE)							\
+   ? ((TYPE_NAME (NODE) && DECL_LANG_SPECIFIC (TYPE_NAME (NODE)))	\
+      ? DECL_TEMPLATE_INFO (TYPE_NAME (NODE)) = (VAL)			\
+      : NULL_TREE)							\
+   : ((TREE_CODE (NODE) == ENUMERAL_TYPE)				\
+      ? ENUM_TEMPLATE_INFO (NODE) = (VAL)				\
+      : ((TREE_CODE (NODE) == TEMPLATE_ID_TYPE)				\
+	 ? TEMPLATE_ID_TYPE_TEMPLATE_INFO (NODE) = (VAL)		\
+	 : (CLASS_TYPE_P (NODE)						\
+	    ? CLASSTYPE_TEMPLATE_INFO (NODE) = (VAL)			\
+	    : NULL_TREE))))
 
 #define TI_TEMPLATE(NODE) TREE_TYPE (TEMPLATE_INFO_CHECK (NODE))
 #define TI_ARGS(NODE) TREE_CHAIN (TEMPLATE_INFO_CHECK (NODE))
@@ -3028,7 +3033,7 @@  more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 /* The name used by the user to name the typename type.  Typically,
    this is an IDENTIFIER_NODE, and the same as the DECL_NAME on the
    corresponding TYPE_DECL.  However, this may also be a
-   TEMPLATE_ID_EXPR if we had something like `typename X::Y<T>'.  */
+   TEMPLATE_ID_TYPE if we had something like `typename X::Y<T>'.  */
 #define TYPENAME_TYPE_FULLNAME(NODE) \
   (TYPE_VALUES_RAW (TYPENAME_TYPE_CHECK (NODE)))
 
@@ -3650,6 +3655,15 @@  more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define DECL_UNBOUND_CLASS_TEMPLATE_P(NODE) \
   (TREE_CODE (NODE) == TEMPLATE_DECL && !DECL_TEMPLATE_RESULT (NODE))
 
+/* Nonzero if NODE is a TEMPLATE_ID_TYPE representing a bound template
+   template parameter;  that is a template-id whose template is a
+   template template parameter.  */
+#define BOUND_TEMPLATE_TEMPLATE_PARM_P(NODE)			\
+  ((NODE) != NULL_TREE						\
+   && TREE_CODE (NODE) == TEMPLATE_ID_TYPE			\
+   && TYPE_TI_TEMPLATE (NODE) != NULL_TREE			\
+   && DECL_TEMPLATE_TEMPLATE_PARM_P (TYPE_TI_TEMPLATE (NODE)))
+
 #define DECL_FUNCTION_TEMPLATE_P(NODE)  \
   (TREE_CODE (NODE) == TEMPLATE_DECL \
    && !DECL_UNBOUND_CLASS_TEMPLATE_P (NODE) \
@@ -4503,7 +4517,7 @@  enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 #define TEMPLATE_TYPE_PARM_INDEX(NODE)					\
   (TYPE_VALUES_RAW (TREE_CHECK3 ((NODE), TEMPLATE_TYPE_PARM,		\
 				 TEMPLATE_TEMPLATE_PARM,		\
-				 BOUND_TEMPLATE_TEMPLATE_PARM)))
+				 TEMPLATE_ID_TYPE)))
 #define TEMPLATE_TYPE_IDX(NODE) \
   (TEMPLATE_PARM_IDX (TEMPLATE_TYPE_PARM_INDEX (NODE)))
 #define TEMPLATE_TYPE_LEVEL(NODE) \
@@ -4554,7 +4568,7 @@  enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 /* Returns the TEMPLATE_DECL associated to a TEMPLATE_TEMPLATE_PARM
    node.  */
 #define TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL(NODE)	\
-  ((TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM)	\
+  (BOUND_TEMPLATE_TEMPLATE_PARM_P (NODE)		\
    ? TYPE_TI_TEMPLATE (NODE)				\
    : TYPE_NAME (NODE))
 
@@ -5666,6 +5680,7 @@  extern bool non_static_member_function_p        (tree);
 extern const char *cxx_printable_name		(tree, int);
 extern const char *cxx_printable_name_translate	(tree, int);
 extern tree build_exception_variant		(tree, tree);
+extern tree build_template_id_type              (tree, tree);
 extern tree bind_template_template_parm		(tree, tree);
 extern tree array_type_nelts_total		(tree);
 extern tree array_type_nelts_top		(tree);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 55cb64b..c71ca0e 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -225,7 +225,7 @@  pp_cxx_unqualified_id (cxx_pretty_printer *pp, tree t)
       pp_cxx_unqualified_id (pp, TEMPLATE_PARM_DECL (t));
       break;
 
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
       pp_cxx_cv_qualifier_seq (pp, t);
       pp_cxx_unqualified_id (pp, TYPE_IDENTIFIER (t));
       pp_cxx_begin_template_argument_list (pp);
@@ -1295,7 +1295,7 @@  pp_cxx_type_specifier_seq (cxx_pretty_printer *pp, tree t)
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
     case TYPE_DECL:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
       pp_cxx_cv_qualifier_seq (pp, t);
       pp_cxx_simple_type_specifier (pp, t);
       break;
@@ -1687,7 +1687,7 @@  pp_cxx_direct_abstract_declarator (cxx_pretty_printer *pp, tree t)
     case TYPENAME_TYPE:
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
     case UNBOUND_CLASS_TEMPLATE:
       break;
 
@@ -1713,7 +1713,7 @@  pp_cxx_type_id (cxx_pretty_printer *pp, tree t)
     case RECORD_TYPE:
     case ENUMERAL_TYPE:
     case TYPENAME_TYPE:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
     case UNBOUND_CLASS_TEMPLATE:
     case TEMPLATE_TEMPLATE_PARM:
     case TEMPLATE_TYPE_PARM:
@@ -2140,7 +2140,7 @@  pp_cxx_canonical_template_parameter (cxx_pretty_printer *pp, tree parm)
 
   /* Brings type template parameters to the canonical forms.  */
   if (code == TEMPLATE_TYPE_PARM || code == TEMPLATE_TEMPLATE_PARM
-      || code == BOUND_TEMPLATE_TEMPLATE_PARM)
+      || BOUND_TEMPLATE_TEMPLATE_PARM_P (parm))
     parm = TEMPLATE_TYPE_PARM_INDEX (parm);
 
   pp_cxx_begin_template_argument_list (pp);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 5a4e027..4b6e903 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -3190,15 +3190,16 @@  make_typename_type (tree context, tree name, enum tag_types tag_type,
 
   if (TYPE_P (name))
     {
-      if (!(TYPE_LANG_SPECIFIC (name)
+      if (TREE_CODE (name) == TEMPLATE_ID_TYPE)
+	/* We use instances of TEMPLATE_ID_TYPE as is.  */;
+      else if (!(TYPE_LANG_SPECIFIC (name)
 	    && (CLASSTYPE_IS_TEMPLATE (name)
 		|| CLASSTYPE_USE_TEMPLATE (name))))
 	name = TYPE_IDENTIFIER (name);
       else
-	/* Create a TEMPLATE_ID_EXPR for the type.  */
-	name = build_nt (TEMPLATE_ID_EXPR,
-			 CLASSTYPE_TI_TEMPLATE (name),
-			 CLASSTYPE_TI_ARGS (name));
+	/* Create a TEMPLATE_ID_TYPE for the type.  */
+	name = build_template_id_type (CLASSTYPE_TI_TEMPLATE (name),
+				       CLASSTYPE_TI_ARGS (name));
     }
   else if (TREE_CODE (name) == TYPE_DECL)
     name = DECL_NAME (name);
@@ -3215,12 +3216,17 @@  make_typename_type (tree context, tree name, enum tag_types tag_type,
 	  error ("%qD is not a type", name);
 	  return error_mark_node;
 	}
+      fullname = build_template_id_type (TREE_OPERAND (fullname, 0),
+					 TREE_OPERAND (fullname, 1));
     }
   if (TREE_CODE (name) == TEMPLATE_DECL)
     {
       error ("%qD used without template parameters", name);
       return error_mark_node;
     }
+  if (TREE_CODE (name) == TEMPLATE_ID_TYPE)
+    name = TYPE_IDENTIFIER (name);
+
   gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
   gcc_assert (TYPE_P (context));
 
@@ -3246,7 +3252,7 @@  make_typename_type (tree context, tree name, enum tag_types tag_type,
   if ((!t || TREE_CODE (t) == TREE_LIST) && dependent_type_p (context))
     return build_typename_type (context, name, fullname, tag_type);
 
-  want_template = TREE_CODE (fullname) == TEMPLATE_ID_EXPR;
+  want_template = TREE_CODE (fullname) == TEMPLATE_ID_TYPE;
   
   if (!t)
     {
@@ -3294,7 +3300,7 @@  make_typename_type (tree context, tree name, enum tag_types tag_type,
   add_typedef_to_current_template_for_access_check (t, context, input_location);
 
   if (want_template)
-    return lookup_template_class (t, TREE_OPERAND (fullname, 1),
+    return lookup_template_class (t, TYPE_TI_ARGS (fullname),
 				  NULL_TREE, context,
 				  /*entering_scope=*/0,
 				  tf_warning_or_error | tf_user);
@@ -11377,7 +11383,7 @@  check_elaborated_type_specifier (enum tag_types tag_code,
     }
   /* Accept bound template template parameters.  */
   else if (allow_template_p
-	   && TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+	   && BOUND_TEMPLATE_TEMPLATE_PARM_P (type))
     ;
   /*   [dcl.type.elab]
 
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 05f4b42..b677104 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1130,8 +1130,8 @@  is_late_template_attribute (tree attr, tree decl)
       /* We can't apply any attributes to a completely unknown type until
 	 instantiation time.  */
       enum tree_code code = TREE_CODE (type);
-      if (code == TEMPLATE_TYPE_PARM
-	  || code == BOUND_TEMPLATE_TEMPLATE_PARM
+      if (BOUND_TEMPLATE_TEMPLATE_PARM_P (type)
+	  ||code == TEMPLATE_TYPE_PARM
 	  || code == TYPENAME_TYPE)
 	return true;
       /* Also defer most attributes on dependent types.  This is not
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 21d6781..20c158f 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -451,7 +451,7 @@  dump_type (tree t, int flags)
 	pp_cxx_canonical_template_parameter (cxx_pp, t);
       break;
 
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
       {
 	tree args = TYPE_TI_ARGS (t);
 	pp_cxx_cv_qualifier_seq (cxx_pp, t);
@@ -570,7 +570,7 @@  dump_typename (tree t, int flags)
   else
     dump_type (ctx, flags & ~TFF_CLASS_KEY_OR_ENUM);
   pp_cxx_colon_colon (cxx_pp);
-  dump_decl (TYPENAME_TYPE_FULLNAME (t), flags);
+  dump_type (TYPENAME_TYPE_FULLNAME (t), flags);
 }
 
 /* Return the name of the supplied aggregate, or enumeral type.  */
@@ -766,7 +766,7 @@  dump_type_prefix (tree t, int flags)
     case RECORD_TYPE:
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
     case TREE_LIST:
     case TYPE_DECL:
     case TREE_VEC:
@@ -869,7 +869,7 @@  dump_type_suffix (tree t, int flags)
     case RECORD_TYPE:
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
     case TREE_LIST:
     case TYPE_DECL:
     case TREE_VEC:
@@ -2407,7 +2407,7 @@  dump_expr (tree t, int flags)
 
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
       dump_type (t, flags);
       break;
 
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index c11e3b3..4320e33 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -664,7 +664,7 @@  cxx_make_type (enum tree_code code)
 
   /* Create lang_type structure.  */
   if (RECORD_OR_UNION_CODE_P (code)
-      || code == BOUND_TEMPLATE_TEMPLATE_PARM)
+      || code == TEMPLATE_ID_TYPE)
     {
       struct lang_type *pi
           = ggc_alloc_cleared_lang_type (sizeof (struct lang_type));
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 548998a..7235660 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -83,7 +83,7 @@  along with GCC; see the file COPYING3.  If not see
    without parameters inside the template.  */
 #define CLASSTYPE_TEMPLATE_ID_P(NODE)					\
   (TYPE_LANG_SPECIFIC (NODE) != NULL					\
-   && (TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM			\
+   && (BOUND_TEMPLATE_TEMPLATE_PARM_P (NODE)				\
        || (CLASSTYPE_TEMPLATE_INFO (NODE) != NULL			\
 	   && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))))))
 
@@ -935,10 +935,10 @@  write_nested_name (const tree decl)
   else if (TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE)
     {
       tree name = TYPENAME_TYPE_FULLNAME (TREE_TYPE (decl));
-      if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+      if (TREE_CODE (name) == TEMPLATE_ID_TYPE)
 	{
 	  write_template_prefix (decl);
-	  write_template_args (TREE_OPERAND (name, 1));
+	  write_template_args (TYPE_TI_ARGS (name));
 	}
       else
 	{
@@ -1023,10 +1023,10 @@  write_prefix (const tree node)
   else if (TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE)
     {
       tree name = TYPENAME_TYPE_FULLNAME (TREE_TYPE (decl));
-      if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+      if (TREE_CODE (name) == TEMPLATE_ID_TYPE)
 	{
 	  write_template_prefix (decl);
-	  write_template_args (TREE_OPERAND (name, 1));
+	  write_template_args (TYPE_TI_ARGS (name));
 	}
       else
 	{
@@ -1943,10 +1943,10 @@  write_type (tree type)
 	      write_template_template_param (type);
 	      break;
 
-	    case BOUND_TEMPLATE_TEMPLATE_PARM:
+	    case TEMPLATE_ID_TYPE:
+	      gcc_assert (BOUND_TEMPLATE_TEMPLATE_PARM_P (type));
 	      write_template_template_param (type);
-	      write_template_args
-		(TI_ARGS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (type)));
+	      write_template_args (TYPE_TI_ARGS (type));
 	      break;
 
 	    case VECTOR_TYPE:
@@ -2521,7 +2521,7 @@  write_expression (tree expr)
   /* Handle template parameters.  */
   if (code == TEMPLATE_TYPE_PARM
       || code == TEMPLATE_TEMPLATE_PARM
-      || code == BOUND_TEMPLATE_TEMPLATE_PARM
+      || BOUND_TEMPLATE_TEMPLATE_PARM_P (expr)
       || code == TEMPLATE_PARM_INDEX)
     write_template_param (expr);
   /* Handle literals.  */
@@ -2995,9 +2995,10 @@  write_template_param (const tree parm)
 
   switch (TREE_CODE (parm))
     {
+    case TEMPLATE_ID_TYPE:
+      gcc_assert (BOUND_TEMPLATE_TEMPLATE_PARM_P (parm));
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
       parm_index = TEMPLATE_TYPE_IDX (parm);
       break;
 
@@ -3027,10 +3028,9 @@  write_template_template_param (const tree parm)
   /* PARM, a TEMPLATE_TEMPLATE_PARM, is an instantiation of the
      template template parameter.  The substitution candidate here is
      only the template.  */
-  if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
+  if (BOUND_TEMPLATE_TEMPLATE_PARM_P (parm))
     {
-      templ
-	= TI_TEMPLATE (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parm));
+      templ = TI_TEMPLATE (TYPE_TEMPLATE_INFO (parm));
       if (find_substitution (templ))
 	return;
     }
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index ceecdef..56ee569 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -5330,7 +5330,7 @@  arg_assoc_type (struct arg_lookup *k, tree type)
       /* Associate the return type.  */
       return arg_assoc_type (k, TREE_TYPE (type));
     case TEMPLATE_TYPE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
       return false;
     case TYPENAME_TYPE:
       return false;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 5952a0f..97de50f 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5093,7 +5093,7 @@  cp_parser_nested_name_specifier_opt (cp_parser *parser,
 		   || CLASSTYPE_IS_TEMPLATE (new_scope)))
 	  && !(TREE_CODE (new_scope) == TYPENAME_TYPE
 	       && (TREE_CODE (TYPENAME_TYPE_FULLNAME (new_scope))
-		   == TEMPLATE_ID_EXPR)))
+		   == TEMPLATE_ID_TYPE)))
 	permerror (input_location, TYPE_P (new_scope)
 		   ? G_("%qT is not a template")
 		   : G_("%qD is not a template"),
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index bb5aa0c..7d00770 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -328,10 +328,8 @@  get_template_info (const_tree t)
   if (!tinfo && DECL_IMPLICIT_TYPEDEF_P (t))
     t = TREE_TYPE (t);
 
-  if (TAGGED_TYPE_P (t))
+  if (TYPE_P (t))
     tinfo = TYPE_TEMPLATE_INFO (t);
-  else if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
-    tinfo = TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t);
 
   return tinfo;
 }
@@ -805,7 +803,7 @@  maybe_process_partial_specialization (tree type)
   if (type == error_mark_node)
     return error_mark_node;
 
-  if (TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+  if (BOUND_TEMPLATE_TEMPLATE_PARM_P (type))
     {
       error ("name of class shadows template template parameter %qD",
 	     TYPE_NAME (type));
@@ -3040,10 +3038,15 @@  find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
     case TEMPLATE_PARM_INDEX:
       return NULL_TREE;
 
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
       /* Check the template itself.  */
-      cp_walk_tree (&TREE_TYPE (TYPE_TI_TEMPLATE (t)), 
-		    &find_parameter_packs_r, ppd, ppd->visited);
+      if (TYPE_TI_TEMPLATE (t) == NULL_TREE)
+	/* This can happen when the name of the template can not yet
+	   be resolved to a TEMPLATE_DECL.  So we don't have any
+	   template tree to walk, yet.  */;
+      else
+	cp_walk_tree (&TREE_TYPE (TYPE_TI_TEMPLATE (t)), 
+		      &find_parameter_packs_r, ppd, ppd->visited);
       /* Check the template arguments.  */
       cp_walk_tree (&TYPE_TI_ARGS (t), &find_parameter_packs_r, ppd, 
 		    ppd->visited);
@@ -7303,10 +7306,11 @@  lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
       int is_dependent_type;
       int use_partial_inst_tmpl = false;
 
-      if (template_type == error_mark_node)
-	/* An error occured while building the template TEMPL, and a
-	   diagnostic has most certainly been emitted for that
-	   already.  Let's propagate that error.  */
+      if (template_type == error_mark_node
+	  || arglist == error_mark_node)
+	/* An error occured while building the template TEMPL or its
+	   argument list, and a diagnostic has most certainly been
+	   emitted for that already.  Let's propagate that error.  */
 	return error_mark_node;
 
       gen_tmpl = most_general_template (templ);
@@ -7812,11 +7816,15 @@  for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
 	return error_mark_node;
       break;
 
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
       /* Record template parameters such as `T' inside `TT<T>'.  */
       if (for_each_template_parm (TYPE_TI_ARGS (t), fn, data, pfd->visited,
 				  pfd->include_nondeduced_p))
 	return error_mark_node;
+
+      if (!BOUND_TEMPLATE_TEMPLATE_PARM_P (t))
+	break;
+
       /* Fall through.  */
 
     case TEMPLATE_TEMPLATE_PARM:
@@ -7888,7 +7896,7 @@  for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
 }
 
 /* For each TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM,
-   BOUND_TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX in T,
+   TEMPLATE_ID_TYPE or TEMPLATE_PARM_INDEX in T,
    call FN with the parameter and the DATA.
    If FN returns nonzero, the iteration is terminated, and
    for_each_template_parm returns 1.  Otherwise, the iteration
@@ -11221,7 +11229,7 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
     case TEMPLATE_PARM_INDEX:
       {
 	int idx;
@@ -11231,6 +11239,34 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
 	r = NULL_TREE;
 
+	if (code == TEMPLATE_ID_TYPE
+	    && !BOUND_TEMPLATE_TEMPLATE_PARM_P (t))
+	  {
+	    /* We are processing a type constructed from a
+	       template-id.  Bound template template parameters are a
+	       particular case of TEMPLATE_ID_TYPE, and they are
+	       handled in an 'else' clause a bit later in this
+	       function.  */
+	    tree argvec = tsubst (TYPE_TI_ARGS (t),
+				  args, complain, in_decl);
+
+	    if (TYPE_TI_TEMPLATE (t) != NULL_TREE)
+	      /* The template name of the TEMPLATE_ID_TYPE resolved to
+		 a TEMPLATE_DECL, so we can try to build a class type
+		 for it.  */
+	      r = lookup_template_class (TYPE_TI_TEMPLATE (t),
+					 argvec, in_decl, NULL_TREE,
+					 /*entering_scope=*/0, complain);
+	    else
+	      /* The template name of the TEMPLATE_ID_TYPE hasn't yet
+		 resolved to a TEMPLATE_DECL, so we can't build a
+		 class type from it yet.  */
+	      r = build_template_id_type (TYPE_IDENTIFIER (t),
+					  argvec);
+	    return cp_build_qualified_type_real
+	      (r, cp_type_quals (t), complain);
+	  }
+
 	gcc_assert (TREE_VEC_LENGTH (args) > 0);
 	template_parm_level_and_index (t, &level, &idx); 
 
@@ -11272,12 +11308,13 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 		return cp_build_qualified_type_real
 		  (arg, quals, complain | tf_ignore_bad_quals);
 	      }
-	    else if (code == BOUND_TEMPLATE_TEMPLATE_PARM)
+	    else if (code == TEMPLATE_ID_TYPE)
 	      {
 		/* We are processing a type constructed from a
 		   template template parameter.  */
 		tree argvec = tsubst (TYPE_TI_ARGS (t),
 				      args, complain, in_decl);
+
 		if (argvec == error_mark_node)
 		  return error_mark_node;
 
@@ -11302,10 +11339,10 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 			  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
+		     When #1 is parsed, the template of the
+		     TEMPLATE_ID_TYPE representing the `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
@@ -11315,9 +11352,9 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 		     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),
+					     build_template_id_type
+					     (TYPE_IDENTIFIER (arg),
+					      argvec),
 					     typename_type,
 					     complain);
 
@@ -11353,9 +11390,12 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	   template parameter, but with a lower level.  */
 	switch (code)
 	  {
+	  case TEMPLATE_ID_TYPE:
+	    /* This must be a bound template template parm, otherwise,
+	       it would have been handled earlier.  */
+	    gcc_assert (BOUND_TEMPLATE_TEMPLATE_PARM_P (t));
 	  case TEMPLATE_TYPE_PARM:
 	  case TEMPLATE_TEMPLATE_PARM:
-	  case BOUND_TEMPLATE_TEMPLATE_PARM:
 	    if (cp_type_quals (t))
 	      {
 		r = tsubst (TYPE_MAIN_VARIANT (t), args, complain, in_decl);
@@ -11389,14 +11429,14 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 		else
 		  TYPE_CANONICAL (r) = canonical_type_parameter (r);
 
-		if (code == BOUND_TEMPLATE_TEMPLATE_PARM)
+		if (BOUND_TEMPLATE_TEMPLATE_PARM_P (t))
 		  {
 		    tree argvec = tsubst (TYPE_TI_ARGS (t), args,
 					  complain, in_decl);
 		    if (argvec == error_mark_node)
 		      return error_mark_node;
 
-		    TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (r)
+		    TEMPLATE_ID_TYPE_TEMPLATE_INFO (r)
 		      = build_template_info (TYPE_TI_TEMPLATE (t), argvec);
 		  }
 	      }
@@ -12424,7 +12464,7 @@  tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     case INTEGER_TYPE:
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
     case TEMPLATE_PARM_INDEX:
     case POINTER_TYPE:
     case REFERENCE_TYPE:
@@ -15851,7 +15891,7 @@  template_parm_level_and_index (tree parm, int* level, int* index)
 {
   if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
       || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
-      || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
+      || BOUND_TEMPLATE_TEMPLATE_PARM_P (parm))
     {
       *index = TEMPLATE_TYPE_IDX (parm);
       *level = TEMPLATE_TYPE_LEVEL (parm);
@@ -16216,9 +16256,10 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 	 within the nested-name-specifier.  */
       return unify_success (explain_p);
 
+    case TEMPLATE_ID_TYPE:
+      gcc_assert (BOUND_TEMPLATE_TEMPLATE_PARM_P (parm));
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
       tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
       if (tparm == error_mark_node)
 	return unify_invalid (explain_p);
@@ -16245,11 +16286,11 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 	      && TREE_CODE (tparm) != TEMPLATE_DECL))
 	gcc_unreachable ();
 
-      if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
+      if (BOUND_TEMPLATE_TEMPLATE_PARM_P (parm))
 	{
 	  /* ARG must be constructed from a template class or a template
 	     template parameter.  */
-	  if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM
+	  if (!BOUND_TEMPLATE_TEMPLATE_PARM_P (arg)
 	      && !CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg))
 	    return unify_template_deduction_failure (explain_p, parm, arg);
 
@@ -16342,7 +16383,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 	}
 
       if (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
-	  || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
+	  || BOUND_TEMPLATE_TEMPLATE_PARM_P (parm))
 	{
 	  /* Deduce template name TT from TT, TT<>, TT<T> and TT<i>.  */
 
@@ -19183,7 +19224,7 @@  dependent_type_p_r (tree type)
 
   /* -- a template-id in which either the template name is a template
      parameter ...  */
-  if (TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+  if (BOUND_TEMPLATE_TEMPLATE_PARM_P (type))
     return true;
   /* ... or any of the template arguments is a dependent type or
 	an expression that is type-dependent or value-dependent.  */
@@ -20030,15 +20071,14 @@  resolve_typename_type (tree type, bool only_current_p)
       if (result == error_mark_node)
 	result = NULL_TREE;
     }
-  else if (TREE_CODE (TYPENAME_TYPE_FULLNAME (type)) == TEMPLATE_ID_EXPR
-	   && DECL_CLASS_TEMPLATE_P (decl))
+  else if (TREE_CODE (TYPENAME_TYPE_FULLNAME (type)) == TEMPLATE_ID_TYPE)
     {
+      tree fullname = TYPENAME_TYPE_FULLNAME (type);
       tree tmpl;
       tree args;
       /* Obtain the template and the arguments.  */
-      tmpl = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 0);
-      args = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 1);
-      /* Instantiate the template.  */
+      tmpl = TYPE_IDENTIFIER (fullname);
+      args = TYPE_TI_ARGS (fullname);
       result = lookup_template_class (tmpl, args, NULL_TREE, NULL_TREE,
 				      /*entering_scope=*/0,
 				      tf_error | tf_user);
diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c
index a66e695..4d0331a 100644
--- a/gcc/cp/ptree.c
+++ b/gcc/cp/ptree.c
@@ -76,9 +76,13 @@  cxx_print_type (FILE *file, tree node, int indent)
 {
   switch (TREE_CODE (node))
     {
+    case TEMPLATE_ID_TYPE:
+      if (BOUND_TEMPLATE_TEMPLATE_PARM_P (node))
+	/* Fall through.  */;
+      else
+	break;
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
       indent_to (file, indent + 3);
       fprintf (file, "index %d level %d orig_level %d",
 	       TEMPLATE_TYPE_IDX (node), TEMPLATE_TYPE_LEVEL (node),
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 3894c68..431c935 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -385,7 +385,7 @@  lookup_field_1 (tree type, tree name, bool want_type)
   tree field;
 
   if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
-      || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM
+      || BOUND_TEMPLATE_TEMPLATE_PARM_P (type)
       || TREE_CODE (type) == TYPENAME_TYPE)
     /* The TYPE_FIELDS of a TEMPLATE_TYPE_PARM and
        BOUND_TEMPLATE_TEMPLATE_PARM are not fields at all;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 8d179d8..250e616 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1624,32 +1624,54 @@  build_exception_variant (tree type, tree raises)
   return v;
 }
 
+/*  Given a TEMPLATE_DECL or an IDENTIFIER_NODE, create a
+    TEMPLATE_ID_TYPE with args as its arguments.
+
+    The TEMPLATE_INFO of the resulting TEMPLATE_ID_TYPE can be
+    retrieved using the TEMPLATE_ID_TYPE_TEMPLATE_INFO accessor.  The
+    template arguments ARGS can be retrieved from the TEMLATE_ID_TYPE by
+    using the TYPE_TI_ARGS accessor, and the TEMPLATE_DECL can be
+    retrieved using TYPE_TI_TEMPLATE.
+
+    Note that if TMPL is an IDENTIFIER_NODE (rather than a
+    TEMPLATE_DECL), the TYPE_TI_TEMPLATE accessor will yield
+    NULL_TREE.  That IDENTIFIER_NODE can be retrieved by using the
+    TYPE_IDENTIFIER accessor instead.  */
+
+tree
+build_template_id_type (tree tmpl, tree args)
+{
+  tree result, decl, name;
+
+  gcc_assert (tmpl && (TREE_CODE (tmpl) == TEMPLATE_DECL
+		       || TREE_CODE (tmpl) == IDENTIFIER_NODE));
+
+  name = (TREE_CODE (tmpl) == TEMPLATE_DECL )? DECL_NAME (tmpl) : tmpl;
+  if (TREE_CODE (tmpl) == IDENTIFIER_NODE)
+    tmpl = NULL_TREE;
+
+  result = cxx_make_type (TEMPLATE_ID_TYPE);
+  decl = build_decl (input_location, TYPE_DECL,
+		     name, NULL_TREE);
+  TREE_TYPE (decl) = result;
+  TYPE_NAME (result) = decl;
+  TYPE_STUB_DECL (result) = decl;
+  SET_TYPE_TEMPLATE_INFO (result, build_template_info (tmpl, args));
+  TYPE_SIZE (result) = 0;
+  SET_TYPE_STRUCTURAL_EQUALITY (result);
+  return result;
+}
+
 /* Given a TEMPLATE_TEMPLATE_PARM node T, create a new
-   BOUND_TEMPLATE_TEMPLATE_PARM bound with NEWARGS as its template
-   arguments.  */
+   TEMPLATE_ID_TYPE bound with NEWARGS as its template arguments.  */
 
 tree
 bind_template_template_parm (tree t, tree newargs)
 {
-  tree decl = TYPE_NAME (t);
-  tree t2;
-
-  t2 = cxx_make_type (BOUND_TEMPLATE_TEMPLATE_PARM);
-  decl = build_decl (input_location,
-		     TYPE_DECL, DECL_NAME (decl), NULL_TREE);
-
-  /* These nodes have to be created to reflect new TYPE_DECL and template
-     arguments.  */
+  tree t2 = build_template_id_type (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t),
+				    newargs);
   TEMPLATE_TYPE_PARM_INDEX (t2) = copy_node (TEMPLATE_TYPE_PARM_INDEX (t));
-  TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (t2)) = decl;
-  TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2)
-    = build_template_info (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t), newargs);
-
-  TREE_TYPE (decl) = t2;
-  TYPE_NAME (t2) = decl;
-  TYPE_STUB_DECL (t2) = decl;
-  TYPE_SIZE (t2) = 0;
-  SET_TYPE_STRUCTURAL_EQUALITY (t2);
+  TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (t2)) = TYPE_NAME (t2);
 
   return t2;
 }
@@ -2937,7 +2959,7 @@  cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
     {
     case DEFAULT_ARG:
     case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_ID_TYPE:
     case UNBOUND_CLASS_TEMPLATE:
     case TEMPLATE_PARM_INDEX:
     case TEMPLATE_TYPE_PARM:
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 4973d7d..9200cfe 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1129,7 +1129,7 @@  comp_template_parms_position (tree t1, tree t2)
   tree index1, index2;
   gcc_assert (t1 && t2
 	      && TREE_CODE (t1) == TREE_CODE (t2)
-	      && (TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM
+	      && (BOUND_TEMPLATE_TEMPLATE_PARM_P (t1)
 		  || TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM
 		  || TREE_CODE (t1) == TEMPLATE_TYPE_PARM));
 
@@ -1230,8 +1230,20 @@  structural_comptypes (tree t1, tree t2, int strict)
 	 track of equivalence in this case, so we fall back on it.  */
       return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
 
+    case TEMPLATE_ID_TYPE:
+      if (!BOUND_TEMPLATE_TEMPLATE_PARM_P (t1))
+	{
+	  if (!cp_tree_equal (TYPE_TI_TEMPLATE (t1),
+			      TYPE_TI_TEMPLATE (t2)))
+	    return false;
+	  return comp_template_args (TYPE_TI_ARGS (t1),
+				     TYPE_TI_ARGS (t2));
+	}
+      else
+	{
+	  /* Fall through.  */;
+	}
     case TEMPLATE_TEMPLATE_PARM:
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
       if (!comp_template_parms_position (t1, t2))
 	return false;
       if (!comp_template_parms
@@ -1248,7 +1260,7 @@  structural_comptypes (tree t1, tree t2, int strict)
     case UNION_TYPE:
       if (TYPE_TEMPLATE_INFO (t1) && TYPE_TEMPLATE_INFO (t2)
 	  && (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2)
-	      || TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM)
+	      || BOUND_TEMPLATE_TEMPLATE_PARM_P (t1))
 	  && comp_template_args (TYPE_TI_ARGS (t1), TYPE_TI_ARGS (t2)))
 	break;
 
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 4648e75..61f0c4d 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -453,10 +453,15 @@  cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
 			 "invalid use of template type parameter %qT", type);
       break;
 
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
-      emit_diagnostic (diag_kind, input_location, 0,
-		       "invalid use of template template parameter %qT",
-		       TYPE_NAME (type));
+    case TEMPLATE_ID_TYPE:
+      if (BOUND_TEMPLATE_TEMPLATE_PARM_P (type))
+	emit_diagnostic (diag_kind, input_location, 0,
+			 "invalid use of template template parameter %qT",
+			 TYPE_NAME (type));
+      else
+	emit_diagnostic (diag_kind, input_location, 0,
+			 "invalid use of template-id %qT",
+			 TYPE_NAME (type));
       break;
 
     case TYPENAME_TYPE: