[1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR

Message ID 20220927195030.2024439-1-ppalka@redhat.com
State New
Headers
Series [1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR |

Commit Message

Patrick Palka Sept. 27, 2022, 7:50 p.m. UTC
  We already have generic support for predicate-like traits that yield a
boolean via TRAIT_EXPR, but we lack the same support for transform-like
traits that yield a type.  Such support would be useful for implementing
efficient built-ins for std::decay and std::remove_cvref and other
conceptually simple type traits that are otherwise relatively expensive
to implement.

This patch implements a generic TRAIT_TYPE type and replaces the
existing hardcoded UNDERLYING_TYPE type to use TRAIT_TYPE instead.

gcc/cp/ChangeLog:

	* cp-objcp-common.cc (cp_common_init_ts): Replace
	UNDERLYING_TYPE with TRAIT_TYPE.
	* cp-tree.def (TRAIT_TYPE): Define.
	(UNDERLYING_TYPE): Remove.
	* cp-tree.h (TRAIT_TYPE_KIND_RAW): Define.
	(TRAIT_TYPE_KIND): Define.
	(TRAIT_TYPE_TYPE1): Define.
	(TRAIT_TYPE_TYPE2): Define.
	(WILDCARD_TYPE_P): Return true for TRAIT_TYPE.
	(finish_trait_type): Declare.
	* cxx-pretty-print.cc (cxx_pretty_printer::primary_expression):
	Adjust after renaming pp_cxx_trait_expression.
	(cxx_pretty_printer::type_id): Replace UNDERLYING_TYPE with
	TRAIT_TYPE.
	(pp_cxx_trait_expression): Rename to ...
	(pp_cxx_trait): ... this.  Handle TRAIT_TYPE as well.  Correct
	pretty printing of the trailing arguments.
	* cxx-pretty-print.h (pp_cxx_trait_expression): Rename to ...
	(pp_cxx_trait_type): ... this.
	* error.cc (dump_type) <case UNDERLYING_TYPE>: Remove.
	<case TRAIT_TYPE>: New.
	(dump_type_prefix): Replace UNDERLYING_WITH with TRAIT_TYPE.
	(dump_type_suffix): Likewise.
	* mangle.cc (write_type) <case UNDERLYING_TYPE>: Remove.
	<case TRAIT_TYPE>: New.
	* module.cc (trees_out::type_node) <case UNDERLYING_TYPE>:
	Remove.
	<case TRAIT_TYPE>: New.
	(trees_in::tree_node): Likewise.
	* parser.cc (cp_parser_primary_expression): Adjust after
	renaming cp_parser_trait_expr.
	(cp_parser_trait_expr): Rename to ...
	(cp_parser_trait): ... this.  Call finish_trait_type for traits
	that yield a type.
	(cp_parser_simple_type_specifier): Adjust after renaming
	cp_parser_trait_expr.
	* pt.cc (for_each_template_parm_r) <case UNDERLYING_TYPE>:
	Remove.
	<case TRAIT_TYPE>: New.
	(tsubst): Likewise.
	(unify): Replace UNDERLYING_TYPE with TRAIT_TYPE.
	(dependent_type_p_r): Likewise.
	* semantics.cc (finish_underlying_type): Don't return
	UNDERLYING_TYPE anymore when processing_template_decl.
	(finish_trait_type): Define.
	* tree.cc (strip_typedefs) <case UNDERLYING_TYPE>: Remove.
	<case TRAIT_TYPE>: New.
	(cp_walk_subtrees): Likewise.
	* typeck.cc (structural_comptypes): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/underlying_type7.C: Adjust expected error message.
---
 gcc/cp/cp-objcp-common.cc                   |  2 +-
 gcc/cp/cp-tree.def                          |  9 ++--
 gcc/cp/cp-tree.h                            | 18 ++++++++
 gcc/cp/cxx-pretty-print.cc                  | 49 ++++++++++++++-------
 gcc/cp/cxx-pretty-print.h                   |  2 +-
 gcc/cp/error.cc                             | 14 +++---
 gcc/cp/mangle.cc                            |  5 ++-
 gcc/cp/module.cc                            | 24 +++++++++-
 gcc/cp/parser.cc                            | 24 +++++-----
 gcc/cp/pt.cc                                | 26 +++++++----
 gcc/cp/semantics.cc                         | 41 ++++++++++++-----
 gcc/cp/tree.cc                              | 22 ++++++---
 gcc/cp/typeck.cc                            |  7 ++-
 gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C  |  4 +-
 gcc/testsuite/g++.dg/ext/underlying_type7.C |  2 +-
 15 files changed, 171 insertions(+), 78 deletions(-)
  

Comments

Jason Merrill Sept. 27, 2022, 9:07 p.m. UTC | #1
On 9/27/22 15:50, Patrick Palka wrote:
> We already have generic support for predicate-like traits that yield a
> boolean via TRAIT_EXPR, but we lack the same support for transform-like
> traits that yield a type.  Such support would be useful for implementing
> efficient built-ins for std::decay and std::remove_cvref and other
> conceptually simple type traits that are otherwise relatively expensive
> to implement.
> 
> This patch implements a generic TRAIT_TYPE type and replaces the
> existing hardcoded UNDERLYING_TYPE type to use TRAIT_TYPE instead.

Sounds good, perhaps we also want to convert BASES to e.g. 
TRAIT_TYPE_PACK at some point...

> gcc/cp/ChangeLog:
> 
> 	* cp-objcp-common.cc (cp_common_init_ts): Replace
> 	UNDERLYING_TYPE with TRAIT_TYPE.
> 	* cp-tree.def (TRAIT_TYPE): Define.
> 	(UNDERLYING_TYPE): Remove.
> 	* cp-tree.h (TRAIT_TYPE_KIND_RAW): Define.
> 	(TRAIT_TYPE_KIND): Define.
> 	(TRAIT_TYPE_TYPE1): Define.
> 	(TRAIT_TYPE_TYPE2): Define.
> 	(WILDCARD_TYPE_P): Return true for TRAIT_TYPE.
> 	(finish_trait_type): Declare.
> 	* cxx-pretty-print.cc (cxx_pretty_printer::primary_expression):
> 	Adjust after renaming pp_cxx_trait_expression.
> 	(cxx_pretty_printer::type_id): Replace UNDERLYING_TYPE with
> 	TRAIT_TYPE.
> 	(pp_cxx_trait_expression): Rename to ...
> 	(pp_cxx_trait): ... this.  Handle TRAIT_TYPE as well.  Correct
> 	pretty printing of the trailing arguments.
> 	* cxx-pretty-print.h (pp_cxx_trait_expression): Rename to ...
> 	(pp_cxx_trait_type): ... this.
> 	* error.cc (dump_type) <case UNDERLYING_TYPE>: Remove.
> 	<case TRAIT_TYPE>: New.
> 	(dump_type_prefix): Replace UNDERLYING_WITH with TRAIT_TYPE.
> 	(dump_type_suffix): Likewise.
> 	* mangle.cc (write_type) <case UNDERLYING_TYPE>: Remove.
> 	<case TRAIT_TYPE>: New.
> 	* module.cc (trees_out::type_node) <case UNDERLYING_TYPE>:
> 	Remove.
> 	<case TRAIT_TYPE>: New.
> 	(trees_in::tree_node): Likewise.
> 	* parser.cc (cp_parser_primary_expression): Adjust after
> 	renaming cp_parser_trait_expr.
> 	(cp_parser_trait_expr): Rename to ...
> 	(cp_parser_trait): ... this.  Call finish_trait_type for traits
> 	that yield a type.
> 	(cp_parser_simple_type_specifier): Adjust after renaming
> 	cp_parser_trait_expr.
> 	* pt.cc (for_each_template_parm_r) <case UNDERLYING_TYPE>:
> 	Remove.
> 	<case TRAIT_TYPE>: New.
> 	(tsubst): Likewise.
> 	(unify): Replace UNDERLYING_TYPE with TRAIT_TYPE.
> 	(dependent_type_p_r): Likewise.
> 	* semantics.cc (finish_underlying_type): Don't return
> 	UNDERLYING_TYPE anymore when processing_template_decl.
> 	(finish_trait_type): Define.
> 	* tree.cc (strip_typedefs) <case UNDERLYING_TYPE>: Remove.
> 	<case TRAIT_TYPE>: New.
> 	(cp_walk_subtrees): Likewise.
> 	* typeck.cc (structural_comptypes): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/ext/underlying_type7.C: Adjust expected error message.
> ---
>   gcc/cp/cp-objcp-common.cc                   |  2 +-
>   gcc/cp/cp-tree.def                          |  9 ++--
>   gcc/cp/cp-tree.h                            | 18 ++++++++
>   gcc/cp/cxx-pretty-print.cc                  | 49 ++++++++++++++-------
>   gcc/cp/cxx-pretty-print.h                   |  2 +-
>   gcc/cp/error.cc                             | 14 +++---
>   gcc/cp/mangle.cc                            |  5 ++-
>   gcc/cp/module.cc                            | 24 +++++++++-
>   gcc/cp/parser.cc                            | 24 +++++-----
>   gcc/cp/pt.cc                                | 26 +++++++----
>   gcc/cp/semantics.cc                         | 41 ++++++++++++-----
>   gcc/cp/tree.cc                              | 22 ++++++---
>   gcc/cp/typeck.cc                            |  7 ++-
>   gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C  |  4 +-
>   gcc/testsuite/g++.dg/ext/underlying_type7.C |  2 +-
>   15 files changed, 171 insertions(+), 78 deletions(-)
> 
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 64975699351..380f288a7f1 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -518,7 +518,7 @@ cp_common_init_ts (void)
>     MARK_TS_TYPE_NON_COMMON (DECLTYPE_TYPE);
>     MARK_TS_TYPE_NON_COMMON (TYPENAME_TYPE);
>     MARK_TS_TYPE_NON_COMMON (TYPEOF_TYPE);
> -  MARK_TS_TYPE_NON_COMMON (UNDERLYING_TYPE);
> +  MARK_TS_TYPE_NON_COMMON (TRAIT_TYPE);
>     MARK_TS_TYPE_NON_COMMON (BOUND_TEMPLATE_TEMPLATE_PARM);
>     MARK_TS_TYPE_NON_COMMON (TEMPLATE_TEMPLATE_PARM);
>     MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM);
> diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
> index f9cbd339f19..f83b4c54d43 100644
> --- a/gcc/cp/cp-tree.def
> +++ b/gcc/cp/cp-tree.def
> @@ -444,9 +444,12 @@ DEFTREECODE (BIT_CAST_EXPR, "bit_cast_expr", tcc_expression, 1)
>   
>   /** C++ extensions. */
>   
> -/* Represents a trait expression during template expansion.  */
> +/* Represents a templated trait that yields an expression.  */
>   DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0)
>   
> +/* Represents a templated trait that yields a type.  */
> +DEFTREECODE (TRAIT_TYPE, "trait_type", tcc_type, 0)
> +
>   /* A lambda expression.  This is a C++0x extension.
>      LAMBDA_EXPR_DEFAULT_CAPTURE_MODE is an enum for the default, which may be
>      none.
> @@ -466,10 +469,6 @@ DEFTREECODE (LAMBDA_EXPR, "lambda_expr", tcc_exceptional, 0)
>      DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction.  */
>   DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
>   
> -/* A type designated by `__underlying_type (type)'.
> -   UNDERLYING_TYPE_TYPE is the type in question.  */
> -DEFTREECODE (UNDERLYING_TYPE, "underlying_type", tcc_type, 0)
> -
>   /* A type designated by one of the bases type traits.
>      BASES_TYPE is the type in question.  */
>   DEFTREECODE (BASES, "bases", tcc_type, 0)
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 99b486b8002..c9adf1b3822 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1436,6 +1436,22 @@ struct GTY (()) tree_trait_expr {
>     enum cp_trait_kind kind;
>   };
>   
> +/* An INTEGER_CST containing the kind of the trait type NODE.  */
> +#define TRAIT_TYPE_KIND_RAW(NODE) \
> +  TYPE_VALUES_RAW (TRAIT_TYPE_CHECK (NODE))
> +
> +/* The kind of the trait type NODE.  */
> +#define TRAIT_TYPE_KIND(NODE) \
> +  ((enum cp_trait_kind) TREE_INT_CST_LOW (TRAIT_TYPE_KIND_RAW (NODE)))
> +
> +/* The first argument of the trait type NODE.  */
> +#define TRAIT_TYPE_TYPE1(NODE) \
> +  TYPE_MIN_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
> +
> +/* The rest of the arguments of the trait type NODE.  */
> +#define TRAIT_TYPE_TYPE2(NODE) \
> +  TYPE_MAX_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))

Can we also store the location of the trait use?

> +
>   /* Identifiers used for lambda types are almost anonymous.  Use this
>      spare flag to distinguish them (they also have the anonymous flag).  */
>   #define IDENTIFIER_LAMBDA_P(NODE) \
> @@ -2225,6 +2241,7 @@ enum languages { lang_c, lang_cplusplus };
>      || TREE_CODE (T) == TYPEOF_TYPE			\
>      || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM	\
>      || TREE_CODE (T) == DECLTYPE_TYPE			\
> +   || TREE_CODE (T) == TRAIT_TYPE			\
>      || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE)
>   
>   /* Nonzero if T is a class (or struct or union) type.  Also nonzero
> @@ -7730,6 +7747,7 @@ extern tree finish_decltype_type                (tree, bool, tsubst_flags_t);
>   extern tree fold_builtin_is_corresponding_member (location_t, int, tree *);
>   extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *);
>   extern tree finish_trait_expr			(location_t, enum cp_trait_kind, tree, tree);
> +extern tree finish_trait_type			(enum cp_trait_kind, tree, tree);
>   extern tree build_lambda_expr                   (void);
>   extern tree build_lambda_object			(tree);
>   extern tree begin_lambda_type                   (tree);
> diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
> index e18143e39a9..d484019a539 100644
> --- a/gcc/cp/cxx-pretty-print.cc
> +++ b/gcc/cp/cxx-pretty-print.cc
> @@ -483,7 +483,7 @@ cxx_pretty_printer::primary_expression (tree t)
>         break;
>   
>       case TRAIT_EXPR:
> -      pp_cxx_trait_expression (this, t);
> +      pp_cxx_trait (this, t);
>         break;
>   
>       case VA_ARG_EXPR:
> @@ -1240,7 +1240,7 @@ cxx_pretty_printer::expression (tree t)
>         break;
>   
>       case TRAIT_EXPR:
> -      pp_cxx_trait_expression (this, t);
> +      pp_cxx_trait (this, t);
>         break;
>   
>       case ATOMIC_CONSTR:
> @@ -1876,7 +1876,7 @@ cxx_pretty_printer::type_id (tree t)
>       case TEMPLATE_PARM_INDEX:
>       case TEMPLATE_DECL:
>       case TYPEOF_TYPE:
> -    case UNDERLYING_TYPE:
> +    case TRAIT_TYPE:

Does this ever end up calling pp_cxx_trait?  Is this code even 
reachable?  It looks like we were already missing support for 
UNDERLYING_TYPE in cxx_pretty_printer::simple_type_specifier.

>       case DECLTYPE_TYPE:
>       case NULLPTR_TYPE:
>       case TEMPLATE_ID_EXPR:
> @@ -2594,9 +2594,22 @@ pp_cxx_binary_fold_expression (cxx_pretty_printer *pp, tree t)
>   }
>   
>   void
> -pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
> +pp_cxx_trait (cxx_pretty_printer *pp, tree t)
>   {
> -  cp_trait_kind kind = TRAIT_EXPR_KIND (t);
> +  cp_trait_kind kind;
> +  tree type1, type2;
> +  if (TREE_CODE (t) == TRAIT_EXPR)
> +    {
> +      kind = TRAIT_EXPR_KIND (t);
> +      type1 = TRAIT_EXPR_TYPE1 (t);
> +      type2 = TRAIT_EXPR_TYPE2 (t);
> +    }
> +  else
> +    {
> +      kind = TRAIT_TYPE_KIND (t);
> +      type1 = TRAIT_TYPE_TYPE1 (t);
> +      type2 = TRAIT_TYPE_TYPE2 (t);
> +    }
>   
>     switch (kind)
>       {
> @@ -2708,23 +2721,29 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
>       case CPTK_REF_CONVERTS_FROM_TEMPORARY:
>         pp_cxx_ws_string (pp, "__reference_converts_from_temporary");
>         break;
> -
> +    case CPTK_UNDERLYING_TYPE:
> +      pp_cxx_ws_string (pp, "__underlying_type");
> +      break;
>       default:
>         gcc_unreachable ();
>       }
>   
>     pp_cxx_left_paren (pp);
> -  pp->type_id (TRAIT_EXPR_TYPE1 (t));
> -
> -  if (kind == CPTK_IS_BASE_OF
> -      || kind == CPTK_IS_SAME_AS
> -      || kind == CPTK_IS_LAYOUT_COMPATIBLE
> -      || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
> +  pp->type_id (type1);
> +  if (type2)
>       {
> -      pp_cxx_separate_with (pp, ',');
> -      pp->type_id (TRAIT_EXPR_TYPE2 (t));
> +      if (TREE_CODE (type2) != TREE_LIST)
> +	{
> +	  pp_cxx_separate_with (pp, ',');
> +	  pp->type_id (type2);
> +	}
> +      else
> +	for (tree arg = type2; arg; arg = TREE_CHAIN (arg))
> +	  {
> +	    pp_cxx_separate_with (pp, ',');
> +	    pp->type_id (TREE_VALUE (arg));
> +	  }
>       }
> -
>     pp_cxx_right_paren (pp);
>   }
>   
> diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
> index 593bd91d4f7..25a2c7c8d4a 100644
> --- a/gcc/cp/cxx-pretty-print.h
> +++ b/gcc/cp/cxx-pretty-print.h
> @@ -90,7 +90,7 @@ void pp_cxx_colon_colon (cxx_pretty_printer *);
>   void pp_cxx_separate_with (cxx_pretty_printer *, int);
>   
>   void pp_cxx_canonical_template_parameter (cxx_pretty_printer *, tree);
> -void pp_cxx_trait_expression (cxx_pretty_printer *, tree);
> +void pp_cxx_trait (cxx_pretty_printer *, tree);
>   void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree);
>   void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree);
>   void pp_cxx_addressof_expression (cxx_pretty_printer *, tree);
> diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> index 0389f35d731..4bf9a83f20b 100644
> --- a/gcc/cp/error.cc
> +++ b/gcc/cp/error.cc
> @@ -698,12 +698,8 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
>         pp_cxx_right_paren (pp);
>         break;
>   
> -    case UNDERLYING_TYPE:
> -      pp_cxx_ws_string (pp, "__underlying_type");
> -      pp_cxx_whitespace (pp);
> -      pp_cxx_left_paren (pp);
> -      dump_expr (pp, UNDERLYING_TYPE_TYPE (t), flags & ~TFF_EXPR_IN_PARENS);
> -      pp_cxx_right_paren (pp);
> +    case TRAIT_TYPE:
> +      pp_cxx_trait (pp, t);
>         break;
>   
>       case TYPE_PACK_EXPANSION:
> @@ -971,7 +967,7 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, int flags)
>       case COMPLEX_TYPE:
>       case VECTOR_TYPE:
>       case TYPEOF_TYPE:
> -    case UNDERLYING_TYPE:
> +    case TRAIT_TYPE:
>       case DECLTYPE_TYPE:
>       case TYPE_PACK_EXPANSION:
>       case FIXED_POINT_TYPE:
> @@ -1095,7 +1091,7 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags)
>       case COMPLEX_TYPE:
>       case VECTOR_TYPE:
>       case TYPEOF_TYPE:
> -    case UNDERLYING_TYPE:
> +    case TRAIT_TYPE:
>       case DECLTYPE_TYPE:
>       case TYPE_PACK_EXPANSION:
>       case FIXED_POINT_TYPE:
> @@ -2956,7 +2952,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
>         break;
>   
>       case TRAIT_EXPR:
> -      pp_cxx_trait_expression (pp, t);
> +      pp_cxx_trait (pp, t);
>         break;
>   
>       case VA_ARG_EXPR:
> diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
> index 00d283fff8c..fc750fc5d8e 100644
> --- a/gcc/cp/mangle.cc
> +++ b/gcc/cp/mangle.cc
> @@ -2389,8 +2389,9 @@ write_type (tree type)
>   	      sorry ("mangling %<typeof%>, use %<decltype%> instead");
>   	      break;
>   
> -	    case UNDERLYING_TYPE:
> -	      sorry ("mangling %<__underlying_type%>");
> +	    case TRAIT_TYPE:
> +	      error ("use of built-in trait %qT in function signature; "
> +		     "use library traits instead", type);
>   	      break;
>   
>   	    case LANG_TYPE:
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 7496df5e843..25741e5d827 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -8910,7 +8910,6 @@ trees_out::type_node (tree type)
>   
>       case DECLTYPE_TYPE:
>       case TYPEOF_TYPE:
> -    case UNDERLYING_TYPE:
>       case DEPENDENT_OPERATOR_TYPE:
>         tree_node (TYPE_VALUES_RAW (type));
>         if (TREE_CODE (type) == DECLTYPE_TYPE)
> @@ -8920,6 +8919,12 @@ trees_out::type_node (tree type)
>   	  tree_node_bools (type);
>         break;
>   
> +    case TRAIT_TYPE:
> +      tree_node (TRAIT_TYPE_KIND_RAW (type));
> +      tree_node (TRAIT_TYPE_TYPE1 (type));
> +      tree_node (TRAIT_TYPE_TYPE2 (type));
> +      break;
> +
>       case TYPE_ARGUMENT_PACK:
>         /* No additional data.  */
>         break;
> @@ -9434,7 +9439,6 @@ trees_in::tree_node (bool is_use)
>   
>   	  case DECLTYPE_TYPE:
>   	  case TYPEOF_TYPE:
> -	  case UNDERLYING_TYPE:
>   	  case DEPENDENT_OPERATOR_TYPE:
>   	    {
>   	      tree expr = tree_node ();
> @@ -9449,6 +9453,22 @@ trees_in::tree_node (bool is_use)
>   	    }
>   	    break;
>   
> +	  case TRAIT_TYPE:
> +	    {
> +	      tree kind = tree_node ();
> +	      tree type1 = tree_node ();
> +	      tree type2 = tree_node ();
> +	      if (!get_overrun ())
> +		{
> +		  res = cxx_make_type (TRAIT_TYPE);
> +		  TRAIT_TYPE_KIND_RAW (res) = kind;
> +		  TRAIT_TYPE_TYPE1 (res) = type1;
> +		  TRAIT_TYPE_TYPE2 (res) = type2;
> +		  SET_TYPE_STRUCTURAL_EQUALITY (res);

This needs a rationale for structural equality rather than canonicalization.

> +		}
> +	    }
> +	    break;
> +
>   	  case TYPE_ARGUMENT_PACK:
>   	    if (!get_overrun ())
>   	      {
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index d501178634a..9f5e2c292b3 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -2783,7 +2783,7 @@ static void cp_parser_late_parsing_default_args
>     (cp_parser *, tree);
>   static tree cp_parser_sizeof_operand
>     (cp_parser *, enum rid);
> -static cp_expr cp_parser_trait_expr
> +static cp_expr cp_parser_trait
>     (cp_parser *, enum rid);
>   static bool cp_parser_declares_only_class_p
>     (cp_parser *);
> @@ -5928,7 +5928,7 @@ cp_parser_primary_expression (cp_parser *parser,
>   	case RID_IS_NOTHROW_CONVERTIBLE:
>   	case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
>   	case RID_REF_CONVERTS_FROM_TEMPORARY:
> -	  return cp_parser_trait_expr (parser, token->keyword);
> +	  return cp_parser_trait (parser, token->keyword);
>   
>   	// C++ concepts
>   	case RID_REQUIRES:
> @@ -10882,18 +10882,16 @@ cp_parser_builtin_offsetof (cp_parser *parser)
>     return expr;
>   }
>   
> -/* Parse a trait expression.
> -
> -   Returns a representation of the expression, the underlying type
> -   of the type at issue when KEYWORD is RID_UNDERLYING_TYPE.  */
> +/* Parse a builtin trait expression or type.  */
>   
>   static cp_expr
> -cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
> +cp_parser_trait (cp_parser* parser, enum rid keyword)
>   {
>     cp_trait_kind kind;
>     tree type1, type2 = NULL_TREE;
>     bool binary = false;
>     bool variadic = false;
> +  bool type = false;
>   
>     switch (keyword)
>       {
> @@ -10989,6 +10987,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
>         break;
>       case RID_UNDERLYING_TYPE:
>         kind = CPTK_UNDERLYING_TYPE;
> +      type = true;
>         break;
>       case RID_BASES:
>         kind = CPTK_BASES;
> @@ -11092,14 +11091,15 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
>        the trait expr now or saving it for template instantiation.  */
>     switch (kind)
>       {
> -    case CPTK_UNDERLYING_TYPE:
> -      return cp_expr (finish_underlying_type (type1), trait_loc);
>       case CPTK_BASES:
>         return cp_expr (finish_bases (type1, false), trait_loc);
>       case CPTK_DIRECT_BASES:
>         return cp_expr (finish_bases (type1, true), trait_loc);
>       default:
> -      return finish_trait_expr (trait_loc, kind, type1, type2);
> +      if (type)
> +	return finish_trait_type (kind, type1, type2);
> +      else
> +	return finish_trait_expr (trait_loc, kind, type1, type2);
>       }
>   }
>   
> @@ -19867,7 +19867,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>         return type;
>   
>       case RID_UNDERLYING_TYPE:
> -      type = cp_parser_trait_expr (parser, RID_UNDERLYING_TYPE);
> +      type = cp_parser_trait (parser, token->keyword);
>         if (decl_specs)
>   	cp_parser_set_decl_spec_type (decl_specs, type,
>   				      token,
> @@ -19877,7 +19877,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>   
>       case RID_BASES:
>       case RID_DIRECT_BASES:
> -      type = cp_parser_trait_expr (parser, token->keyword);
> +      type = cp_parser_trait (parser, token->keyword);
>         if (decl_specs)
>          cp_parser_set_decl_spec_type (decl_specs, type,
>                                        token,
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 30c6994bae1..1a4491d3556 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -10619,7 +10619,6 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
>   
>       case TYPEOF_TYPE:
>       case DECLTYPE_TYPE:
> -    case UNDERLYING_TYPE:
>         if (pfd->include_nondeduced_p
>   	  && for_each_template_parm (TYPE_VALUES_RAW (t), fn, data,
>   				     pfd->visited,
> @@ -10629,6 +10628,15 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
>         *walk_subtrees = false;
>         break;
>   
> +    case TRAIT_TYPE:
> +      if (pfd->include_nondeduced_p)
> +	{
> +	  WALK_SUBTREE (TRAIT_TYPE_TYPE1 (t));
> +	  WALK_SUBTREE (TRAIT_TYPE_TYPE2 (t));
> +	}
> +      *walk_subtrees = false;
> +      break;
> +
>       case FUNCTION_DECL:
>       case VAR_DECL:
>         if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
> @@ -16515,11 +16523,11 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   					complain | tf_ignore_bad_quals);
>         }
>   
> -    case UNDERLYING_TYPE:
> +    case TRAIT_TYPE:
>         {
> -	tree type = tsubst (UNDERLYING_TYPE_TYPE (t), args,
> -			    complain, in_decl);
> -	return finish_underlying_type (type);
> +	tree type1 = tsubst (TRAIT_TYPE_TYPE1 (t), args, complain, in_decl);
> +	tree type2 = tsubst (TRAIT_TYPE_TYPE2 (t), args, complain, in_decl);
> +	return finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2);
>         }
>   
>       case TYPE_ARGUMENT_PACK:
> @@ -24929,9 +24937,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
>   
>       case TYPEOF_TYPE:
>       case DECLTYPE_TYPE:
> -    case UNDERLYING_TYPE:
> +    case TRAIT_TYPE:
>         /* Cannot deduce anything from TYPEOF_TYPE, DECLTYPE_TYPE,
> -	 or UNDERLYING_TYPE nodes.  */
> +	 or TRAIT_TYPE nodes.  */
>         return unify_success (explain_p);
>   
>       case ERROR_MARK:
> @@ -27506,12 +27514,12 @@ dependent_type_p_r (tree type)
>   	       (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)))))
>       return true;
>   
> -  /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and UNDERLYING_TYPEs are
> +  /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and TRAIT_TYPEs are
>        dependent; if the argument of the `typeof' expression is not
>        type-dependent, then it should already been have resolved.  */
>     if (TREE_CODE (type) == TYPEOF_TYPE
>         || TREE_CODE (type) == DECLTYPE_TYPE
> -      || TREE_CODE (type) == UNDERLYING_TYPE)
> +      || TREE_CODE (type) == TRAIT_TYPE)
>       return true;
>   
>     /* A template argument pack is dependent if any of its packed
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index e8cd50558d6..ea00805c97d 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -4397,17 +4397,6 @@ finish_typeof (tree expr)
>   tree
>   finish_underlying_type (tree type)
>   {
> -  tree underlying_type;
> -
> -  if (processing_template_decl)
> -    {
> -      underlying_type = cxx_make_type (UNDERLYING_TYPE);
> -      UNDERLYING_TYPE_TYPE (underlying_type) = type;
> -      SET_TYPE_STRUCTURAL_EQUALITY (underlying_type);
> -
> -      return underlying_type;
> -    }
> -
>     if (!complete_type_or_else (type, NULL_TREE))
>       return error_mark_node;
>   
> @@ -4417,7 +4406,7 @@ finish_underlying_type (tree type)
>         return error_mark_node;
>       }
>   
> -  underlying_type = ENUM_UNDERLYING_TYPE (type);
> +  tree underlying_type = ENUM_UNDERLYING_TYPE (type);
>   
>     /* Fixup necessary in this case because ENUM_UNDERLYING_TYPE
>        includes TYPE_MIN_VALUE and TYPE_MAX_VALUE information.
> @@ -12224,6 +12213,34 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
>     return maybe_wrap_with_location (val, loc);
>   }
>   
> +/* Process a trait type.  */
> +
> +tree
> +finish_trait_type (cp_trait_kind kind, tree type1, tree type2)
> +{
> +  if (type1 == error_mark_node
> +      || type2 == error_mark_node)
> +    return error_mark_node;
> +
> +  if (processing_template_decl)
> +    {
> +      tree type = cxx_make_type (TRAIT_TYPE);
> +      TRAIT_TYPE_TYPE1 (type) = type1;
> +      TRAIT_TYPE_TYPE2 (type) = type2;
> +      TRAIT_TYPE_KIND_RAW (type) = build_int_cstu (integer_type_node, kind);
> +      SET_TYPE_STRUCTURAL_EQUALITY (type);
> +      return type;
> +    }
> +
> +  switch (kind)
> +    {
> +    case CPTK_UNDERLYING_TYPE:
> +      return finish_underlying_type (type1);
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +
>   /* Do-nothing variants of functions to handle pragma FLOAT_CONST_DECIMAL64,
>      which is ignored for C++.  */
>   
> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> index d0bd41ae5a0..eef694689cc 100644
> --- a/gcc/cp/tree.cc
> +++ b/gcc/cp/tree.cc
> @@ -1776,10 +1776,17 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
>   		   DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t),
>   		   tf_none));
>         break;
> -    case UNDERLYING_TYPE:
> -      type = strip_typedefs (UNDERLYING_TYPE_TYPE (t),
> -			     remove_attributes, flags);
> -      result = finish_underlying_type (type);
> +    case TRAIT_TYPE:
> +      {
> +	tree type1 = strip_typedefs (TRAIT_TYPE_TYPE1 (t),
> +				     remove_attributes, flags);
> +	tree type2 = strip_typedefs (TRAIT_TYPE_TYPE2 (t),
> +				     remove_attributes, flags);
> +	if (type1 == TRAIT_TYPE_TYPE1 (t) && type2 == TRAIT_TYPE_TYPE2 (t))
> +	  result = NULL_TREE;
> +	else
> +	  result = finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2);
> +      }
>         break;
>       case TYPE_PACK_EXPANSION:
>         {
> @@ -5383,7 +5390,6 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
>       case UNBOUND_CLASS_TEMPLATE:
>       case TEMPLATE_PARM_INDEX:
>       case TYPEOF_TYPE:
> -    case UNDERLYING_TYPE:
>         /* None of these have subtrees other than those already walked
>   	 above.  */
>         *walk_subtrees_p = 0;
> @@ -5472,6 +5478,12 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
>         *walk_subtrees_p = 0;
>         break;
>   
> +    case TRAIT_TYPE:
> +      WALK_SUBTREE (TRAIT_TYPE_TYPE1 (*tp));
> +      WALK_SUBTREE (TRAIT_TYPE_TYPE2 (*tp));
> +      *walk_subtrees_p = 0;
> +      break;
> +
>       case DECLTYPE_TYPE:
>         ++cp_unevaluated_operand;
>         /* We can't use WALK_SUBTREE here because of the goto.  */
> diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> index 4854b983765..5064a009af0 100644
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -1621,8 +1621,11 @@ structural_comptypes (tree t1, tree t2, int strict)
>           return false;
>         break;
>   
> -    case UNDERLYING_TYPE:
> -      if (!same_type_p (UNDERLYING_TYPE_TYPE (t1), UNDERLYING_TYPE_TYPE (t2)))
> +    case TRAIT_TYPE:
> +      if (TRAIT_TYPE_KIND (t1) != TRAIT_TYPE_KIND (t2))
> +	return false;
> +      if (!same_type_p (TRAIT_TYPE_TYPE1 (t1), TRAIT_TYPE_TYPE1 (t2))
> +	  || !cp_tree_equal (TRAIT_TYPE_TYPE2 (t1), TRAIT_TYPE_TYPE2 (t2)))
>   	return false;
>         break;
>   
> diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
> index 1f5e94f6d83..50946576f74 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
> @@ -5,7 +5,7 @@ template<typename>
>   struct A {};
>   
>   template<typename T>
> -using B = A<__underlying_type(T) [[gnu::aligned(4)]]>; // { dg-warning "ignoring attributes on template argument" }
> +using B = A<__underlying_type(T) [[gnu::aligned(4)]]>; // { dg-warning "ignoring attributes applied to dependent type" }
>   
>   template<typename T>
> -using B = A<__underlying_type(T) [[gnu::packed]]>; // { dg-warning "ignoring attributes on template argument" }
> +using B = A<__underlying_type(T) [[gnu::packed]]>; // { dg-warning "ignoring attributes applied to dependent type" }
> diff --git a/gcc/testsuite/g++.dg/ext/underlying_type7.C b/gcc/testsuite/g++.dg/ext/underlying_type7.C
> index 2d6ec51792c..137a0f08547 100644
> --- a/gcc/testsuite/g++.dg/ext/underlying_type7.C
> +++ b/gcc/testsuite/g++.dg/ext/underlying_type7.C
> @@ -9,7 +9,7 @@ enum class E6 : long { c = __LONG_MAX__ };
>   
>   template<typename T>
>     void
> -  test(T, __underlying_type(T)) // { dg-message "sorry, unimplemented: mangling" }
> +  test(T, __underlying_type(T)) // { dg-error "built-in trait '__underlying_type\\(T\\)'" }
>     { }
>   
>   int main()
  
Patrick Palka Sept. 28, 2022, 4:36 p.m. UTC | #2
On Tue, 27 Sep 2022, Jason Merrill wrote:

> On 9/27/22 15:50, Patrick Palka wrote:
> > We already have generic support for predicate-like traits that yield a
> > boolean via TRAIT_EXPR, but we lack the same support for transform-like
> > traits that yield a type.  Such support would be useful for implementing
> > efficient built-ins for std::decay and std::remove_cvref and other
> > conceptually simple type traits that are otherwise relatively expensive
> > to implement.
> > 
> > This patch implements a generic TRAIT_TYPE type and replaces the
> > existing hardcoded UNDERLYING_TYPE type to use TRAIT_TYPE instead.
> 
> Sounds good, perhaps we also want to convert BASES to e.g. TRAIT_TYPE_PACK at
> some point...

*nod*

> 
> > gcc/cp/ChangeLog:
> > 
> > 	* cp-objcp-common.cc (cp_common_init_ts): Replace
> > 	UNDERLYING_TYPE with TRAIT_TYPE.
> > 	* cp-tree.def (TRAIT_TYPE): Define.
> > 	(UNDERLYING_TYPE): Remove.
> > 	* cp-tree.h (TRAIT_TYPE_KIND_RAW): Define.
> > 	(TRAIT_TYPE_KIND): Define.
> > 	(TRAIT_TYPE_TYPE1): Define.
> > 	(TRAIT_TYPE_TYPE2): Define.
> > 	(WILDCARD_TYPE_P): Return true for TRAIT_TYPE.
> > 	(finish_trait_type): Declare.
> > 	* cxx-pretty-print.cc (cxx_pretty_printer::primary_expression):
> > 	Adjust after renaming pp_cxx_trait_expression.
> > 	(cxx_pretty_printer::type_id): Replace UNDERLYING_TYPE with
> > 	TRAIT_TYPE.
> > 	(pp_cxx_trait_expression): Rename to ...
> > 	(pp_cxx_trait): ... this.  Handle TRAIT_TYPE as well.  Correct
> > 	pretty printing of the trailing arguments.
> > 	* cxx-pretty-print.h (pp_cxx_trait_expression): Rename to ...
> > 	(pp_cxx_trait_type): ... this.
> > 	* error.cc (dump_type) <case UNDERLYING_TYPE>: Remove.
> > 	<case TRAIT_TYPE>: New.
> > 	(dump_type_prefix): Replace UNDERLYING_WITH with TRAIT_TYPE.
> > 	(dump_type_suffix): Likewise.
> > 	* mangle.cc (write_type) <case UNDERLYING_TYPE>: Remove.
> > 	<case TRAIT_TYPE>: New.
> > 	* module.cc (trees_out::type_node) <case UNDERLYING_TYPE>:
> > 	Remove.
> > 	<case TRAIT_TYPE>: New.
> > 	(trees_in::tree_node): Likewise.
> > 	* parser.cc (cp_parser_primary_expression): Adjust after
> > 	renaming cp_parser_trait_expr.
> > 	(cp_parser_trait_expr): Rename to ...
> > 	(cp_parser_trait): ... this.  Call finish_trait_type for traits
> > 	that yield a type.
> > 	(cp_parser_simple_type_specifier): Adjust after renaming
> > 	cp_parser_trait_expr.
> > 	* pt.cc (for_each_template_parm_r) <case UNDERLYING_TYPE>:
> > 	Remove.
> > 	<case TRAIT_TYPE>: New.
> > 	(tsubst): Likewise.
> > 	(unify): Replace UNDERLYING_TYPE with TRAIT_TYPE.
> > 	(dependent_type_p_r): Likewise.
> > 	* semantics.cc (finish_underlying_type): Don't return
> > 	UNDERLYING_TYPE anymore when processing_template_decl.
> > 	(finish_trait_type): Define.
> > 	* tree.cc (strip_typedefs) <case UNDERLYING_TYPE>: Remove.
> > 	<case TRAIT_TYPE>: New.
> > 	(cp_walk_subtrees): Likewise.
> > 	* typeck.cc (structural_comptypes): Likewise.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/ext/underlying_type7.C: Adjust expected error message.
> > ---
> >   gcc/cp/cp-objcp-common.cc                   |  2 +-
> >   gcc/cp/cp-tree.def                          |  9 ++--
> >   gcc/cp/cp-tree.h                            | 18 ++++++++
> >   gcc/cp/cxx-pretty-print.cc                  | 49 ++++++++++++++-------
> >   gcc/cp/cxx-pretty-print.h                   |  2 +-
> >   gcc/cp/error.cc                             | 14 +++---
> >   gcc/cp/mangle.cc                            |  5 ++-
> >   gcc/cp/module.cc                            | 24 +++++++++-
> >   gcc/cp/parser.cc                            | 24 +++++-----
> >   gcc/cp/pt.cc                                | 26 +++++++----
> >   gcc/cp/semantics.cc                         | 41 ++++++++++++-----
> >   gcc/cp/tree.cc                              | 22 ++++++---
> >   gcc/cp/typeck.cc                            |  7 ++-
> >   gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C  |  4 +-
> >   gcc/testsuite/g++.dg/ext/underlying_type7.C |  2 +-
> >   15 files changed, 171 insertions(+), 78 deletions(-)
> > 
> > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > index 64975699351..380f288a7f1 100644
> > --- a/gcc/cp/cp-objcp-common.cc
> > +++ b/gcc/cp/cp-objcp-common.cc
> > @@ -518,7 +518,7 @@ cp_common_init_ts (void)
> >     MARK_TS_TYPE_NON_COMMON (DECLTYPE_TYPE);
> >     MARK_TS_TYPE_NON_COMMON (TYPENAME_TYPE);
> >     MARK_TS_TYPE_NON_COMMON (TYPEOF_TYPE);
> > -  MARK_TS_TYPE_NON_COMMON (UNDERLYING_TYPE);
> > +  MARK_TS_TYPE_NON_COMMON (TRAIT_TYPE);
> >     MARK_TS_TYPE_NON_COMMON (BOUND_TEMPLATE_TEMPLATE_PARM);
> >     MARK_TS_TYPE_NON_COMMON (TEMPLATE_TEMPLATE_PARM);
> >     MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM);
> > diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
> > index f9cbd339f19..f83b4c54d43 100644
> > --- a/gcc/cp/cp-tree.def
> > +++ b/gcc/cp/cp-tree.def
> > @@ -444,9 +444,12 @@ DEFTREECODE (BIT_CAST_EXPR, "bit_cast_expr",
> > tcc_expression, 1)
> >     /** C++ extensions. */
> >   -/* Represents a trait expression during template expansion.  */
> > +/* Represents a templated trait that yields an expression.  */
> >   DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0)
> >   +/* Represents a templated trait that yields a type.  */
> > +DEFTREECODE (TRAIT_TYPE, "trait_type", tcc_type, 0)
> > +
> >   /* A lambda expression.  This is a C++0x extension.
> >      LAMBDA_EXPR_DEFAULT_CAPTURE_MODE is an enum for the default, which may
> > be
> >      none.
> > @@ -466,10 +469,6 @@ DEFTREECODE (LAMBDA_EXPR, "lambda_expr",
> > tcc_exceptional, 0)
> >      DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction.
> > */
> >   DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
> >   -/* A type designated by `__underlying_type (type)'.
> > -   UNDERLYING_TYPE_TYPE is the type in question.  */
> > -DEFTREECODE (UNDERLYING_TYPE, "underlying_type", tcc_type, 0)
> > -
> >   /* A type designated by one of the bases type traits.
> >      BASES_TYPE is the type in question.  */
> >   DEFTREECODE (BASES, "bases", tcc_type, 0)
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index 99b486b8002..c9adf1b3822 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -1436,6 +1436,22 @@ struct GTY (()) tree_trait_expr {
> >     enum cp_trait_kind kind;
> >   };
> >   +/* An INTEGER_CST containing the kind of the trait type NODE.  */
> > +#define TRAIT_TYPE_KIND_RAW(NODE) \
> > +  TYPE_VALUES_RAW (TRAIT_TYPE_CHECK (NODE))
> > +
> > +/* The kind of the trait type NODE.  */
> > +#define TRAIT_TYPE_KIND(NODE) \
> > +  ((enum cp_trait_kind) TREE_INT_CST_LOW (TRAIT_TYPE_KIND_RAW (NODE)))
> > +
> > +/* The first argument of the trait type NODE.  */
> > +#define TRAIT_TYPE_TYPE1(NODE) \
> > +  TYPE_MIN_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
> > +
> > +/* The rest of the arguments of the trait type NODE.  */
> > +#define TRAIT_TYPE_TYPE2(NODE) \
> > +  TYPE_MAX_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
> 
> Can we also store the location of the trait use?

Hmm, I suppose we could create a TYPE_DECL for each use and store it
there, but I'm not really sure how we'd use this location?  Presumably
for diagnostics, but I can't come up with an example.

FWIW I think currently TYPENAME_TYPE is the only "non-declared" type that
has a TYPE_DECL (and location info).  DECLTYPE_TYPE, TYPE_PACK_EXPANSION,
etc don't have TYPE_DECL (or location info).  I wonder why only
TYPENAME_TYPE has one?

> 
> > +
> >   /* Identifiers used for lambda types are almost anonymous.  Use this
> >      spare flag to distinguish them (they also have the anonymous flag).  */
> >   #define IDENTIFIER_LAMBDA_P(NODE) \
> > @@ -2225,6 +2241,7 @@ enum languages { lang_c, lang_cplusplus };
> >      || TREE_CODE (T) == TYPEOF_TYPE			\
> >      || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM	\
> >      || TREE_CODE (T) == DECLTYPE_TYPE			\
> > +   || TREE_CODE (T) == TRAIT_TYPE			\
> >      || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE)
> >     /* Nonzero if T is a class (or struct or union) type.  Also nonzero
> > @@ -7730,6 +7747,7 @@ extern tree finish_decltype_type                (tree,
> > bool, tsubst_flags_t);
> >   extern tree fold_builtin_is_corresponding_member (location_t, int, tree
> > *);
> >   extern tree fold_builtin_is_pointer_inverconvertible_with_class
> > (location_t, int, tree *);
> >   extern tree finish_trait_expr			(location_t, enum
> > cp_trait_kind, tree, tree);
> > +extern tree finish_trait_type			(enum cp_trait_kind,
> > tree, tree);
> >   extern tree build_lambda_expr                   (void);
> >   extern tree build_lambda_object			(tree);
> >   extern tree begin_lambda_type                   (tree);
> > diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
> > index e18143e39a9..d484019a539 100644
> > --- a/gcc/cp/cxx-pretty-print.cc
> > +++ b/gcc/cp/cxx-pretty-print.cc
> > @@ -483,7 +483,7 @@ cxx_pretty_printer::primary_expression (tree t)
> >         break;
> >         case TRAIT_EXPR:
> > -      pp_cxx_trait_expression (this, t);
> > +      pp_cxx_trait (this, t);
> >         break;
> >         case VA_ARG_EXPR:
> > @@ -1240,7 +1240,7 @@ cxx_pretty_printer::expression (tree t)
> >         break;
> >         case TRAIT_EXPR:
> > -      pp_cxx_trait_expression (this, t);
> > +      pp_cxx_trait (this, t);
> >         break;
> >         case ATOMIC_CONSTR:
> > @@ -1876,7 +1876,7 @@ cxx_pretty_printer::type_id (tree t)
> >       case TEMPLATE_PARM_INDEX:
> >       case TEMPLATE_DECL:
> >       case TYPEOF_TYPE:
> > -    case UNDERLYING_TYPE:
> > +    case TRAIT_TYPE:
> 
> Does this ever end up calling pp_cxx_trait?  Is this code even reachable?  It
> looks like we were already missing support for UNDERLYING_TYPE in
> cxx_pretty_printer::simple_type_specifier.

Looks like it's reachable at least through pp_cxx_trait (which calls
type_id on each of the trait's arguments), so e.g. when pretty printing
__remove_cv(__remove_cv(T)) we currently get the "unhandled tree code"
fallback for the inner trait.  I fixed this in v2 below by adding support
for UNDERLYING_TYPE in simple_type_specifier and added a testcase.

> 
> >       case DECLTYPE_TYPE:
> >       case NULLPTR_TYPE:
> >       case TEMPLATE_ID_EXPR:
> > @@ -2594,9 +2594,22 @@ pp_cxx_binary_fold_expression (cxx_pretty_printer
> > *pp, tree t)
> >   }
> >     void
> > -pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
> > +pp_cxx_trait (cxx_pretty_printer *pp, tree t)
> >   {
> > -  cp_trait_kind kind = TRAIT_EXPR_KIND (t);
> > +  cp_trait_kind kind;
> > +  tree type1, type2;
> > +  if (TREE_CODE (t) == TRAIT_EXPR)
> > +    {
> > +      kind = TRAIT_EXPR_KIND (t);
> > +      type1 = TRAIT_EXPR_TYPE1 (t);
> > +      type2 = TRAIT_EXPR_TYPE2 (t);
> > +    }
> > +  else
> > +    {
> > +      kind = TRAIT_TYPE_KIND (t);
> > +      type1 = TRAIT_TYPE_TYPE1 (t);
> > +      type2 = TRAIT_TYPE_TYPE2 (t);
> > +    }
> >       switch (kind)
> >       {
> > @@ -2708,23 +2721,29 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp,
> > tree t)
> >       case CPTK_REF_CONVERTS_FROM_TEMPORARY:
> >         pp_cxx_ws_string (pp, "__reference_converts_from_temporary");
> >         break;
> > -
> > +    case CPTK_UNDERLYING_TYPE:
> > +      pp_cxx_ws_string (pp, "__underlying_type");
> > +      break;
> >       default:
> >         gcc_unreachable ();
> >       }
> >       pp_cxx_left_paren (pp);
> > -  pp->type_id (TRAIT_EXPR_TYPE1 (t));
> > -
> > -  if (kind == CPTK_IS_BASE_OF
> > -      || kind == CPTK_IS_SAME_AS
> > -      || kind == CPTK_IS_LAYOUT_COMPATIBLE
> > -      || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
> > +  pp->type_id (type1);
> > +  if (type2)
> >       {
> > -      pp_cxx_separate_with (pp, ',');
> > -      pp->type_id (TRAIT_EXPR_TYPE2 (t));
> > +      if (TREE_CODE (type2) != TREE_LIST)
> > +	{
> > +	  pp_cxx_separate_with (pp, ',');
> > +	  pp->type_id (type2);
> > +	}
> > +      else
> > +	for (tree arg = type2; arg; arg = TREE_CHAIN (arg))
> > +	  {
> > +	    pp_cxx_separate_with (pp, ',');
> > +	    pp->type_id (TREE_VALUE (arg));
> > +	  }
> >       }
> > -
> >     pp_cxx_right_paren (pp);
> >   }
> >   diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
> > index 593bd91d4f7..25a2c7c8d4a 100644
> > --- a/gcc/cp/cxx-pretty-print.h
> > +++ b/gcc/cp/cxx-pretty-print.h
> > @@ -90,7 +90,7 @@ void pp_cxx_colon_colon (cxx_pretty_printer *);
> >   void pp_cxx_separate_with (cxx_pretty_printer *, int);
> >     void pp_cxx_canonical_template_parameter (cxx_pretty_printer *, tree);
> > -void pp_cxx_trait_expression (cxx_pretty_printer *, tree);
> > +void pp_cxx_trait (cxx_pretty_printer *, tree);
> >   void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree);
> >   void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree);
> >   void pp_cxx_addressof_expression (cxx_pretty_printer *, tree);
> > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> > index 0389f35d731..4bf9a83f20b 100644
> > --- a/gcc/cp/error.cc
> > +++ b/gcc/cp/error.cc
> > @@ -698,12 +698,8 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
> >         pp_cxx_right_paren (pp);
> >         break;
> >   -    case UNDERLYING_TYPE:
> > -      pp_cxx_ws_string (pp, "__underlying_type");
> > -      pp_cxx_whitespace (pp);
> > -      pp_cxx_left_paren (pp);
> > -      dump_expr (pp, UNDERLYING_TYPE_TYPE (t), flags &
> > ~TFF_EXPR_IN_PARENS);
> > -      pp_cxx_right_paren (pp);
> > +    case TRAIT_TYPE:
> > +      pp_cxx_trait (pp, t);
> >         break;
> >         case TYPE_PACK_EXPANSION:
> > @@ -971,7 +967,7 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, int
> > flags)
> >       case COMPLEX_TYPE:
> >       case VECTOR_TYPE:
> >       case TYPEOF_TYPE:
> > -    case UNDERLYING_TYPE:
> > +    case TRAIT_TYPE:
> >       case DECLTYPE_TYPE:
> >       case TYPE_PACK_EXPANSION:
> >       case FIXED_POINT_TYPE:
> > @@ -1095,7 +1091,7 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int
> > flags)
> >       case COMPLEX_TYPE:
> >       case VECTOR_TYPE:
> >       case TYPEOF_TYPE:
> > -    case UNDERLYING_TYPE:
> > +    case TRAIT_TYPE:
> >       case DECLTYPE_TYPE:
> >       case TYPE_PACK_EXPANSION:
> >       case FIXED_POINT_TYPE:
> > @@ -2956,7 +2952,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
> >         break;
> >         case TRAIT_EXPR:
> > -      pp_cxx_trait_expression (pp, t);
> > +      pp_cxx_trait (pp, t);
> >         break;
> >         case VA_ARG_EXPR:
> > diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
> > index 00d283fff8c..fc750fc5d8e 100644
> > --- a/gcc/cp/mangle.cc
> > +++ b/gcc/cp/mangle.cc
> > @@ -2389,8 +2389,9 @@ write_type (tree type)
> >   	      sorry ("mangling %<typeof%>, use %<decltype%> instead");
> >   	      break;
> >   -	    case UNDERLYING_TYPE:
> > -	      sorry ("mangling %<__underlying_type%>");
> > +	    case TRAIT_TYPE:
> > +	      error ("use of built-in trait %qT in function signature; "
> > +		     "use library traits instead", type);
> >   	      break;
> >     	    case LANG_TYPE:
> > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > index 7496df5e843..25741e5d827 100644
> > --- a/gcc/cp/module.cc
> > +++ b/gcc/cp/module.cc
> > @@ -8910,7 +8910,6 @@ trees_out::type_node (tree type)
> >         case DECLTYPE_TYPE:
> >       case TYPEOF_TYPE:
> > -    case UNDERLYING_TYPE:
> >       case DEPENDENT_OPERATOR_TYPE:
> >         tree_node (TYPE_VALUES_RAW (type));
> >         if (TREE_CODE (type) == DECLTYPE_TYPE)
> > @@ -8920,6 +8919,12 @@ trees_out::type_node (tree type)
> >   	  tree_node_bools (type);
> >         break;
> >   +    case TRAIT_TYPE:
> > +      tree_node (TRAIT_TYPE_KIND_RAW (type));
> > +      tree_node (TRAIT_TYPE_TYPE1 (type));
> > +      tree_node (TRAIT_TYPE_TYPE2 (type));
> > +      break;
> > +
> >       case TYPE_ARGUMENT_PACK:
> >         /* No additional data.  */
> >         break;
> > @@ -9434,7 +9439,6 @@ trees_in::tree_node (bool is_use)
> >     	  case DECLTYPE_TYPE:
> >   	  case TYPEOF_TYPE:
> > -	  case UNDERLYING_TYPE:
> >   	  case DEPENDENT_OPERATOR_TYPE:
> >   	    {
> >   	      tree expr = tree_node ();
> > @@ -9449,6 +9453,22 @@ trees_in::tree_node (bool is_use)
> >   	    }
> >   	    break;
> >   +	  case TRAIT_TYPE:
> > +	    {
> > +	      tree kind = tree_node ();
> > +	      tree type1 = tree_node ();
> > +	      tree type2 = tree_node ();
> > +	      if (!get_overrun ())
> > +		{
> > +		  res = cxx_make_type (TRAIT_TYPE);
> > +		  TRAIT_TYPE_KIND_RAW (res) = kind;
> > +		  TRAIT_TYPE_TYPE1 (res) = type1;
> > +		  TRAIT_TYPE_TYPE2 (res) = type2;
> > +		  SET_TYPE_STRUCTURAL_EQUALITY (res);
> 
> This needs a rationale for structural equality rather than canonicalization.

Fixed in v2.  I suppose we can get away with structural equality given
the intended use of these traits is to implement the standard library
traits.

Also in v2, make sure to propagate the cv-quals of TRAIT_TYPE during
substitution.

-- >8 --

Subject: [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR

gcc/cp/ChangeLog:

	* cp-objcp-common.cc (cp_common_init_ts): Replace
	UNDERLYING_TYPE with TRAIT_TYPE.
	* cp-tree.def (TRAIT_TYPE): Define.
	(UNDERLYING_TYPE): Remove.
	* cp-tree.h (TRAIT_TYPE_KIND_RAW): Define.
	(TRAIT_TYPE_KIND): Define.
	(TRAIT_TYPE_TYPE1): Define.
	(TRAIT_TYPE_TYPE2): Define.
	(WILDCARD_TYPE_P): Return true for TRAIT_TYPE.
	(finish_trait_type): Declare.
	* cxx-pretty-print.cc (cxx_pretty_printer::primary_expression):
	Adjust after renaming pp_cxx_trait_expression.
	(cxx_pretty_printer::simple_type_specifier) <case TRAIT_TYPE>:
	New.
	(cxx_pretty_printer::type_id): Replace UNDERLYING_TYPE with
	TRAIT_TYPE.
	(pp_cxx_trait_expression): Rename to ...
	(pp_cxx_trait): ... this.  Handle TRAIT_TYPE as well.  Correct
	pretty printing of the trailing arguments.
	* cxx-pretty-print.h (pp_cxx_trait_expression): Rename to ...
	(pp_cxx_trait_type): ... this.
	* error.cc (dump_type) <case UNDERLYING_TYPE>: Remove.
	<case TRAIT_TYPE>: New.
	(dump_type_prefix): Replace UNDERLYING_WITH with TRAIT_TYPE.
	(dump_type_suffix): Likewise.
	* mangle.cc (write_type) <case UNDERLYING_TYPE>: Remove.
	<case TRAIT_TYPE>: New.
	* module.cc (trees_out::type_node) <case UNDERLYING_TYPE>:
	Remove.
	<case TRAIT_TYPE>: New.
	(trees_in::tree_node): Likewise.
	* parser.cc (cp_parser_primary_expression): Adjust after
	renaming cp_parser_trait_expr.
	(cp_parser_trait_expr): Rename to ...
	(cp_parser_trait): ... this.  Call finish_trait_type for traits
	that yield a type.
	(cp_parser_simple_type_specifier): Adjust after renaming
	cp_parser_trait_expr.
	* pt.cc (for_each_template_parm_r) <case UNDERLYING_TYPE>:
	Remove.
	<case TRAIT_TYPE>: New.
	(tsubst): Likewise.
	(unify): Replace UNDERLYING_TYPE with TRAIT_TYPE.
	(dependent_type_p_r): Likewise.
	* semantics.cc (finish_underlying_type): Don't return
	UNDERLYING_TYPE anymore when processing_template_decl.
	(finish_trait_type): Define.
	* tree.cc (strip_typedefs) <case UNDERLYING_TYPE>: Remove.
	<case TRAIT_TYPE>: New.
	(cp_walk_subtrees): Likewise.
	* typeck.cc (structural_comptypes): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/underlying_type7.C: Adjust expected error message.
	* g++.dg/ext/underlying_type13.C: New test.
	* g++.dg/ext/underlying_type14.C: New test.
---
 gcc/cp/cp-objcp-common.cc                    |  2 +-
 gcc/cp/cp-tree.def                           |  9 ++--
 gcc/cp/cp-tree.h                             | 18 +++++++
 gcc/cp/cxx-pretty-print.cc                   | 53 ++++++++++++++------
 gcc/cp/cxx-pretty-print.h                    |  2 +-
 gcc/cp/error.cc                              | 14 ++----
 gcc/cp/mangle.cc                             |  5 +-
 gcc/cp/module.cc                             | 24 ++++++++-
 gcc/cp/parser.cc                             | 24 ++++-----
 gcc/cp/pt.cc                                 | 29 +++++++----
 gcc/cp/semantics.cc                          | 45 ++++++++++++-----
 gcc/cp/tree.cc                               | 22 ++++++--
 gcc/cp/typeck.cc                             |  7 ++-
 gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C   |  4 +-
 gcc/testsuite/g++.dg/ext/underlying_type13.C |  7 +++
 gcc/testsuite/g++.dg/ext/underlying_type14.C |  8 +++
 gcc/testsuite/g++.dg/ext/underlying_type7.C  |  2 +-
 17 files changed, 197 insertions(+), 78 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/underlying_type13.C
 create mode 100644 gcc/testsuite/g++.dg/ext/underlying_type14.C

diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 64975699351..380f288a7f1 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -518,7 +518,7 @@ cp_common_init_ts (void)
   MARK_TS_TYPE_NON_COMMON (DECLTYPE_TYPE);
   MARK_TS_TYPE_NON_COMMON (TYPENAME_TYPE);
   MARK_TS_TYPE_NON_COMMON (TYPEOF_TYPE);
-  MARK_TS_TYPE_NON_COMMON (UNDERLYING_TYPE);
+  MARK_TS_TYPE_NON_COMMON (TRAIT_TYPE);
   MARK_TS_TYPE_NON_COMMON (BOUND_TEMPLATE_TEMPLATE_PARM);
   MARK_TS_TYPE_NON_COMMON (TEMPLATE_TEMPLATE_PARM);
   MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM);
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index f9cbd339f19..f83b4c54d43 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -444,9 +444,12 @@ DEFTREECODE (BIT_CAST_EXPR, "bit_cast_expr", tcc_expression, 1)
 
 /** C++ extensions. */
 
-/* Represents a trait expression during template expansion.  */
+/* Represents a templated trait that yields an expression.  */
 DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0)
 
+/* Represents a templated trait that yields a type.  */
+DEFTREECODE (TRAIT_TYPE, "trait_type", tcc_type, 0)
+
 /* A lambda expression.  This is a C++0x extension.
    LAMBDA_EXPR_DEFAULT_CAPTURE_MODE is an enum for the default, which may be
    none.
@@ -466,10 +469,6 @@ DEFTREECODE (LAMBDA_EXPR, "lambda_expr", tcc_exceptional, 0)
    DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction.  */
 DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
 
-/* A type designated by `__underlying_type (type)'.
-   UNDERLYING_TYPE_TYPE is the type in question.  */
-DEFTREECODE (UNDERLYING_TYPE, "underlying_type", tcc_type, 0)
-
 /* A type designated by one of the bases type traits.
    BASES_TYPE is the type in question.  */
 DEFTREECODE (BASES, "bases", tcc_type, 0)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 19bbfbc557f..a89baa8d232 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1436,6 +1436,22 @@ struct GTY (()) tree_trait_expr {
   enum cp_trait_kind kind;
 };
 
+/* An INTEGER_CST containing the kind of the trait type NODE.  */
+#define TRAIT_TYPE_KIND_RAW(NODE) \
+  TYPE_VALUES_RAW (TRAIT_TYPE_CHECK (NODE))
+
+/* The kind of the trait type NODE.  */
+#define TRAIT_TYPE_KIND(NODE) \
+  ((enum cp_trait_kind) TREE_INT_CST_LOW (TRAIT_TYPE_KIND_RAW (NODE)))
+
+/* The first argument of the trait type NODE.  */
+#define TRAIT_TYPE_TYPE1(NODE) \
+  TYPE_MIN_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
+
+/* The rest of the arguments of the trait type NODE.  */
+#define TRAIT_TYPE_TYPE2(NODE) \
+  TYPE_MAX_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
+
 /* Identifiers used for lambda types are almost anonymous.  Use this
    spare flag to distinguish them (they also have the anonymous flag).  */
 #define IDENTIFIER_LAMBDA_P(NODE) \
@@ -2225,6 +2241,7 @@ enum languages { lang_c, lang_cplusplus };
    || TREE_CODE (T) == TYPEOF_TYPE			\
    || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM	\
    || TREE_CODE (T) == DECLTYPE_TYPE			\
+   || TREE_CODE (T) == TRAIT_TYPE			\
    || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE)
 
 /* Nonzero if T is a class (or struct or union) type.  Also nonzero
@@ -7731,6 +7748,7 @@ extern tree finish_decltype_type                (tree, bool, tsubst_flags_t);
 extern tree fold_builtin_is_corresponding_member (location_t, int, tree *);
 extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *);
 extern tree finish_trait_expr			(location_t, enum cp_trait_kind, tree, tree);
+extern tree finish_trait_type			(enum cp_trait_kind, tree, tree);
 extern tree build_lambda_expr                   (void);
 extern tree build_lambda_object			(tree);
 extern tree begin_lambda_type                   (tree);
diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index e18143e39a9..928c58e0f67 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -483,7 +483,7 @@ cxx_pretty_printer::primary_expression (tree t)
       break;
 
     case TRAIT_EXPR:
-      pp_cxx_trait_expression (this, t);
+      pp_cxx_trait (this, t);
       break;
 
     case VA_ARG_EXPR:
@@ -1240,7 +1240,7 @@ cxx_pretty_printer::expression (tree t)
       break;
 
     case TRAIT_EXPR:
-      pp_cxx_trait_expression (this, t);
+      pp_cxx_trait (this, t);
       break;
 
     case ATOMIC_CONSTR:
@@ -1385,6 +1385,10 @@ cxx_pretty_printer::simple_type_specifier (tree t)
       pp_cxx_ws_string (this, "std::nullptr_t");
       break;
 
+    case TRAIT_TYPE:
+      pp_cxx_trait (this, t);
+      break;
+
     default:
       c_pretty_printer::simple_type_specifier (t);
       break;
@@ -1876,7 +1880,7 @@ cxx_pretty_printer::type_id (tree t)
     case TEMPLATE_PARM_INDEX:
     case TEMPLATE_DECL:
     case TYPEOF_TYPE:
-    case UNDERLYING_TYPE:
+    case TRAIT_TYPE:
     case DECLTYPE_TYPE:
     case NULLPTR_TYPE:
     case TEMPLATE_ID_EXPR:
@@ -2594,9 +2598,22 @@ pp_cxx_binary_fold_expression (cxx_pretty_printer *pp, tree t)
 }
 
 void
-pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
+pp_cxx_trait (cxx_pretty_printer *pp, tree t)
 {
-  cp_trait_kind kind = TRAIT_EXPR_KIND (t);
+  cp_trait_kind kind;
+  tree type1, type2;
+  if (TREE_CODE (t) == TRAIT_EXPR)
+    {
+      kind = TRAIT_EXPR_KIND (t);
+      type1 = TRAIT_EXPR_TYPE1 (t);
+      type2 = TRAIT_EXPR_TYPE2 (t);
+    }
+  else
+    {
+      kind = TRAIT_TYPE_KIND (t);
+      type1 = TRAIT_TYPE_TYPE1 (t);
+      type2 = TRAIT_TYPE_TYPE2 (t);
+    }
 
   switch (kind)
     {
@@ -2708,23 +2725,29 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       pp_cxx_ws_string (pp, "__reference_converts_from_temporary");
       break;
-
+    case CPTK_UNDERLYING_TYPE:
+      pp_cxx_ws_string (pp, "__underlying_type");
+      break;
     default:
       gcc_unreachable ();
     }
 
   pp_cxx_left_paren (pp);
-  pp->type_id (TRAIT_EXPR_TYPE1 (t));
-
-  if (kind == CPTK_IS_BASE_OF
-      || kind == CPTK_IS_SAME_AS
-      || kind == CPTK_IS_LAYOUT_COMPATIBLE
-      || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
+  pp->type_id (type1);
+  if (type2)
     {
-      pp_cxx_separate_with (pp, ',');
-      pp->type_id (TRAIT_EXPR_TYPE2 (t));
+      if (TREE_CODE (type2) != TREE_LIST)
+	{
+	  pp_cxx_separate_with (pp, ',');
+	  pp->type_id (type2);
+	}
+      else
+	for (tree arg = type2; arg; arg = TREE_CHAIN (arg))
+	  {
+	    pp_cxx_separate_with (pp, ',');
+	    pp->type_id (TREE_VALUE (arg));
+	  }
     }
-
   pp_cxx_right_paren (pp);
 }
 
diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
index 593bd91d4f7..25a2c7c8d4a 100644
--- a/gcc/cp/cxx-pretty-print.h
+++ b/gcc/cp/cxx-pretty-print.h
@@ -90,7 +90,7 @@ void pp_cxx_colon_colon (cxx_pretty_printer *);
 void pp_cxx_separate_with (cxx_pretty_printer *, int);
 
 void pp_cxx_canonical_template_parameter (cxx_pretty_printer *, tree);
-void pp_cxx_trait_expression (cxx_pretty_printer *, tree);
+void pp_cxx_trait (cxx_pretty_printer *, tree);
 void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree);
 void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree);
 void pp_cxx_addressof_expression (cxx_pretty_printer *, tree);
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 0389f35d731..4bf9a83f20b 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -698,12 +698,8 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
       pp_cxx_right_paren (pp);
       break;
 
-    case UNDERLYING_TYPE:
-      pp_cxx_ws_string (pp, "__underlying_type");
-      pp_cxx_whitespace (pp);
-      pp_cxx_left_paren (pp);
-      dump_expr (pp, UNDERLYING_TYPE_TYPE (t), flags & ~TFF_EXPR_IN_PARENS);
-      pp_cxx_right_paren (pp);
+    case TRAIT_TYPE:
+      pp_cxx_trait (pp, t);
       break;
 
     case TYPE_PACK_EXPANSION:
@@ -971,7 +967,7 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, int flags)
     case COMPLEX_TYPE:
     case VECTOR_TYPE:
     case TYPEOF_TYPE:
-    case UNDERLYING_TYPE:
+    case TRAIT_TYPE:
     case DECLTYPE_TYPE:
     case TYPE_PACK_EXPANSION:
     case FIXED_POINT_TYPE:
@@ -1095,7 +1091,7 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags)
     case COMPLEX_TYPE:
     case VECTOR_TYPE:
     case TYPEOF_TYPE:
-    case UNDERLYING_TYPE:
+    case TRAIT_TYPE:
     case DECLTYPE_TYPE:
     case TYPE_PACK_EXPANSION:
     case FIXED_POINT_TYPE:
@@ -2956,7 +2952,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
       break;
 
     case TRAIT_EXPR:
-      pp_cxx_trait_expression (pp, t);
+      pp_cxx_trait (pp, t);
       break;
 
     case VA_ARG_EXPR:
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 00d283fff8c..fc750fc5d8e 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -2389,8 +2389,9 @@ write_type (tree type)
 	      sorry ("mangling %<typeof%>, use %<decltype%> instead");
 	      break;
 
-	    case UNDERLYING_TYPE:
-	      sorry ("mangling %<__underlying_type%>");
+	    case TRAIT_TYPE:
+	      error ("use of built-in trait %qT in function signature; "
+		     "use library traits instead", type);
 	      break;
 
 	    case LANG_TYPE:
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 7496df5e843..25741e5d827 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -8910,7 +8910,6 @@ trees_out::type_node (tree type)
 
     case DECLTYPE_TYPE:
     case TYPEOF_TYPE:
-    case UNDERLYING_TYPE:
     case DEPENDENT_OPERATOR_TYPE:
       tree_node (TYPE_VALUES_RAW (type));
       if (TREE_CODE (type) == DECLTYPE_TYPE)
@@ -8920,6 +8919,12 @@ trees_out::type_node (tree type)
 	  tree_node_bools (type);
       break;
 
+    case TRAIT_TYPE:
+      tree_node (TRAIT_TYPE_KIND_RAW (type));
+      tree_node (TRAIT_TYPE_TYPE1 (type));
+      tree_node (TRAIT_TYPE_TYPE2 (type));
+      break;
+
     case TYPE_ARGUMENT_PACK:
       /* No additional data.  */
       break;
@@ -9434,7 +9439,6 @@ trees_in::tree_node (bool is_use)
 
 	  case DECLTYPE_TYPE:
 	  case TYPEOF_TYPE:
-	  case UNDERLYING_TYPE:
 	  case DEPENDENT_OPERATOR_TYPE:
 	    {
 	      tree expr = tree_node ();
@@ -9449,6 +9453,22 @@ trees_in::tree_node (bool is_use)
 	    }
 	    break;
 
+	  case TRAIT_TYPE:
+	    {
+	      tree kind = tree_node ();
+	      tree type1 = tree_node ();
+	      tree type2 = tree_node ();
+	      if (!get_overrun ())
+		{
+		  res = cxx_make_type (TRAIT_TYPE);
+		  TRAIT_TYPE_KIND_RAW (res) = kind;
+		  TRAIT_TYPE_TYPE1 (res) = type1;
+		  TRAIT_TYPE_TYPE2 (res) = type2;
+		  SET_TYPE_STRUCTURAL_EQUALITY (res);
+		}
+	    }
+	    break;
+
 	  case TYPE_ARGUMENT_PACK:
 	    if (!get_overrun ())
 	      {
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index d501178634a..9f5e2c292b3 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2783,7 +2783,7 @@ static void cp_parser_late_parsing_default_args
   (cp_parser *, tree);
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
-static cp_expr cp_parser_trait_expr
+static cp_expr cp_parser_trait
   (cp_parser *, enum rid);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
@@ -5928,7 +5928,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_IS_NOTHROW_CONVERTIBLE:
 	case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
 	case RID_REF_CONVERTS_FROM_TEMPORARY:
-	  return cp_parser_trait_expr (parser, token->keyword);
+	  return cp_parser_trait (parser, token->keyword);
 
 	// C++ concepts
 	case RID_REQUIRES:
@@ -10882,18 +10882,16 @@ cp_parser_builtin_offsetof (cp_parser *parser)
   return expr;
 }
 
-/* Parse a trait expression.
-
-   Returns a representation of the expression, the underlying type
-   of the type at issue when KEYWORD is RID_UNDERLYING_TYPE.  */
+/* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, enum rid keyword)
 {
   cp_trait_kind kind;
   tree type1, type2 = NULL_TREE;
   bool binary = false;
   bool variadic = false;
+  bool type = false;
 
   switch (keyword)
     {
@@ -10989,6 +10987,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
       break;
     case RID_UNDERLYING_TYPE:
       kind = CPTK_UNDERLYING_TYPE;
+      type = true;
       break;
     case RID_BASES:
       kind = CPTK_BASES;
@@ -11092,14 +11091,15 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
      the trait expr now or saving it for template instantiation.  */
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return cp_expr (finish_underlying_type (type1), trait_loc);
     case CPTK_BASES:
       return cp_expr (finish_bases (type1, false), trait_loc);
     case CPTK_DIRECT_BASES:
       return cp_expr (finish_bases (type1, true), trait_loc);
     default:
-      return finish_trait_expr (trait_loc, kind, type1, type2);
+      if (type)
+	return finish_trait_type (kind, type1, type2);
+      else
+	return finish_trait_expr (trait_loc, kind, type1, type2);
     }
 }
 
@@ -19867,7 +19867,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       return type;
 
     case RID_UNDERLYING_TYPE:
-      type = cp_parser_trait_expr (parser, RID_UNDERLYING_TYPE);
+      type = cp_parser_trait (parser, token->keyword);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
@@ -19877,7 +19877,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
     case RID_BASES:
     case RID_DIRECT_BASES:
-      type = cp_parser_trait_expr (parser, token->keyword);
+      type = cp_parser_trait (parser, token->keyword);
       if (decl_specs)
        cp_parser_set_decl_spec_type (decl_specs, type,
                                      token,
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2d83dfd6954..cf8d8d50d63 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10618,7 +10618,6 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
 
     case TYPEOF_TYPE:
     case DECLTYPE_TYPE:
-    case UNDERLYING_TYPE:
       if (pfd->include_nondeduced_p
 	  && for_each_template_parm (TYPE_VALUES_RAW (t), fn, data,
 				     pfd->visited,
@@ -10628,6 +10627,15 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
       *walk_subtrees = false;
       break;
 
+    case TRAIT_TYPE:
+      if (pfd->include_nondeduced_p)
+	{
+	  WALK_SUBTREE (TRAIT_TYPE_TYPE1 (t));
+	  WALK_SUBTREE (TRAIT_TYPE_TYPE2 (t));
+	}
+      *walk_subtrees = false;
+      break;
+
     case FUNCTION_DECL:
     case VAR_DECL:
       if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
@@ -16514,11 +16522,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 					complain | tf_ignore_bad_quals);
       }
 
-    case UNDERLYING_TYPE:
+    case TRAIT_TYPE:
       {
-	tree type = tsubst (UNDERLYING_TYPE_TYPE (t), args,
-			    complain, in_decl);
-	return finish_underlying_type (type);
+	tree type1 = tsubst (TRAIT_TYPE_TYPE1 (t), args, complain, in_decl);
+	tree type2 = tsubst (TRAIT_TYPE_TYPE2 (t), args, complain, in_decl);
+	type = finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2);
+	return cp_build_qualified_type (type,
+					cp_type_quals (t) | cp_type_quals (type),
+					complain | tf_ignore_bad_quals);
       }
 
     case TYPE_ARGUMENT_PACK:
@@ -24928,9 +24939,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 
     case TYPEOF_TYPE:
     case DECLTYPE_TYPE:
-    case UNDERLYING_TYPE:
+    case TRAIT_TYPE:
       /* Cannot deduce anything from TYPEOF_TYPE, DECLTYPE_TYPE,
-	 or UNDERLYING_TYPE nodes.  */
+	 or TRAIT_TYPE nodes.  */
       return unify_success (explain_p);
 
     case ERROR_MARK:
@@ -27505,12 +27516,12 @@ dependent_type_p_r (tree type)
 	       (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)))))
     return true;
 
-  /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and UNDERLYING_TYPEs are
+  /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and TRAIT_TYPEs are
      dependent; if the argument of the `typeof' expression is not
      type-dependent, then it should already been have resolved.  */
   if (TREE_CODE (type) == TYPEOF_TYPE
       || TREE_CODE (type) == DECLTYPE_TYPE
-      || TREE_CODE (type) == UNDERLYING_TYPE)
+      || TREE_CODE (type) == TRAIT_TYPE)
     return true;
 
   /* A template argument pack is dependent if any of its packed
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e8cd50558d6..73144ef04b8 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -4397,17 +4397,6 @@ finish_typeof (tree expr)
 tree
 finish_underlying_type (tree type)
 {
-  tree underlying_type;
-
-  if (processing_template_decl)
-    {
-      underlying_type = cxx_make_type (UNDERLYING_TYPE);
-      UNDERLYING_TYPE_TYPE (underlying_type) = type;
-      SET_TYPE_STRUCTURAL_EQUALITY (underlying_type);
-
-      return underlying_type;
-    }
-
   if (!complete_type_or_else (type, NULL_TREE))
     return error_mark_node;
 
@@ -4417,7 +4406,7 @@ finish_underlying_type (tree type)
       return error_mark_node;
     }
 
-  underlying_type = ENUM_UNDERLYING_TYPE (type);
+  tree underlying_type = ENUM_UNDERLYING_TYPE (type);
 
   /* Fixup necessary in this case because ENUM_UNDERLYING_TYPE
      includes TYPE_MIN_VALUE and TYPE_MAX_VALUE information.
@@ -12224,6 +12213,38 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
   return maybe_wrap_with_location (val, loc);
 }
 
+/* Process a trait type.  */
+
+tree
+finish_trait_type (cp_trait_kind kind, tree type1, tree type2)
+{
+  if (type1 == error_mark_node
+      || type2 == error_mark_node)
+    return error_mark_node;
+
+  if (processing_template_decl)
+    {
+      tree type = cxx_make_type (TRAIT_TYPE);
+      TRAIT_TYPE_TYPE1 (type) = type1;
+      TRAIT_TYPE_TYPE2 (type) = type2;
+      TRAIT_TYPE_KIND_RAW (type) = build_int_cstu (integer_type_node, kind);
+      /* These traits are intended to be used in the definition of the ::type
+	 member of the corresponding standard library type trait (and thus won't
+	 appear directly in template signatures), so structural equality should
+	 suffice.  */
+      SET_TYPE_STRUCTURAL_EQUALITY (type);
+      return type;
+    }
+
+  switch (kind)
+    {
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Do-nothing variants of functions to handle pragma FLOAT_CONST_DECIMAL64,
    which is ignored for C++.  */
 
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index ea4dfc651bb..aa9c1b7d8f9 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -1776,10 +1776,17 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
 		   DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t),
 		   tf_none));
       break;
-    case UNDERLYING_TYPE:
-      type = strip_typedefs (UNDERLYING_TYPE_TYPE (t),
-			     remove_attributes, flags);
-      result = finish_underlying_type (type);
+    case TRAIT_TYPE:
+      {
+	tree type1 = strip_typedefs (TRAIT_TYPE_TYPE1 (t),
+				     remove_attributes, flags);
+	tree type2 = strip_typedefs (TRAIT_TYPE_TYPE2 (t),
+				     remove_attributes, flags);
+	if (type1 == TRAIT_TYPE_TYPE1 (t) && type2 == TRAIT_TYPE_TYPE2 (t))
+	  result = NULL_TREE;
+	else
+	  result = finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2);
+      }
       break;
     case TYPE_PACK_EXPANSION:
       {
@@ -5383,7 +5390,6 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
     case UNBOUND_CLASS_TEMPLATE:
     case TEMPLATE_PARM_INDEX:
     case TYPEOF_TYPE:
-    case UNDERLYING_TYPE:
       /* None of these have subtrees other than those already walked
 	 above.  */
       *walk_subtrees_p = 0;
@@ -5472,6 +5478,12 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
       *walk_subtrees_p = 0;
       break;
 
+    case TRAIT_TYPE:
+      WALK_SUBTREE (TRAIT_TYPE_TYPE1 (*tp));
+      WALK_SUBTREE (TRAIT_TYPE_TYPE2 (*tp));
+      *walk_subtrees_p = 0;
+      break;
+
     case DECLTYPE_TYPE:
       ++cp_unevaluated_operand;
       /* We can't use WALK_SUBTREE here because of the goto.  */
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 5f16c4d2426..cecf825f5e6 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -1621,8 +1621,11 @@ structural_comptypes (tree t1, tree t2, int strict)
         return false;
       break;
 
-    case UNDERLYING_TYPE:
-      if (!same_type_p (UNDERLYING_TYPE_TYPE (t1), UNDERLYING_TYPE_TYPE (t2)))
+    case TRAIT_TYPE:
+      if (TRAIT_TYPE_KIND (t1) != TRAIT_TYPE_KIND (t2))
+	return false;
+      if (!same_type_p (TRAIT_TYPE_TYPE1 (t1), TRAIT_TYPE_TYPE1 (t2))
+	  || !cp_tree_equal (TRAIT_TYPE_TYPE2 (t1), TRAIT_TYPE_TYPE2 (t2)))
 	return false;
       break;
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
index 1f5e94f6d83..50946576f74 100644
--- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
@@ -5,7 +5,7 @@ template<typename>
 struct A {};
 
 template<typename T>
-using B = A<__underlying_type(T) [[gnu::aligned(4)]]>; // { dg-warning "ignoring attributes on template argument" }
+using B = A<__underlying_type(T) [[gnu::aligned(4)]]>; // { dg-warning "ignoring attributes applied to dependent type" }
 
 template<typename T>
-using B = A<__underlying_type(T) [[gnu::packed]]>; // { dg-warning "ignoring attributes on template argument" }
+using B = A<__underlying_type(T) [[gnu::packed]]>; // { dg-warning "ignoring attributes applied to dependent type" }
diff --git a/gcc/testsuite/g++.dg/ext/underlying_type13.C b/gcc/testsuite/g++.dg/ext/underlying_type13.C
new file mode 100644
index 00000000000..c53da11eb8a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/underlying_type13.C
@@ -0,0 +1,7 @@
+// Verify when substituting __underlying_type its cv-quals are carried over.
+// { dg-do compile { target c++11 } }
+
+template<class T> using const_underlying_type_t = const __underlying_type(T);
+enum A { a };
+using type = const_underlying_type_t<A>;
+using type = const __underlying_type(A);
diff --git a/gcc/testsuite/g++.dg/ext/underlying_type14.C b/gcc/testsuite/g++.dg/ext/underlying_type14.C
new file mode 100644
index 00000000000..91840b2015c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/underlying_type14.C
@@ -0,0 +1,8 @@
+// Verify pretty-printing when nesting a builtin trait.
+
+template<class T> void f(__underlying_type(__underlying_type(T))); // { dg-error "" }
+// { dg-message "__underlying_type\\(__underlying_type\\(T\\)\\)\\)" "" { target *-*-* } .-1 }
+
+int main() {
+  f<int>(0); // { dg-error "no match" }
+}
diff --git a/gcc/testsuite/g++.dg/ext/underlying_type7.C b/gcc/testsuite/g++.dg/ext/underlying_type7.C
index 2d6ec51792c..137a0f08547 100644
--- a/gcc/testsuite/g++.dg/ext/underlying_type7.C
+++ b/gcc/testsuite/g++.dg/ext/underlying_type7.C
@@ -9,7 +9,7 @@ enum class E6 : long { c = __LONG_MAX__ };
 
 template<typename T>
   void
-  test(T, __underlying_type(T)) // { dg-message "sorry, unimplemented: mangling" }
+  test(T, __underlying_type(T)) // { dg-error "built-in trait '__underlying_type\\(T\\)'" }
   { }
 
 int main()
  
Jason Merrill Sept. 28, 2022, 6:49 p.m. UTC | #3
On 9/28/22 12:36, Patrick Palka wrote:
> On Tue, 27 Sep 2022, Jason Merrill wrote:
> 
>> On 9/27/22 15:50, Patrick Palka wrote:
>>> We already have generic support for predicate-like traits that yield a
>>> boolean via TRAIT_EXPR, but we lack the same support for transform-like
>>> traits that yield a type.  Such support would be useful for implementing
>>> efficient built-ins for std::decay and std::remove_cvref and other
>>> conceptually simple type traits that are otherwise relatively expensive
>>> to implement.
>>>
>>> This patch implements a generic TRAIT_TYPE type and replaces the
>>> existing hardcoded UNDERLYING_TYPE type to use TRAIT_TYPE instead.
>>
>> Sounds good, perhaps we also want to convert BASES to e.g. TRAIT_TYPE_PACK at
>> some point...
> 
> *nod*
> 
>>
>>> gcc/cp/ChangeLog:
>>>
>>> 	* cp-objcp-common.cc (cp_common_init_ts): Replace
>>> 	UNDERLYING_TYPE with TRAIT_TYPE.
>>> 	* cp-tree.def (TRAIT_TYPE): Define.
>>> 	(UNDERLYING_TYPE): Remove.
>>> 	* cp-tree.h (TRAIT_TYPE_KIND_RAW): Define.
>>> 	(TRAIT_TYPE_KIND): Define.
>>> 	(TRAIT_TYPE_TYPE1): Define.
>>> 	(TRAIT_TYPE_TYPE2): Define.
>>> 	(WILDCARD_TYPE_P): Return true for TRAIT_TYPE.
>>> 	(finish_trait_type): Declare.
>>> 	* cxx-pretty-print.cc (cxx_pretty_printer::primary_expression):
>>> 	Adjust after renaming pp_cxx_trait_expression.
>>> 	(cxx_pretty_printer::type_id): Replace UNDERLYING_TYPE with
>>> 	TRAIT_TYPE.
>>> 	(pp_cxx_trait_expression): Rename to ...
>>> 	(pp_cxx_trait): ... this.  Handle TRAIT_TYPE as well.  Correct
>>> 	pretty printing of the trailing arguments.
>>> 	* cxx-pretty-print.h (pp_cxx_trait_expression): Rename to ...
>>> 	(pp_cxx_trait_type): ... this.
>>> 	* error.cc (dump_type) <case UNDERLYING_TYPE>: Remove.
>>> 	<case TRAIT_TYPE>: New.
>>> 	(dump_type_prefix): Replace UNDERLYING_WITH with TRAIT_TYPE.
>>> 	(dump_type_suffix): Likewise.
>>> 	* mangle.cc (write_type) <case UNDERLYING_TYPE>: Remove.
>>> 	<case TRAIT_TYPE>: New.
>>> 	* module.cc (trees_out::type_node) <case UNDERLYING_TYPE>:
>>> 	Remove.
>>> 	<case TRAIT_TYPE>: New.
>>> 	(trees_in::tree_node): Likewise.
>>> 	* parser.cc (cp_parser_primary_expression): Adjust after
>>> 	renaming cp_parser_trait_expr.
>>> 	(cp_parser_trait_expr): Rename to ...
>>> 	(cp_parser_trait): ... this.  Call finish_trait_type for traits
>>> 	that yield a type.
>>> 	(cp_parser_simple_type_specifier): Adjust after renaming
>>> 	cp_parser_trait_expr.
>>> 	* pt.cc (for_each_template_parm_r) <case UNDERLYING_TYPE>:
>>> 	Remove.
>>> 	<case TRAIT_TYPE>: New.
>>> 	(tsubst): Likewise.
>>> 	(unify): Replace UNDERLYING_TYPE with TRAIT_TYPE.
>>> 	(dependent_type_p_r): Likewise.
>>> 	* semantics.cc (finish_underlying_type): Don't return
>>> 	UNDERLYING_TYPE anymore when processing_template_decl.
>>> 	(finish_trait_type): Define.
>>> 	* tree.cc (strip_typedefs) <case UNDERLYING_TYPE>: Remove.
>>> 	<case TRAIT_TYPE>: New.
>>> 	(cp_walk_subtrees): Likewise.
>>> 	* typeck.cc (structural_comptypes): Likewise.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> 	* g++.dg/ext/underlying_type7.C: Adjust expected error message.
>>> ---
>>>    gcc/cp/cp-objcp-common.cc                   |  2 +-
>>>    gcc/cp/cp-tree.def                          |  9 ++--
>>>    gcc/cp/cp-tree.h                            | 18 ++++++++
>>>    gcc/cp/cxx-pretty-print.cc                  | 49 ++++++++++++++-------
>>>    gcc/cp/cxx-pretty-print.h                   |  2 +-
>>>    gcc/cp/error.cc                             | 14 +++---
>>>    gcc/cp/mangle.cc                            |  5 ++-
>>>    gcc/cp/module.cc                            | 24 +++++++++-
>>>    gcc/cp/parser.cc                            | 24 +++++-----
>>>    gcc/cp/pt.cc                                | 26 +++++++----
>>>    gcc/cp/semantics.cc                         | 41 ++++++++++++-----
>>>    gcc/cp/tree.cc                              | 22 ++++++---
>>>    gcc/cp/typeck.cc                            |  7 ++-
>>>    gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C  |  4 +-
>>>    gcc/testsuite/g++.dg/ext/underlying_type7.C |  2 +-
>>>    15 files changed, 171 insertions(+), 78 deletions(-)
>>>
>>> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
>>> index 64975699351..380f288a7f1 100644
>>> --- a/gcc/cp/cp-objcp-common.cc
>>> +++ b/gcc/cp/cp-objcp-common.cc
>>> @@ -518,7 +518,7 @@ cp_common_init_ts (void)
>>>      MARK_TS_TYPE_NON_COMMON (DECLTYPE_TYPE);
>>>      MARK_TS_TYPE_NON_COMMON (TYPENAME_TYPE);
>>>      MARK_TS_TYPE_NON_COMMON (TYPEOF_TYPE);
>>> -  MARK_TS_TYPE_NON_COMMON (UNDERLYING_TYPE);
>>> +  MARK_TS_TYPE_NON_COMMON (TRAIT_TYPE);
>>>      MARK_TS_TYPE_NON_COMMON (BOUND_TEMPLATE_TEMPLATE_PARM);
>>>      MARK_TS_TYPE_NON_COMMON (TEMPLATE_TEMPLATE_PARM);
>>>      MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM);
>>> diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
>>> index f9cbd339f19..f83b4c54d43 100644
>>> --- a/gcc/cp/cp-tree.def
>>> +++ b/gcc/cp/cp-tree.def
>>> @@ -444,9 +444,12 @@ DEFTREECODE (BIT_CAST_EXPR, "bit_cast_expr",
>>> tcc_expression, 1)
>>>      /** C++ extensions. */
>>>    -/* Represents a trait expression during template expansion.  */
>>> +/* Represents a templated trait that yields an expression.  */
>>>    DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0)
>>>    +/* Represents a templated trait that yields a type.  */
>>> +DEFTREECODE (TRAIT_TYPE, "trait_type", tcc_type, 0)
>>> +
>>>    /* A lambda expression.  This is a C++0x extension.
>>>       LAMBDA_EXPR_DEFAULT_CAPTURE_MODE is an enum for the default, which may
>>> be
>>>       none.
>>> @@ -466,10 +469,6 @@ DEFTREECODE (LAMBDA_EXPR, "lambda_expr",
>>> tcc_exceptional, 0)
>>>       DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction.
>>> */
>>>    DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
>>>    -/* A type designated by `__underlying_type (type)'.
>>> -   UNDERLYING_TYPE_TYPE is the type in question.  */
>>> -DEFTREECODE (UNDERLYING_TYPE, "underlying_type", tcc_type, 0)
>>> -
>>>    /* A type designated by one of the bases type traits.
>>>       BASES_TYPE is the type in question.  */
>>>    DEFTREECODE (BASES, "bases", tcc_type, 0)
>>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
>>> index 99b486b8002..c9adf1b3822 100644
>>> --- a/gcc/cp/cp-tree.h
>>> +++ b/gcc/cp/cp-tree.h
>>> @@ -1436,6 +1436,22 @@ struct GTY (()) tree_trait_expr {
>>>      enum cp_trait_kind kind;
>>>    };
>>>    +/* An INTEGER_CST containing the kind of the trait type NODE.  */
>>> +#define TRAIT_TYPE_KIND_RAW(NODE) \
>>> +  TYPE_VALUES_RAW (TRAIT_TYPE_CHECK (NODE))
>>> +
>>> +/* The kind of the trait type NODE.  */
>>> +#define TRAIT_TYPE_KIND(NODE) \
>>> +  ((enum cp_trait_kind) TREE_INT_CST_LOW (TRAIT_TYPE_KIND_RAW (NODE)))
>>> +
>>> +/* The first argument of the trait type NODE.  */
>>> +#define TRAIT_TYPE_TYPE1(NODE) \
>>> +  TYPE_MIN_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
>>> +
>>> +/* The rest of the arguments of the trait type NODE.  */
>>> +#define TRAIT_TYPE_TYPE2(NODE) \
>>> +  TYPE_MAX_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
>>
>> Can we also store the location of the trait use?
> 
> Hmm, I suppose we could create a TYPE_DECL for each use and store it
> there, but I'm not really sure how we'd use this location?  Presumably
> for diagnostics, but I can't come up with an example.
> 
> FWIW I think currently TYPENAME_TYPE is the only "non-declared" type that
> has a TYPE_DECL (and location info).  DECLTYPE_TYPE, TYPE_PACK_EXPANSION,
> etc don't have TYPE_DECL (or location info).  I wonder why only
> TYPENAME_TYPE has one?

Pretty sure TYPENAME_TYPE was the first one added, I guess the later 
ones just didn't bother because as you mention, it wouldn't actually be 
used: looks like all the occurrences of "location_of (type)" are dealing 
with class declarations.

>>> +
>>>    /* Identifiers used for lambda types are almost anonymous.  Use this
>>>       spare flag to distinguish them (they also have the anonymous flag).  */
>>>    #define IDENTIFIER_LAMBDA_P(NODE) \
>>> @@ -2225,6 +2241,7 @@ enum languages { lang_c, lang_cplusplus };
>>>       || TREE_CODE (T) == TYPEOF_TYPE			\
>>>       || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM	\
>>>       || TREE_CODE (T) == DECLTYPE_TYPE			\
>>> +   || TREE_CODE (T) == TRAIT_TYPE			\
>>>       || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE)
>>>      /* Nonzero if T is a class (or struct or union) type.  Also nonzero
>>> @@ -7730,6 +7747,7 @@ extern tree finish_decltype_type                (tree,
>>> bool, tsubst_flags_t);
>>>    extern tree fold_builtin_is_corresponding_member (location_t, int, tree
>>> *);
>>>    extern tree fold_builtin_is_pointer_inverconvertible_with_class
>>> (location_t, int, tree *);
>>>    extern tree finish_trait_expr			(location_t, enum
>>> cp_trait_kind, tree, tree);
>>> +extern tree finish_trait_type			(enum cp_trait_kind,
>>> tree, tree);
>>>    extern tree build_lambda_expr                   (void);
>>>    extern tree build_lambda_object			(tree);
>>>    extern tree begin_lambda_type                   (tree);
>>> diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
>>> index e18143e39a9..d484019a539 100644
>>> --- a/gcc/cp/cxx-pretty-print.cc
>>> +++ b/gcc/cp/cxx-pretty-print.cc
>>> @@ -483,7 +483,7 @@ cxx_pretty_printer::primary_expression (tree t)
>>>          break;
>>>          case TRAIT_EXPR:
>>> -      pp_cxx_trait_expression (this, t);
>>> +      pp_cxx_trait (this, t);
>>>          break;
>>>          case VA_ARG_EXPR:
>>> @@ -1240,7 +1240,7 @@ cxx_pretty_printer::expression (tree t)
>>>          break;
>>>          case TRAIT_EXPR:
>>> -      pp_cxx_trait_expression (this, t);
>>> +      pp_cxx_trait (this, t);
>>>          break;
>>>          case ATOMIC_CONSTR:
>>> @@ -1876,7 +1876,7 @@ cxx_pretty_printer::type_id (tree t)
>>>        case TEMPLATE_PARM_INDEX:
>>>        case TEMPLATE_DECL:
>>>        case TYPEOF_TYPE:
>>> -    case UNDERLYING_TYPE:
>>> +    case TRAIT_TYPE:
>>
>> Does this ever end up calling pp_cxx_trait?  Is this code even reachable?  It
>> looks like we were already missing support for UNDERLYING_TYPE in
>> cxx_pretty_printer::simple_type_specifier.
> 
> Looks like it's reachable at least through pp_cxx_trait (which calls
> type_id on each of the trait's arguments), so e.g. when pretty printing
> __remove_cv(__remove_cv(T)) we currently get the "unhandled tree code"
> fallback for the inner trait.  I fixed this in v2 below by adding support
> for UNDERLYING_TYPE in simple_type_specifier and added a testcase.
> 
>>
>>>        case DECLTYPE_TYPE:
>>>        case NULLPTR_TYPE:
>>>        case TEMPLATE_ID_EXPR:
>>> @@ -2594,9 +2594,22 @@ pp_cxx_binary_fold_expression (cxx_pretty_printer
>>> *pp, tree t)
>>>    }
>>>      void
>>> -pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
>>> +pp_cxx_trait (cxx_pretty_printer *pp, tree t)
>>>    {
>>> -  cp_trait_kind kind = TRAIT_EXPR_KIND (t);
>>> +  cp_trait_kind kind;
>>> +  tree type1, type2;
>>> +  if (TREE_CODE (t) == TRAIT_EXPR)
>>> +    {
>>> +      kind = TRAIT_EXPR_KIND (t);
>>> +      type1 = TRAIT_EXPR_TYPE1 (t);
>>> +      type2 = TRAIT_EXPR_TYPE2 (t);
>>> +    }
>>> +  else
>>> +    {
>>> +      kind = TRAIT_TYPE_KIND (t);
>>> +      type1 = TRAIT_TYPE_TYPE1 (t);
>>> +      type2 = TRAIT_TYPE_TYPE2 (t);
>>> +    }
>>>        switch (kind)
>>>        {
>>> @@ -2708,23 +2721,29 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp,
>>> tree t)
>>>        case CPTK_REF_CONVERTS_FROM_TEMPORARY:
>>>          pp_cxx_ws_string (pp, "__reference_converts_from_temporary");
>>>          break;
>>> -
>>> +    case CPTK_UNDERLYING_TYPE:
>>> +      pp_cxx_ws_string (pp, "__underlying_type");
>>> +      break;
>>>        default:
>>>          gcc_unreachable ();
>>>        }
>>>        pp_cxx_left_paren (pp);
>>> -  pp->type_id (TRAIT_EXPR_TYPE1 (t));
>>> -
>>> -  if (kind == CPTK_IS_BASE_OF
>>> -      || kind == CPTK_IS_SAME_AS
>>> -      || kind == CPTK_IS_LAYOUT_COMPATIBLE
>>> -      || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
>>> +  pp->type_id (type1);
>>> +  if (type2)
>>>        {
>>> -      pp_cxx_separate_with (pp, ',');
>>> -      pp->type_id (TRAIT_EXPR_TYPE2 (t));
>>> +      if (TREE_CODE (type2) != TREE_LIST)
>>> +	{
>>> +	  pp_cxx_separate_with (pp, ',');
>>> +	  pp->type_id (type2);
>>> +	}
>>> +      else
>>> +	for (tree arg = type2; arg; arg = TREE_CHAIN (arg))
>>> +	  {
>>> +	    pp_cxx_separate_with (pp, ',');
>>> +	    pp->type_id (TREE_VALUE (arg));
>>> +	  }
>>>        }
>>> -
>>>      pp_cxx_right_paren (pp);
>>>    }
>>>    diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
>>> index 593bd91d4f7..25a2c7c8d4a 100644
>>> --- a/gcc/cp/cxx-pretty-print.h
>>> +++ b/gcc/cp/cxx-pretty-print.h
>>> @@ -90,7 +90,7 @@ void pp_cxx_colon_colon (cxx_pretty_printer *);
>>>    void pp_cxx_separate_with (cxx_pretty_printer *, int);
>>>      void pp_cxx_canonical_template_parameter (cxx_pretty_printer *, tree);
>>> -void pp_cxx_trait_expression (cxx_pretty_printer *, tree);
>>> +void pp_cxx_trait (cxx_pretty_printer *, tree);
>>>    void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree);
>>>    void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree);
>>>    void pp_cxx_addressof_expression (cxx_pretty_printer *, tree);
>>> diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
>>> index 0389f35d731..4bf9a83f20b 100644
>>> --- a/gcc/cp/error.cc
>>> +++ b/gcc/cp/error.cc
>>> @@ -698,12 +698,8 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
>>>          pp_cxx_right_paren (pp);
>>>          break;
>>>    -    case UNDERLYING_TYPE:
>>> -      pp_cxx_ws_string (pp, "__underlying_type");
>>> -      pp_cxx_whitespace (pp);
>>> -      pp_cxx_left_paren (pp);
>>> -      dump_expr (pp, UNDERLYING_TYPE_TYPE (t), flags &
>>> ~TFF_EXPR_IN_PARENS);
>>> -      pp_cxx_right_paren (pp);
>>> +    case TRAIT_TYPE:
>>> +      pp_cxx_trait (pp, t);
>>>          break;
>>>          case TYPE_PACK_EXPANSION:
>>> @@ -971,7 +967,7 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, int
>>> flags)
>>>        case COMPLEX_TYPE:
>>>        case VECTOR_TYPE:
>>>        case TYPEOF_TYPE:
>>> -    case UNDERLYING_TYPE:
>>> +    case TRAIT_TYPE:
>>>        case DECLTYPE_TYPE:
>>>        case TYPE_PACK_EXPANSION:
>>>        case FIXED_POINT_TYPE:
>>> @@ -1095,7 +1091,7 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int
>>> flags)
>>>        case COMPLEX_TYPE:
>>>        case VECTOR_TYPE:
>>>        case TYPEOF_TYPE:
>>> -    case UNDERLYING_TYPE:
>>> +    case TRAIT_TYPE:
>>>        case DECLTYPE_TYPE:
>>>        case TYPE_PACK_EXPANSION:
>>>        case FIXED_POINT_TYPE:
>>> @@ -2956,7 +2952,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
>>>          break;
>>>          case TRAIT_EXPR:
>>> -      pp_cxx_trait_expression (pp, t);
>>> +      pp_cxx_trait (pp, t);
>>>          break;
>>>          case VA_ARG_EXPR:
>>> diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
>>> index 00d283fff8c..fc750fc5d8e 100644
>>> --- a/gcc/cp/mangle.cc
>>> +++ b/gcc/cp/mangle.cc
>>> @@ -2389,8 +2389,9 @@ write_type (tree type)
>>>    	      sorry ("mangling %<typeof%>, use %<decltype%> instead");
>>>    	      break;
>>>    -	    case UNDERLYING_TYPE:
>>> -	      sorry ("mangling %<__underlying_type%>");
>>> +	    case TRAIT_TYPE:
>>> +	      error ("use of built-in trait %qT in function signature; "
>>> +		     "use library traits instead", type);
>>>    	      break;
>>>      	    case LANG_TYPE:
>>> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
>>> index 7496df5e843..25741e5d827 100644
>>> --- a/gcc/cp/module.cc
>>> +++ b/gcc/cp/module.cc
>>> @@ -8910,7 +8910,6 @@ trees_out::type_node (tree type)
>>>          case DECLTYPE_TYPE:
>>>        case TYPEOF_TYPE:
>>> -    case UNDERLYING_TYPE:
>>>        case DEPENDENT_OPERATOR_TYPE:
>>>          tree_node (TYPE_VALUES_RAW (type));
>>>          if (TREE_CODE (type) == DECLTYPE_TYPE)
>>> @@ -8920,6 +8919,12 @@ trees_out::type_node (tree type)
>>>    	  tree_node_bools (type);
>>>          break;
>>>    +    case TRAIT_TYPE:
>>> +      tree_node (TRAIT_TYPE_KIND_RAW (type));
>>> +      tree_node (TRAIT_TYPE_TYPE1 (type));
>>> +      tree_node (TRAIT_TYPE_TYPE2 (type));
>>> +      break;
>>> +
>>>        case TYPE_ARGUMENT_PACK:
>>>          /* No additional data.  */
>>>          break;
>>> @@ -9434,7 +9439,6 @@ trees_in::tree_node (bool is_use)
>>>      	  case DECLTYPE_TYPE:
>>>    	  case TYPEOF_TYPE:
>>> -	  case UNDERLYING_TYPE:
>>>    	  case DEPENDENT_OPERATOR_TYPE:
>>>    	    {
>>>    	      tree expr = tree_node ();
>>> @@ -9449,6 +9453,22 @@ trees_in::tree_node (bool is_use)
>>>    	    }
>>>    	    break;
>>>    +	  case TRAIT_TYPE:
>>> +	    {
>>> +	      tree kind = tree_node ();
>>> +	      tree type1 = tree_node ();
>>> +	      tree type2 = tree_node ();
>>> +	      if (!get_overrun ())
>>> +		{
>>> +		  res = cxx_make_type (TRAIT_TYPE);
>>> +		  TRAIT_TYPE_KIND_RAW (res) = kind;
>>> +		  TRAIT_TYPE_TYPE1 (res) = type1;
>>> +		  TRAIT_TYPE_TYPE2 (res) = type2;
>>> +		  SET_TYPE_STRUCTURAL_EQUALITY (res);
>>
>> This needs a rationale for structural equality rather than canonicalization.
> 
> Fixed in v2.  I suppose we can get away with structural equality given
> the intended use of these traits is to implement the standard library
> traits.
> 
> Also in v2, make sure to propagate the cv-quals of TRAIT_TYPE during
> substitution.

OK.

> -- >8 --
> 
> Subject: [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR
> 
> gcc/cp/ChangeLog:
> 
> 	* cp-objcp-common.cc (cp_common_init_ts): Replace
> 	UNDERLYING_TYPE with TRAIT_TYPE.
> 	* cp-tree.def (TRAIT_TYPE): Define.
> 	(UNDERLYING_TYPE): Remove.
> 	* cp-tree.h (TRAIT_TYPE_KIND_RAW): Define.
> 	(TRAIT_TYPE_KIND): Define.
> 	(TRAIT_TYPE_TYPE1): Define.
> 	(TRAIT_TYPE_TYPE2): Define.
> 	(WILDCARD_TYPE_P): Return true for TRAIT_TYPE.
> 	(finish_trait_type): Declare.
> 	* cxx-pretty-print.cc (cxx_pretty_printer::primary_expression):
> 	Adjust after renaming pp_cxx_trait_expression.
> 	(cxx_pretty_printer::simple_type_specifier) <case TRAIT_TYPE>:
> 	New.
> 	(cxx_pretty_printer::type_id): Replace UNDERLYING_TYPE with
> 	TRAIT_TYPE.
> 	(pp_cxx_trait_expression): Rename to ...
> 	(pp_cxx_trait): ... this.  Handle TRAIT_TYPE as well.  Correct
> 	pretty printing of the trailing arguments.
> 	* cxx-pretty-print.h (pp_cxx_trait_expression): Rename to ...
> 	(pp_cxx_trait_type): ... this.
> 	* error.cc (dump_type) <case UNDERLYING_TYPE>: Remove.
> 	<case TRAIT_TYPE>: New.
> 	(dump_type_prefix): Replace UNDERLYING_WITH with TRAIT_TYPE.
> 	(dump_type_suffix): Likewise.
> 	* mangle.cc (write_type) <case UNDERLYING_TYPE>: Remove.
> 	<case TRAIT_TYPE>: New.
> 	* module.cc (trees_out::type_node) <case UNDERLYING_TYPE>:
> 	Remove.
> 	<case TRAIT_TYPE>: New.
> 	(trees_in::tree_node): Likewise.
> 	* parser.cc (cp_parser_primary_expression): Adjust after
> 	renaming cp_parser_trait_expr.
> 	(cp_parser_trait_expr): Rename to ...
> 	(cp_parser_trait): ... this.  Call finish_trait_type for traits
> 	that yield a type.
> 	(cp_parser_simple_type_specifier): Adjust after renaming
> 	cp_parser_trait_expr.
> 	* pt.cc (for_each_template_parm_r) <case UNDERLYING_TYPE>:
> 	Remove.
> 	<case TRAIT_TYPE>: New.
> 	(tsubst): Likewise.
> 	(unify): Replace UNDERLYING_TYPE with TRAIT_TYPE.
> 	(dependent_type_p_r): Likewise.
> 	* semantics.cc (finish_underlying_type): Don't return
> 	UNDERLYING_TYPE anymore when processing_template_decl.
> 	(finish_trait_type): Define.
> 	* tree.cc (strip_typedefs) <case UNDERLYING_TYPE>: Remove.
> 	<case TRAIT_TYPE>: New.
> 	(cp_walk_subtrees): Likewise.
> 	* typeck.cc (structural_comptypes): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/ext/underlying_type7.C: Adjust expected error message.
> 	* g++.dg/ext/underlying_type13.C: New test.
> 	* g++.dg/ext/underlying_type14.C: New test.
> ---
>   gcc/cp/cp-objcp-common.cc                    |  2 +-
>   gcc/cp/cp-tree.def                           |  9 ++--
>   gcc/cp/cp-tree.h                             | 18 +++++++
>   gcc/cp/cxx-pretty-print.cc                   | 53 ++++++++++++++------
>   gcc/cp/cxx-pretty-print.h                    |  2 +-
>   gcc/cp/error.cc                              | 14 ++----
>   gcc/cp/mangle.cc                             |  5 +-
>   gcc/cp/module.cc                             | 24 ++++++++-
>   gcc/cp/parser.cc                             | 24 ++++-----
>   gcc/cp/pt.cc                                 | 29 +++++++----
>   gcc/cp/semantics.cc                          | 45 ++++++++++++-----
>   gcc/cp/tree.cc                               | 22 ++++++--
>   gcc/cp/typeck.cc                             |  7 ++-
>   gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C   |  4 +-
>   gcc/testsuite/g++.dg/ext/underlying_type13.C |  7 +++
>   gcc/testsuite/g++.dg/ext/underlying_type14.C |  8 +++
>   gcc/testsuite/g++.dg/ext/underlying_type7.C  |  2 +-
>   17 files changed, 197 insertions(+), 78 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/ext/underlying_type13.C
>   create mode 100644 gcc/testsuite/g++.dg/ext/underlying_type14.C
> 
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 64975699351..380f288a7f1 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -518,7 +518,7 @@ cp_common_init_ts (void)
>     MARK_TS_TYPE_NON_COMMON (DECLTYPE_TYPE);
>     MARK_TS_TYPE_NON_COMMON (TYPENAME_TYPE);
>     MARK_TS_TYPE_NON_COMMON (TYPEOF_TYPE);
> -  MARK_TS_TYPE_NON_COMMON (UNDERLYING_TYPE);
> +  MARK_TS_TYPE_NON_COMMON (TRAIT_TYPE);
>     MARK_TS_TYPE_NON_COMMON (BOUND_TEMPLATE_TEMPLATE_PARM);
>     MARK_TS_TYPE_NON_COMMON (TEMPLATE_TEMPLATE_PARM);
>     MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM);
> diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
> index f9cbd339f19..f83b4c54d43 100644
> --- a/gcc/cp/cp-tree.def
> +++ b/gcc/cp/cp-tree.def
> @@ -444,9 +444,12 @@ DEFTREECODE (BIT_CAST_EXPR, "bit_cast_expr", tcc_expression, 1)
>   
>   /** C++ extensions. */
>   
> -/* Represents a trait expression during template expansion.  */
> +/* Represents a templated trait that yields an expression.  */
>   DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0)
>   
> +/* Represents a templated trait that yields a type.  */
> +DEFTREECODE (TRAIT_TYPE, "trait_type", tcc_type, 0)
> +
>   /* A lambda expression.  This is a C++0x extension.
>      LAMBDA_EXPR_DEFAULT_CAPTURE_MODE is an enum for the default, which may be
>      none.
> @@ -466,10 +469,6 @@ DEFTREECODE (LAMBDA_EXPR, "lambda_expr", tcc_exceptional, 0)
>      DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction.  */
>   DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
>   
> -/* A type designated by `__underlying_type (type)'.
> -   UNDERLYING_TYPE_TYPE is the type in question.  */
> -DEFTREECODE (UNDERLYING_TYPE, "underlying_type", tcc_type, 0)
> -
>   /* A type designated by one of the bases type traits.
>      BASES_TYPE is the type in question.  */
>   DEFTREECODE (BASES, "bases", tcc_type, 0)
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 19bbfbc557f..a89baa8d232 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1436,6 +1436,22 @@ struct GTY (()) tree_trait_expr {
>     enum cp_trait_kind kind;
>   };
>   
> +/* An INTEGER_CST containing the kind of the trait type NODE.  */
> +#define TRAIT_TYPE_KIND_RAW(NODE) \
> +  TYPE_VALUES_RAW (TRAIT_TYPE_CHECK (NODE))
> +
> +/* The kind of the trait type NODE.  */
> +#define TRAIT_TYPE_KIND(NODE) \
> +  ((enum cp_trait_kind) TREE_INT_CST_LOW (TRAIT_TYPE_KIND_RAW (NODE)))
> +
> +/* The first argument of the trait type NODE.  */
> +#define TRAIT_TYPE_TYPE1(NODE) \
> +  TYPE_MIN_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
> +
> +/* The rest of the arguments of the trait type NODE.  */
> +#define TRAIT_TYPE_TYPE2(NODE) \
> +  TYPE_MAX_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
> +
>   /* Identifiers used for lambda types are almost anonymous.  Use this
>      spare flag to distinguish them (they also have the anonymous flag).  */
>   #define IDENTIFIER_LAMBDA_P(NODE) \
> @@ -2225,6 +2241,7 @@ enum languages { lang_c, lang_cplusplus };
>      || TREE_CODE (T) == TYPEOF_TYPE			\
>      || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM	\
>      || TREE_CODE (T) == DECLTYPE_TYPE			\
> +   || TREE_CODE (T) == TRAIT_TYPE			\
>      || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE)
>   
>   /* Nonzero if T is a class (or struct or union) type.  Also nonzero
> @@ -7731,6 +7748,7 @@ extern tree finish_decltype_type                (tree, bool, tsubst_flags_t);
>   extern tree fold_builtin_is_corresponding_member (location_t, int, tree *);
>   extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *);
>   extern tree finish_trait_expr			(location_t, enum cp_trait_kind, tree, tree);
> +extern tree finish_trait_type			(enum cp_trait_kind, tree, tree);
>   extern tree build_lambda_expr                   (void);
>   extern tree build_lambda_object			(tree);
>   extern tree begin_lambda_type                   (tree);
> diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
> index e18143e39a9..928c58e0f67 100644
> --- a/gcc/cp/cxx-pretty-print.cc
> +++ b/gcc/cp/cxx-pretty-print.cc
> @@ -483,7 +483,7 @@ cxx_pretty_printer::primary_expression (tree t)
>         break;
>   
>       case TRAIT_EXPR:
> -      pp_cxx_trait_expression (this, t);
> +      pp_cxx_trait (this, t);
>         break;
>   
>       case VA_ARG_EXPR:
> @@ -1240,7 +1240,7 @@ cxx_pretty_printer::expression (tree t)
>         break;
>   
>       case TRAIT_EXPR:
> -      pp_cxx_trait_expression (this, t);
> +      pp_cxx_trait (this, t);
>         break;
>   
>       case ATOMIC_CONSTR:
> @@ -1385,6 +1385,10 @@ cxx_pretty_printer::simple_type_specifier (tree t)
>         pp_cxx_ws_string (this, "std::nullptr_t");
>         break;
>   
> +    case TRAIT_TYPE:
> +      pp_cxx_trait (this, t);
> +      break;
> +
>       default:
>         c_pretty_printer::simple_type_specifier (t);
>         break;
> @@ -1876,7 +1880,7 @@ cxx_pretty_printer::type_id (tree t)
>       case TEMPLATE_PARM_INDEX:
>       case TEMPLATE_DECL:
>       case TYPEOF_TYPE:
> -    case UNDERLYING_TYPE:
> +    case TRAIT_TYPE:
>       case DECLTYPE_TYPE:
>       case NULLPTR_TYPE:
>       case TEMPLATE_ID_EXPR:
> @@ -2594,9 +2598,22 @@ pp_cxx_binary_fold_expression (cxx_pretty_printer *pp, tree t)
>   }
>   
>   void
> -pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
> +pp_cxx_trait (cxx_pretty_printer *pp, tree t)
>   {
> -  cp_trait_kind kind = TRAIT_EXPR_KIND (t);
> +  cp_trait_kind kind;
> +  tree type1, type2;
> +  if (TREE_CODE (t) == TRAIT_EXPR)
> +    {
> +      kind = TRAIT_EXPR_KIND (t);
> +      type1 = TRAIT_EXPR_TYPE1 (t);
> +      type2 = TRAIT_EXPR_TYPE2 (t);
> +    }
> +  else
> +    {
> +      kind = TRAIT_TYPE_KIND (t);
> +      type1 = TRAIT_TYPE_TYPE1 (t);
> +      type2 = TRAIT_TYPE_TYPE2 (t);
> +    }
>   
>     switch (kind)
>       {
> @@ -2708,23 +2725,29 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
>       case CPTK_REF_CONVERTS_FROM_TEMPORARY:
>         pp_cxx_ws_string (pp, "__reference_converts_from_temporary");
>         break;
> -
> +    case CPTK_UNDERLYING_TYPE:
> +      pp_cxx_ws_string (pp, "__underlying_type");
> +      break;
>       default:
>         gcc_unreachable ();
>       }
>   
>     pp_cxx_left_paren (pp);
> -  pp->type_id (TRAIT_EXPR_TYPE1 (t));
> -
> -  if (kind == CPTK_IS_BASE_OF
> -      || kind == CPTK_IS_SAME_AS
> -      || kind == CPTK_IS_LAYOUT_COMPATIBLE
> -      || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
> +  pp->type_id (type1);
> +  if (type2)
>       {
> -      pp_cxx_separate_with (pp, ',');
> -      pp->type_id (TRAIT_EXPR_TYPE2 (t));
> +      if (TREE_CODE (type2) != TREE_LIST)
> +	{
> +	  pp_cxx_separate_with (pp, ',');
> +	  pp->type_id (type2);
> +	}
> +      else
> +	for (tree arg = type2; arg; arg = TREE_CHAIN (arg))
> +	  {
> +	    pp_cxx_separate_with (pp, ',');
> +	    pp->type_id (TREE_VALUE (arg));
> +	  }
>       }
> -
>     pp_cxx_right_paren (pp);
>   }
>   
> diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
> index 593bd91d4f7..25a2c7c8d4a 100644
> --- a/gcc/cp/cxx-pretty-print.h
> +++ b/gcc/cp/cxx-pretty-print.h
> @@ -90,7 +90,7 @@ void pp_cxx_colon_colon (cxx_pretty_printer *);
>   void pp_cxx_separate_with (cxx_pretty_printer *, int);
>   
>   void pp_cxx_canonical_template_parameter (cxx_pretty_printer *, tree);
> -void pp_cxx_trait_expression (cxx_pretty_printer *, tree);
> +void pp_cxx_trait (cxx_pretty_printer *, tree);
>   void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree);
>   void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree);
>   void pp_cxx_addressof_expression (cxx_pretty_printer *, tree);
> diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> index 0389f35d731..4bf9a83f20b 100644
> --- a/gcc/cp/error.cc
> +++ b/gcc/cp/error.cc
> @@ -698,12 +698,8 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
>         pp_cxx_right_paren (pp);
>         break;
>   
> -    case UNDERLYING_TYPE:
> -      pp_cxx_ws_string (pp, "__underlying_type");
> -      pp_cxx_whitespace (pp);
> -      pp_cxx_left_paren (pp);
> -      dump_expr (pp, UNDERLYING_TYPE_TYPE (t), flags & ~TFF_EXPR_IN_PARENS);
> -      pp_cxx_right_paren (pp);
> +    case TRAIT_TYPE:
> +      pp_cxx_trait (pp, t);
>         break;
>   
>       case TYPE_PACK_EXPANSION:
> @@ -971,7 +967,7 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, int flags)
>       case COMPLEX_TYPE:
>       case VECTOR_TYPE:
>       case TYPEOF_TYPE:
> -    case UNDERLYING_TYPE:
> +    case TRAIT_TYPE:
>       case DECLTYPE_TYPE:
>       case TYPE_PACK_EXPANSION:
>       case FIXED_POINT_TYPE:
> @@ -1095,7 +1091,7 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags)
>       case COMPLEX_TYPE:
>       case VECTOR_TYPE:
>       case TYPEOF_TYPE:
> -    case UNDERLYING_TYPE:
> +    case TRAIT_TYPE:
>       case DECLTYPE_TYPE:
>       case TYPE_PACK_EXPANSION:
>       case FIXED_POINT_TYPE:
> @@ -2956,7 +2952,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
>         break;
>   
>       case TRAIT_EXPR:
> -      pp_cxx_trait_expression (pp, t);
> +      pp_cxx_trait (pp, t);
>         break;
>   
>       case VA_ARG_EXPR:
> diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
> index 00d283fff8c..fc750fc5d8e 100644
> --- a/gcc/cp/mangle.cc
> +++ b/gcc/cp/mangle.cc
> @@ -2389,8 +2389,9 @@ write_type (tree type)
>   	      sorry ("mangling %<typeof%>, use %<decltype%> instead");
>   	      break;
>   
> -	    case UNDERLYING_TYPE:
> -	      sorry ("mangling %<__underlying_type%>");
> +	    case TRAIT_TYPE:
> +	      error ("use of built-in trait %qT in function signature; "
> +		     "use library traits instead", type);
>   	      break;
>   
>   	    case LANG_TYPE:
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 7496df5e843..25741e5d827 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -8910,7 +8910,6 @@ trees_out::type_node (tree type)
>   
>       case DECLTYPE_TYPE:
>       case TYPEOF_TYPE:
> -    case UNDERLYING_TYPE:
>       case DEPENDENT_OPERATOR_TYPE:
>         tree_node (TYPE_VALUES_RAW (type));
>         if (TREE_CODE (type) == DECLTYPE_TYPE)
> @@ -8920,6 +8919,12 @@ trees_out::type_node (tree type)
>   	  tree_node_bools (type);
>         break;
>   
> +    case TRAIT_TYPE:
> +      tree_node (TRAIT_TYPE_KIND_RAW (type));
> +      tree_node (TRAIT_TYPE_TYPE1 (type));
> +      tree_node (TRAIT_TYPE_TYPE2 (type));
> +      break;
> +
>       case TYPE_ARGUMENT_PACK:
>         /* No additional data.  */
>         break;
> @@ -9434,7 +9439,6 @@ trees_in::tree_node (bool is_use)
>   
>   	  case DECLTYPE_TYPE:
>   	  case TYPEOF_TYPE:
> -	  case UNDERLYING_TYPE:
>   	  case DEPENDENT_OPERATOR_TYPE:
>   	    {
>   	      tree expr = tree_node ();
> @@ -9449,6 +9453,22 @@ trees_in::tree_node (bool is_use)
>   	    }
>   	    break;
>   
> +	  case TRAIT_TYPE:
> +	    {
> +	      tree kind = tree_node ();
> +	      tree type1 = tree_node ();
> +	      tree type2 = tree_node ();
> +	      if (!get_overrun ())
> +		{
> +		  res = cxx_make_type (TRAIT_TYPE);
> +		  TRAIT_TYPE_KIND_RAW (res) = kind;
> +		  TRAIT_TYPE_TYPE1 (res) = type1;
> +		  TRAIT_TYPE_TYPE2 (res) = type2;
> +		  SET_TYPE_STRUCTURAL_EQUALITY (res);
> +		}
> +	    }
> +	    break;
> +
>   	  case TYPE_ARGUMENT_PACK:
>   	    if (!get_overrun ())
>   	      {
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index d501178634a..9f5e2c292b3 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -2783,7 +2783,7 @@ static void cp_parser_late_parsing_default_args
>     (cp_parser *, tree);
>   static tree cp_parser_sizeof_operand
>     (cp_parser *, enum rid);
> -static cp_expr cp_parser_trait_expr
> +static cp_expr cp_parser_trait
>     (cp_parser *, enum rid);
>   static bool cp_parser_declares_only_class_p
>     (cp_parser *);
> @@ -5928,7 +5928,7 @@ cp_parser_primary_expression (cp_parser *parser,
>   	case RID_IS_NOTHROW_CONVERTIBLE:
>   	case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
>   	case RID_REF_CONVERTS_FROM_TEMPORARY:
> -	  return cp_parser_trait_expr (parser, token->keyword);
> +	  return cp_parser_trait (parser, token->keyword);
>   
>   	// C++ concepts
>   	case RID_REQUIRES:
> @@ -10882,18 +10882,16 @@ cp_parser_builtin_offsetof (cp_parser *parser)
>     return expr;
>   }
>   
> -/* Parse a trait expression.
> -
> -   Returns a representation of the expression, the underlying type
> -   of the type at issue when KEYWORD is RID_UNDERLYING_TYPE.  */
> +/* Parse a builtin trait expression or type.  */
>   
>   static cp_expr
> -cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
> +cp_parser_trait (cp_parser* parser, enum rid keyword)
>   {
>     cp_trait_kind kind;
>     tree type1, type2 = NULL_TREE;
>     bool binary = false;
>     bool variadic = false;
> +  bool type = false;
>   
>     switch (keyword)
>       {
> @@ -10989,6 +10987,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
>         break;
>       case RID_UNDERLYING_TYPE:
>         kind = CPTK_UNDERLYING_TYPE;
> +      type = true;
>         break;
>       case RID_BASES:
>         kind = CPTK_BASES;
> @@ -11092,14 +11091,15 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
>        the trait expr now or saving it for template instantiation.  */
>     switch (kind)
>       {
> -    case CPTK_UNDERLYING_TYPE:
> -      return cp_expr (finish_underlying_type (type1), trait_loc);
>       case CPTK_BASES:
>         return cp_expr (finish_bases (type1, false), trait_loc);
>       case CPTK_DIRECT_BASES:
>         return cp_expr (finish_bases (type1, true), trait_loc);
>       default:
> -      return finish_trait_expr (trait_loc, kind, type1, type2);
> +      if (type)
> +	return finish_trait_type (kind, type1, type2);
> +      else
> +	return finish_trait_expr (trait_loc, kind, type1, type2);
>       }
>   }
>   
> @@ -19867,7 +19867,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>         return type;
>   
>       case RID_UNDERLYING_TYPE:
> -      type = cp_parser_trait_expr (parser, RID_UNDERLYING_TYPE);
> +      type = cp_parser_trait (parser, token->keyword);
>         if (decl_specs)
>   	cp_parser_set_decl_spec_type (decl_specs, type,
>   				      token,
> @@ -19877,7 +19877,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>   
>       case RID_BASES:
>       case RID_DIRECT_BASES:
> -      type = cp_parser_trait_expr (parser, token->keyword);
> +      type = cp_parser_trait (parser, token->keyword);
>         if (decl_specs)
>          cp_parser_set_decl_spec_type (decl_specs, type,
>                                        token,
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 2d83dfd6954..cf8d8d50d63 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -10618,7 +10618,6 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
>   
>       case TYPEOF_TYPE:
>       case DECLTYPE_TYPE:
> -    case UNDERLYING_TYPE:
>         if (pfd->include_nondeduced_p
>   	  && for_each_template_parm (TYPE_VALUES_RAW (t), fn, data,
>   				     pfd->visited,
> @@ -10628,6 +10627,15 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
>         *walk_subtrees = false;
>         break;
>   
> +    case TRAIT_TYPE:
> +      if (pfd->include_nondeduced_p)
> +	{
> +	  WALK_SUBTREE (TRAIT_TYPE_TYPE1 (t));
> +	  WALK_SUBTREE (TRAIT_TYPE_TYPE2 (t));
> +	}
> +      *walk_subtrees = false;
> +      break;
> +
>       case FUNCTION_DECL:
>       case VAR_DECL:
>         if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
> @@ -16514,11 +16522,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   					complain | tf_ignore_bad_quals);
>         }
>   
> -    case UNDERLYING_TYPE:
> +    case TRAIT_TYPE:
>         {
> -	tree type = tsubst (UNDERLYING_TYPE_TYPE (t), args,
> -			    complain, in_decl);
> -	return finish_underlying_type (type);
> +	tree type1 = tsubst (TRAIT_TYPE_TYPE1 (t), args, complain, in_decl);
> +	tree type2 = tsubst (TRAIT_TYPE_TYPE2 (t), args, complain, in_decl);
> +	type = finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2);
> +	return cp_build_qualified_type (type,
> +					cp_type_quals (t) | cp_type_quals (type),
> +					complain | tf_ignore_bad_quals);
>         }
>   
>       case TYPE_ARGUMENT_PACK:
> @@ -24928,9 +24939,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
>   
>       case TYPEOF_TYPE:
>       case DECLTYPE_TYPE:
> -    case UNDERLYING_TYPE:
> +    case TRAIT_TYPE:
>         /* Cannot deduce anything from TYPEOF_TYPE, DECLTYPE_TYPE,
> -	 or UNDERLYING_TYPE nodes.  */
> +	 or TRAIT_TYPE nodes.  */
>         return unify_success (explain_p);
>   
>       case ERROR_MARK:
> @@ -27505,12 +27516,12 @@ dependent_type_p_r (tree type)
>   	       (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)))))
>       return true;
>   
> -  /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and UNDERLYING_TYPEs are
> +  /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and TRAIT_TYPEs are
>        dependent; if the argument of the `typeof' expression is not
>        type-dependent, then it should already been have resolved.  */
>     if (TREE_CODE (type) == TYPEOF_TYPE
>         || TREE_CODE (type) == DECLTYPE_TYPE
> -      || TREE_CODE (type) == UNDERLYING_TYPE)
> +      || TREE_CODE (type) == TRAIT_TYPE)
>       return true;
>   
>     /* A template argument pack is dependent if any of its packed
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index e8cd50558d6..73144ef04b8 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -4397,17 +4397,6 @@ finish_typeof (tree expr)
>   tree
>   finish_underlying_type (tree type)
>   {
> -  tree underlying_type;
> -
> -  if (processing_template_decl)
> -    {
> -      underlying_type = cxx_make_type (UNDERLYING_TYPE);
> -      UNDERLYING_TYPE_TYPE (underlying_type) = type;
> -      SET_TYPE_STRUCTURAL_EQUALITY (underlying_type);
> -
> -      return underlying_type;
> -    }
> -
>     if (!complete_type_or_else (type, NULL_TREE))
>       return error_mark_node;
>   
> @@ -4417,7 +4406,7 @@ finish_underlying_type (tree type)
>         return error_mark_node;
>       }
>   
> -  underlying_type = ENUM_UNDERLYING_TYPE (type);
> +  tree underlying_type = ENUM_UNDERLYING_TYPE (type);
>   
>     /* Fixup necessary in this case because ENUM_UNDERLYING_TYPE
>        includes TYPE_MIN_VALUE and TYPE_MAX_VALUE information.
> @@ -12224,6 +12213,38 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
>     return maybe_wrap_with_location (val, loc);
>   }
>   
> +/* Process a trait type.  */
> +
> +tree
> +finish_trait_type (cp_trait_kind kind, tree type1, tree type2)
> +{
> +  if (type1 == error_mark_node
> +      || type2 == error_mark_node)
> +    return error_mark_node;
> +
> +  if (processing_template_decl)
> +    {
> +      tree type = cxx_make_type (TRAIT_TYPE);
> +      TRAIT_TYPE_TYPE1 (type) = type1;
> +      TRAIT_TYPE_TYPE2 (type) = type2;
> +      TRAIT_TYPE_KIND_RAW (type) = build_int_cstu (integer_type_node, kind);
> +      /* These traits are intended to be used in the definition of the ::type
> +	 member of the corresponding standard library type trait (and thus won't
> +	 appear directly in template signatures), so structural equality should
> +	 suffice.  */
> +      SET_TYPE_STRUCTURAL_EQUALITY (type);
> +      return type;
> +    }
> +
> +  switch (kind)
> +    {
> +    case CPTK_UNDERLYING_TYPE:
> +      return finish_underlying_type (type1);
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +
>   /* Do-nothing variants of functions to handle pragma FLOAT_CONST_DECIMAL64,
>      which is ignored for C++.  */
>   
> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> index ea4dfc651bb..aa9c1b7d8f9 100644
> --- a/gcc/cp/tree.cc
> +++ b/gcc/cp/tree.cc
> @@ -1776,10 +1776,17 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
>   		   DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t),
>   		   tf_none));
>         break;
> -    case UNDERLYING_TYPE:
> -      type = strip_typedefs (UNDERLYING_TYPE_TYPE (t),
> -			     remove_attributes, flags);
> -      result = finish_underlying_type (type);
> +    case TRAIT_TYPE:
> +      {
> +	tree type1 = strip_typedefs (TRAIT_TYPE_TYPE1 (t),
> +				     remove_attributes, flags);
> +	tree type2 = strip_typedefs (TRAIT_TYPE_TYPE2 (t),
> +				     remove_attributes, flags);
> +	if (type1 == TRAIT_TYPE_TYPE1 (t) && type2 == TRAIT_TYPE_TYPE2 (t))
> +	  result = NULL_TREE;
> +	else
> +	  result = finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2);
> +      }
>         break;
>       case TYPE_PACK_EXPANSION:
>         {
> @@ -5383,7 +5390,6 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
>       case UNBOUND_CLASS_TEMPLATE:
>       case TEMPLATE_PARM_INDEX:
>       case TYPEOF_TYPE:
> -    case UNDERLYING_TYPE:
>         /* None of these have subtrees other than those already walked
>   	 above.  */
>         *walk_subtrees_p = 0;
> @@ -5472,6 +5478,12 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
>         *walk_subtrees_p = 0;
>         break;
>   
> +    case TRAIT_TYPE:
> +      WALK_SUBTREE (TRAIT_TYPE_TYPE1 (*tp));
> +      WALK_SUBTREE (TRAIT_TYPE_TYPE2 (*tp));
> +      *walk_subtrees_p = 0;
> +      break;
> +
>       case DECLTYPE_TYPE:
>         ++cp_unevaluated_operand;
>         /* We can't use WALK_SUBTREE here because of the goto.  */
> diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> index 5f16c4d2426..cecf825f5e6 100644
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -1621,8 +1621,11 @@ structural_comptypes (tree t1, tree t2, int strict)
>           return false;
>         break;
>   
> -    case UNDERLYING_TYPE:
> -      if (!same_type_p (UNDERLYING_TYPE_TYPE (t1), UNDERLYING_TYPE_TYPE (t2)))
> +    case TRAIT_TYPE:
> +      if (TRAIT_TYPE_KIND (t1) != TRAIT_TYPE_KIND (t2))
> +	return false;
> +      if (!same_type_p (TRAIT_TYPE_TYPE1 (t1), TRAIT_TYPE_TYPE1 (t2))
> +	  || !cp_tree_equal (TRAIT_TYPE_TYPE2 (t1), TRAIT_TYPE_TYPE2 (t2)))
>   	return false;
>         break;
>   
> diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
> index 1f5e94f6d83..50946576f74 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
> @@ -5,7 +5,7 @@ template<typename>
>   struct A {};
>   
>   template<typename T>
> -using B = A<__underlying_type(T) [[gnu::aligned(4)]]>; // { dg-warning "ignoring attributes on template argument" }
> +using B = A<__underlying_type(T) [[gnu::aligned(4)]]>; // { dg-warning "ignoring attributes applied to dependent type" }
>   
>   template<typename T>
> -using B = A<__underlying_type(T) [[gnu::packed]]>; // { dg-warning "ignoring attributes on template argument" }
> +using B = A<__underlying_type(T) [[gnu::packed]]>; // { dg-warning "ignoring attributes applied to dependent type" }
> diff --git a/gcc/testsuite/g++.dg/ext/underlying_type13.C b/gcc/testsuite/g++.dg/ext/underlying_type13.C
> new file mode 100644
> index 00000000000..c53da11eb8a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/underlying_type13.C
> @@ -0,0 +1,7 @@
> +// Verify when substituting __underlying_type its cv-quals are carried over.
> +// { dg-do compile { target c++11 } }
> +
> +template<class T> using const_underlying_type_t = const __underlying_type(T);
> +enum A { a };
> +using type = const_underlying_type_t<A>;
> +using type = const __underlying_type(A);
> diff --git a/gcc/testsuite/g++.dg/ext/underlying_type14.C b/gcc/testsuite/g++.dg/ext/underlying_type14.C
> new file mode 100644
> index 00000000000..91840b2015c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/underlying_type14.C
> @@ -0,0 +1,8 @@
> +// Verify pretty-printing when nesting a builtin trait.
> +
> +template<class T> void f(__underlying_type(__underlying_type(T))); // { dg-error "" }
> +// { dg-message "__underlying_type\\(__underlying_type\\(T\\)\\)\\)" "" { target *-*-* } .-1 }
> +
> +int main() {
> +  f<int>(0); // { dg-error "no match" }
> +}
> diff --git a/gcc/testsuite/g++.dg/ext/underlying_type7.C b/gcc/testsuite/g++.dg/ext/underlying_type7.C
> index 2d6ec51792c..137a0f08547 100644
> --- a/gcc/testsuite/g++.dg/ext/underlying_type7.C
> +++ b/gcc/testsuite/g++.dg/ext/underlying_type7.C
> @@ -9,7 +9,7 @@ enum class E6 : long { c = __LONG_MAX__ };
>   
>   template<typename T>
>     void
> -  test(T, __underlying_type(T)) // { dg-message "sorry, unimplemented: mangling" }
> +  test(T, __underlying_type(T)) // { dg-error "built-in trait '__underlying_type\\(T\\)'" }
>     { }
>   
>   int main()
  

Patch

diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 64975699351..380f288a7f1 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -518,7 +518,7 @@  cp_common_init_ts (void)
   MARK_TS_TYPE_NON_COMMON (DECLTYPE_TYPE);
   MARK_TS_TYPE_NON_COMMON (TYPENAME_TYPE);
   MARK_TS_TYPE_NON_COMMON (TYPEOF_TYPE);
-  MARK_TS_TYPE_NON_COMMON (UNDERLYING_TYPE);
+  MARK_TS_TYPE_NON_COMMON (TRAIT_TYPE);
   MARK_TS_TYPE_NON_COMMON (BOUND_TEMPLATE_TEMPLATE_PARM);
   MARK_TS_TYPE_NON_COMMON (TEMPLATE_TEMPLATE_PARM);
   MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM);
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index f9cbd339f19..f83b4c54d43 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -444,9 +444,12 @@  DEFTREECODE (BIT_CAST_EXPR, "bit_cast_expr", tcc_expression, 1)
 
 /** C++ extensions. */
 
-/* Represents a trait expression during template expansion.  */
+/* Represents a templated trait that yields an expression.  */
 DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0)
 
+/* Represents a templated trait that yields a type.  */
+DEFTREECODE (TRAIT_TYPE, "trait_type", tcc_type, 0)
+
 /* A lambda expression.  This is a C++0x extension.
    LAMBDA_EXPR_DEFAULT_CAPTURE_MODE is an enum for the default, which may be
    none.
@@ -466,10 +469,6 @@  DEFTREECODE (LAMBDA_EXPR, "lambda_expr", tcc_exceptional, 0)
    DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction.  */
 DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
 
-/* A type designated by `__underlying_type (type)'.
-   UNDERLYING_TYPE_TYPE is the type in question.  */
-DEFTREECODE (UNDERLYING_TYPE, "underlying_type", tcc_type, 0)
-
 /* A type designated by one of the bases type traits.
    BASES_TYPE is the type in question.  */
 DEFTREECODE (BASES, "bases", tcc_type, 0)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 99b486b8002..c9adf1b3822 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1436,6 +1436,22 @@  struct GTY (()) tree_trait_expr {
   enum cp_trait_kind kind;
 };
 
+/* An INTEGER_CST containing the kind of the trait type NODE.  */
+#define TRAIT_TYPE_KIND_RAW(NODE) \
+  TYPE_VALUES_RAW (TRAIT_TYPE_CHECK (NODE))
+
+/* The kind of the trait type NODE.  */
+#define TRAIT_TYPE_KIND(NODE) \
+  ((enum cp_trait_kind) TREE_INT_CST_LOW (TRAIT_TYPE_KIND_RAW (NODE)))
+
+/* The first argument of the trait type NODE.  */
+#define TRAIT_TYPE_TYPE1(NODE) \
+  TYPE_MIN_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
+
+/* The rest of the arguments of the trait type NODE.  */
+#define TRAIT_TYPE_TYPE2(NODE) \
+  TYPE_MAX_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
+
 /* Identifiers used for lambda types are almost anonymous.  Use this
    spare flag to distinguish them (they also have the anonymous flag).  */
 #define IDENTIFIER_LAMBDA_P(NODE) \
@@ -2225,6 +2241,7 @@  enum languages { lang_c, lang_cplusplus };
    || TREE_CODE (T) == TYPEOF_TYPE			\
    || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM	\
    || TREE_CODE (T) == DECLTYPE_TYPE			\
+   || TREE_CODE (T) == TRAIT_TYPE			\
    || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE)
 
 /* Nonzero if T is a class (or struct or union) type.  Also nonzero
@@ -7730,6 +7747,7 @@  extern tree finish_decltype_type                (tree, bool, tsubst_flags_t);
 extern tree fold_builtin_is_corresponding_member (location_t, int, tree *);
 extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *);
 extern tree finish_trait_expr			(location_t, enum cp_trait_kind, tree, tree);
+extern tree finish_trait_type			(enum cp_trait_kind, tree, tree);
 extern tree build_lambda_expr                   (void);
 extern tree build_lambda_object			(tree);
 extern tree begin_lambda_type                   (tree);
diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index e18143e39a9..d484019a539 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -483,7 +483,7 @@  cxx_pretty_printer::primary_expression (tree t)
       break;
 
     case TRAIT_EXPR:
-      pp_cxx_trait_expression (this, t);
+      pp_cxx_trait (this, t);
       break;
 
     case VA_ARG_EXPR:
@@ -1240,7 +1240,7 @@  cxx_pretty_printer::expression (tree t)
       break;
 
     case TRAIT_EXPR:
-      pp_cxx_trait_expression (this, t);
+      pp_cxx_trait (this, t);
       break;
 
     case ATOMIC_CONSTR:
@@ -1876,7 +1876,7 @@  cxx_pretty_printer::type_id (tree t)
     case TEMPLATE_PARM_INDEX:
     case TEMPLATE_DECL:
     case TYPEOF_TYPE:
-    case UNDERLYING_TYPE:
+    case TRAIT_TYPE:
     case DECLTYPE_TYPE:
     case NULLPTR_TYPE:
     case TEMPLATE_ID_EXPR:
@@ -2594,9 +2594,22 @@  pp_cxx_binary_fold_expression (cxx_pretty_printer *pp, tree t)
 }
 
 void
-pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
+pp_cxx_trait (cxx_pretty_printer *pp, tree t)
 {
-  cp_trait_kind kind = TRAIT_EXPR_KIND (t);
+  cp_trait_kind kind;
+  tree type1, type2;
+  if (TREE_CODE (t) == TRAIT_EXPR)
+    {
+      kind = TRAIT_EXPR_KIND (t);
+      type1 = TRAIT_EXPR_TYPE1 (t);
+      type2 = TRAIT_EXPR_TYPE2 (t);
+    }
+  else
+    {
+      kind = TRAIT_TYPE_KIND (t);
+      type1 = TRAIT_TYPE_TYPE1 (t);
+      type2 = TRAIT_TYPE_TYPE2 (t);
+    }
 
   switch (kind)
     {
@@ -2708,23 +2721,29 @@  pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       pp_cxx_ws_string (pp, "__reference_converts_from_temporary");
       break;
-
+    case CPTK_UNDERLYING_TYPE:
+      pp_cxx_ws_string (pp, "__underlying_type");
+      break;
     default:
       gcc_unreachable ();
     }
 
   pp_cxx_left_paren (pp);
-  pp->type_id (TRAIT_EXPR_TYPE1 (t));
-
-  if (kind == CPTK_IS_BASE_OF
-      || kind == CPTK_IS_SAME_AS
-      || kind == CPTK_IS_LAYOUT_COMPATIBLE
-      || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
+  pp->type_id (type1);
+  if (type2)
     {
-      pp_cxx_separate_with (pp, ',');
-      pp->type_id (TRAIT_EXPR_TYPE2 (t));
+      if (TREE_CODE (type2) != TREE_LIST)
+	{
+	  pp_cxx_separate_with (pp, ',');
+	  pp->type_id (type2);
+	}
+      else
+	for (tree arg = type2; arg; arg = TREE_CHAIN (arg))
+	  {
+	    pp_cxx_separate_with (pp, ',');
+	    pp->type_id (TREE_VALUE (arg));
+	  }
     }
-
   pp_cxx_right_paren (pp);
 }
 
diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
index 593bd91d4f7..25a2c7c8d4a 100644
--- a/gcc/cp/cxx-pretty-print.h
+++ b/gcc/cp/cxx-pretty-print.h
@@ -90,7 +90,7 @@  void pp_cxx_colon_colon (cxx_pretty_printer *);
 void pp_cxx_separate_with (cxx_pretty_printer *, int);
 
 void pp_cxx_canonical_template_parameter (cxx_pretty_printer *, tree);
-void pp_cxx_trait_expression (cxx_pretty_printer *, tree);
+void pp_cxx_trait (cxx_pretty_printer *, tree);
 void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree);
 void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree);
 void pp_cxx_addressof_expression (cxx_pretty_printer *, tree);
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 0389f35d731..4bf9a83f20b 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -698,12 +698,8 @@  dump_type (cxx_pretty_printer *pp, tree t, int flags)
       pp_cxx_right_paren (pp);
       break;
 
-    case UNDERLYING_TYPE:
-      pp_cxx_ws_string (pp, "__underlying_type");
-      pp_cxx_whitespace (pp);
-      pp_cxx_left_paren (pp);
-      dump_expr (pp, UNDERLYING_TYPE_TYPE (t), flags & ~TFF_EXPR_IN_PARENS);
-      pp_cxx_right_paren (pp);
+    case TRAIT_TYPE:
+      pp_cxx_trait (pp, t);
       break;
 
     case TYPE_PACK_EXPANSION:
@@ -971,7 +967,7 @@  dump_type_prefix (cxx_pretty_printer *pp, tree t, int flags)
     case COMPLEX_TYPE:
     case VECTOR_TYPE:
     case TYPEOF_TYPE:
-    case UNDERLYING_TYPE:
+    case TRAIT_TYPE:
     case DECLTYPE_TYPE:
     case TYPE_PACK_EXPANSION:
     case FIXED_POINT_TYPE:
@@ -1095,7 +1091,7 @@  dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags)
     case COMPLEX_TYPE:
     case VECTOR_TYPE:
     case TYPEOF_TYPE:
-    case UNDERLYING_TYPE:
+    case TRAIT_TYPE:
     case DECLTYPE_TYPE:
     case TYPE_PACK_EXPANSION:
     case FIXED_POINT_TYPE:
@@ -2956,7 +2952,7 @@  dump_expr (cxx_pretty_printer *pp, tree t, int flags)
       break;
 
     case TRAIT_EXPR:
-      pp_cxx_trait_expression (pp, t);
+      pp_cxx_trait (pp, t);
       break;
 
     case VA_ARG_EXPR:
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 00d283fff8c..fc750fc5d8e 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -2389,8 +2389,9 @@  write_type (tree type)
 	      sorry ("mangling %<typeof%>, use %<decltype%> instead");
 	      break;
 
-	    case UNDERLYING_TYPE:
-	      sorry ("mangling %<__underlying_type%>");
+	    case TRAIT_TYPE:
+	      error ("use of built-in trait %qT in function signature; "
+		     "use library traits instead", type);
 	      break;
 
 	    case LANG_TYPE:
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 7496df5e843..25741e5d827 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -8910,7 +8910,6 @@  trees_out::type_node (tree type)
 
     case DECLTYPE_TYPE:
     case TYPEOF_TYPE:
-    case UNDERLYING_TYPE:
     case DEPENDENT_OPERATOR_TYPE:
       tree_node (TYPE_VALUES_RAW (type));
       if (TREE_CODE (type) == DECLTYPE_TYPE)
@@ -8920,6 +8919,12 @@  trees_out::type_node (tree type)
 	  tree_node_bools (type);
       break;
 
+    case TRAIT_TYPE:
+      tree_node (TRAIT_TYPE_KIND_RAW (type));
+      tree_node (TRAIT_TYPE_TYPE1 (type));
+      tree_node (TRAIT_TYPE_TYPE2 (type));
+      break;
+
     case TYPE_ARGUMENT_PACK:
       /* No additional data.  */
       break;
@@ -9434,7 +9439,6 @@  trees_in::tree_node (bool is_use)
 
 	  case DECLTYPE_TYPE:
 	  case TYPEOF_TYPE:
-	  case UNDERLYING_TYPE:
 	  case DEPENDENT_OPERATOR_TYPE:
 	    {
 	      tree expr = tree_node ();
@@ -9449,6 +9453,22 @@  trees_in::tree_node (bool is_use)
 	    }
 	    break;
 
+	  case TRAIT_TYPE:
+	    {
+	      tree kind = tree_node ();
+	      tree type1 = tree_node ();
+	      tree type2 = tree_node ();
+	      if (!get_overrun ())
+		{
+		  res = cxx_make_type (TRAIT_TYPE);
+		  TRAIT_TYPE_KIND_RAW (res) = kind;
+		  TRAIT_TYPE_TYPE1 (res) = type1;
+		  TRAIT_TYPE_TYPE2 (res) = type2;
+		  SET_TYPE_STRUCTURAL_EQUALITY (res);
+		}
+	    }
+	    break;
+
 	  case TYPE_ARGUMENT_PACK:
 	    if (!get_overrun ())
 	      {
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index d501178634a..9f5e2c292b3 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2783,7 +2783,7 @@  static void cp_parser_late_parsing_default_args
   (cp_parser *, tree);
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
-static cp_expr cp_parser_trait_expr
+static cp_expr cp_parser_trait
   (cp_parser *, enum rid);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
@@ -5928,7 +5928,7 @@  cp_parser_primary_expression (cp_parser *parser,
 	case RID_IS_NOTHROW_CONVERTIBLE:
 	case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
 	case RID_REF_CONVERTS_FROM_TEMPORARY:
-	  return cp_parser_trait_expr (parser, token->keyword);
+	  return cp_parser_trait (parser, token->keyword);
 
 	// C++ concepts
 	case RID_REQUIRES:
@@ -10882,18 +10882,16 @@  cp_parser_builtin_offsetof (cp_parser *parser)
   return expr;
 }
 
-/* Parse a trait expression.
-
-   Returns a representation of the expression, the underlying type
-   of the type at issue when KEYWORD is RID_UNDERLYING_TYPE.  */
+/* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, enum rid keyword)
 {
   cp_trait_kind kind;
   tree type1, type2 = NULL_TREE;
   bool binary = false;
   bool variadic = false;
+  bool type = false;
 
   switch (keyword)
     {
@@ -10989,6 +10987,7 @@  cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
       break;
     case RID_UNDERLYING_TYPE:
       kind = CPTK_UNDERLYING_TYPE;
+      type = true;
       break;
     case RID_BASES:
       kind = CPTK_BASES;
@@ -11092,14 +11091,15 @@  cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
      the trait expr now or saving it for template instantiation.  */
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return cp_expr (finish_underlying_type (type1), trait_loc);
     case CPTK_BASES:
       return cp_expr (finish_bases (type1, false), trait_loc);
     case CPTK_DIRECT_BASES:
       return cp_expr (finish_bases (type1, true), trait_loc);
     default:
-      return finish_trait_expr (trait_loc, kind, type1, type2);
+      if (type)
+	return finish_trait_type (kind, type1, type2);
+      else
+	return finish_trait_expr (trait_loc, kind, type1, type2);
     }
 }
 
@@ -19867,7 +19867,7 @@  cp_parser_simple_type_specifier (cp_parser* parser,
       return type;
 
     case RID_UNDERLYING_TYPE:
-      type = cp_parser_trait_expr (parser, RID_UNDERLYING_TYPE);
+      type = cp_parser_trait (parser, token->keyword);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
@@ -19877,7 +19877,7 @@  cp_parser_simple_type_specifier (cp_parser* parser,
 
     case RID_BASES:
     case RID_DIRECT_BASES:
-      type = cp_parser_trait_expr (parser, token->keyword);
+      type = cp_parser_trait (parser, token->keyword);
       if (decl_specs)
        cp_parser_set_decl_spec_type (decl_specs, type,
                                      token,
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 30c6994bae1..1a4491d3556 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10619,7 +10619,6 @@  for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
 
     case TYPEOF_TYPE:
     case DECLTYPE_TYPE:
-    case UNDERLYING_TYPE:
       if (pfd->include_nondeduced_p
 	  && for_each_template_parm (TYPE_VALUES_RAW (t), fn, data,
 				     pfd->visited,
@@ -10629,6 +10628,15 @@  for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
       *walk_subtrees = false;
       break;
 
+    case TRAIT_TYPE:
+      if (pfd->include_nondeduced_p)
+	{
+	  WALK_SUBTREE (TRAIT_TYPE_TYPE1 (t));
+	  WALK_SUBTREE (TRAIT_TYPE_TYPE2 (t));
+	}
+      *walk_subtrees = false;
+      break;
+
     case FUNCTION_DECL:
     case VAR_DECL:
       if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
@@ -16515,11 +16523,11 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 					complain | tf_ignore_bad_quals);
       }
 
-    case UNDERLYING_TYPE:
+    case TRAIT_TYPE:
       {
-	tree type = tsubst (UNDERLYING_TYPE_TYPE (t), args,
-			    complain, in_decl);
-	return finish_underlying_type (type);
+	tree type1 = tsubst (TRAIT_TYPE_TYPE1 (t), args, complain, in_decl);
+	tree type2 = tsubst (TRAIT_TYPE_TYPE2 (t), args, complain, in_decl);
+	return finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2);
       }
 
     case TYPE_ARGUMENT_PACK:
@@ -24929,9 +24937,9 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 
     case TYPEOF_TYPE:
     case DECLTYPE_TYPE:
-    case UNDERLYING_TYPE:
+    case TRAIT_TYPE:
       /* Cannot deduce anything from TYPEOF_TYPE, DECLTYPE_TYPE,
-	 or UNDERLYING_TYPE nodes.  */
+	 or TRAIT_TYPE nodes.  */
       return unify_success (explain_p);
 
     case ERROR_MARK:
@@ -27506,12 +27514,12 @@  dependent_type_p_r (tree type)
 	       (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)))))
     return true;
 
-  /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and UNDERLYING_TYPEs are
+  /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and TRAIT_TYPEs are
      dependent; if the argument of the `typeof' expression is not
      type-dependent, then it should already been have resolved.  */
   if (TREE_CODE (type) == TYPEOF_TYPE
       || TREE_CODE (type) == DECLTYPE_TYPE
-      || TREE_CODE (type) == UNDERLYING_TYPE)
+      || TREE_CODE (type) == TRAIT_TYPE)
     return true;
 
   /* A template argument pack is dependent if any of its packed
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e8cd50558d6..ea00805c97d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -4397,17 +4397,6 @@  finish_typeof (tree expr)
 tree
 finish_underlying_type (tree type)
 {
-  tree underlying_type;
-
-  if (processing_template_decl)
-    {
-      underlying_type = cxx_make_type (UNDERLYING_TYPE);
-      UNDERLYING_TYPE_TYPE (underlying_type) = type;
-      SET_TYPE_STRUCTURAL_EQUALITY (underlying_type);
-
-      return underlying_type;
-    }
-
   if (!complete_type_or_else (type, NULL_TREE))
     return error_mark_node;
 
@@ -4417,7 +4406,7 @@  finish_underlying_type (tree type)
       return error_mark_node;
     }
 
-  underlying_type = ENUM_UNDERLYING_TYPE (type);
+  tree underlying_type = ENUM_UNDERLYING_TYPE (type);
 
   /* Fixup necessary in this case because ENUM_UNDERLYING_TYPE
      includes TYPE_MIN_VALUE and TYPE_MAX_VALUE information.
@@ -12224,6 +12213,34 @@  finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
   return maybe_wrap_with_location (val, loc);
 }
 
+/* Process a trait type.  */
+
+tree
+finish_trait_type (cp_trait_kind kind, tree type1, tree type2)
+{
+  if (type1 == error_mark_node
+      || type2 == error_mark_node)
+    return error_mark_node;
+
+  if (processing_template_decl)
+    {
+      tree type = cxx_make_type (TRAIT_TYPE);
+      TRAIT_TYPE_TYPE1 (type) = type1;
+      TRAIT_TYPE_TYPE2 (type) = type2;
+      TRAIT_TYPE_KIND_RAW (type) = build_int_cstu (integer_type_node, kind);
+      SET_TYPE_STRUCTURAL_EQUALITY (type);
+      return type;
+    }
+
+  switch (kind)
+    {
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Do-nothing variants of functions to handle pragma FLOAT_CONST_DECIMAL64,
    which is ignored for C++.  */
 
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index d0bd41ae5a0..eef694689cc 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -1776,10 +1776,17 @@  strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
 		   DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t),
 		   tf_none));
       break;
-    case UNDERLYING_TYPE:
-      type = strip_typedefs (UNDERLYING_TYPE_TYPE (t),
-			     remove_attributes, flags);
-      result = finish_underlying_type (type);
+    case TRAIT_TYPE:
+      {
+	tree type1 = strip_typedefs (TRAIT_TYPE_TYPE1 (t),
+				     remove_attributes, flags);
+	tree type2 = strip_typedefs (TRAIT_TYPE_TYPE2 (t),
+				     remove_attributes, flags);
+	if (type1 == TRAIT_TYPE_TYPE1 (t) && type2 == TRAIT_TYPE_TYPE2 (t))
+	  result = NULL_TREE;
+	else
+	  result = finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2);
+      }
       break;
     case TYPE_PACK_EXPANSION:
       {
@@ -5383,7 +5390,6 @@  cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
     case UNBOUND_CLASS_TEMPLATE:
     case TEMPLATE_PARM_INDEX:
     case TYPEOF_TYPE:
-    case UNDERLYING_TYPE:
       /* None of these have subtrees other than those already walked
 	 above.  */
       *walk_subtrees_p = 0;
@@ -5472,6 +5478,12 @@  cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
       *walk_subtrees_p = 0;
       break;
 
+    case TRAIT_TYPE:
+      WALK_SUBTREE (TRAIT_TYPE_TYPE1 (*tp));
+      WALK_SUBTREE (TRAIT_TYPE_TYPE2 (*tp));
+      *walk_subtrees_p = 0;
+      break;
+
     case DECLTYPE_TYPE:
       ++cp_unevaluated_operand;
       /* We can't use WALK_SUBTREE here because of the goto.  */
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 4854b983765..5064a009af0 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -1621,8 +1621,11 @@  structural_comptypes (tree t1, tree t2, int strict)
         return false;
       break;
 
-    case UNDERLYING_TYPE:
-      if (!same_type_p (UNDERLYING_TYPE_TYPE (t1), UNDERLYING_TYPE_TYPE (t2)))
+    case TRAIT_TYPE:
+      if (TRAIT_TYPE_KIND (t1) != TRAIT_TYPE_KIND (t2))
+	return false;
+      if (!same_type_p (TRAIT_TYPE_TYPE1 (t1), TRAIT_TYPE_TYPE1 (t2))
+	  || !cp_tree_equal (TRAIT_TYPE_TYPE2 (t1), TRAIT_TYPE_TYPE2 (t2)))
 	return false;
       break;
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
index 1f5e94f6d83..50946576f74 100644
--- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
@@ -5,7 +5,7 @@  template<typename>
 struct A {};
 
 template<typename T>
-using B = A<__underlying_type(T) [[gnu::aligned(4)]]>; // { dg-warning "ignoring attributes on template argument" }
+using B = A<__underlying_type(T) [[gnu::aligned(4)]]>; // { dg-warning "ignoring attributes applied to dependent type" }
 
 template<typename T>
-using B = A<__underlying_type(T) [[gnu::packed]]>; // { dg-warning "ignoring attributes on template argument" }
+using B = A<__underlying_type(T) [[gnu::packed]]>; // { dg-warning "ignoring attributes applied to dependent type" }
diff --git a/gcc/testsuite/g++.dg/ext/underlying_type7.C b/gcc/testsuite/g++.dg/ext/underlying_type7.C
index 2d6ec51792c..137a0f08547 100644
--- a/gcc/testsuite/g++.dg/ext/underlying_type7.C
+++ b/gcc/testsuite/g++.dg/ext/underlying_type7.C
@@ -9,7 +9,7 @@  enum class E6 : long { c = __LONG_MAX__ };
 
 template<typename T>
   void
-  test(T, __underlying_type(T)) // { dg-message "sorry, unimplemented: mangling" }
+  test(T, __underlying_type(T)) // { dg-error "built-in trait '__underlying_type\\(T\\)'" }
   { }
 
 int main()