public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR
@ 2022-09-27 19:50 Patrick Palka
  2022-09-27 19:50 ` [PATCH 2/2] c++: implement __remove_cv, __remove_reference and __remove_cvref Patrick Palka
  2022-09-27 21:07 ` [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR Jason Merrill
  0 siblings, 2 replies; 7+ messages in thread
From: Patrick Palka @ 2022-09-27 19:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, libstdc++, Patrick Palka

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(-)

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()
-- 
2.38.0.rc1.2.g4b79ee4b0c


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 2/2] c++: implement __remove_cv, __remove_reference and __remove_cvref
  2022-09-27 19:50 [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR Patrick Palka
@ 2022-09-27 19:50 ` Patrick Palka
  2022-09-27 20:27   ` Jonathan Wakely
  2022-09-27 21:09   ` Jason Merrill
  2022-09-27 21:07 ` [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR Jason Merrill
  1 sibling, 2 replies; 7+ messages in thread
From: Patrick Palka @ 2022-09-27 19:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, libstdc++, Patrick Palka

This uses TRAIT_TYPE from the previous patch to implement efficient
built-ins for std::remove_cv, std::remove_reference and std::remove_cvref.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk?

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Add __remove_cv,
	__remove_reference and __remove_cvref.
	* c-common.h (enum rid): Add RID_REMOVE_CV, RID_REMOVE_REFERENCE
	and RID_REMOVE_CVREF.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Handle CPTK_REMOVE_CV,
	CPTK_REMOVE_REFERENCE and CPTK_REMOVE_CVREF.
	* cp-objcp-common.cc (names_builtin_p): Likewise.
	* cp-tree.h (enum cp_trait_kind): Add CPTK_REMOVE_CV,
	CPTK_REMOVE_REFERENCE and CPTK_REMOVE_CVREF.
	* cxx-pretty-print.cc (pp_cxx_trait): Handle CPTK_REMOVE_CV,
	CPTK_REMOVE_REFERENCE and CPTK_REMOVE_CVREF.
	* parser.cc (cp_keyword_starts_decl_specifier_p): Return true
	for RID_REMOVE_CV, RID_REMOVE_REFERENCE and RID_REMOVE_CVREF.
	(cp_parser_trait): Handle RID_REMOVE_CV, RID_REMOVE_REFERENCE
	and RID_REMOVE_CVREF.
	(cp_parser_simple_type_specifier): Likewise.
	* semantics.cc (finish_trait_type): Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/unique_ptr.h (unique_ptr<_Tp[], _Dp>): Remove
	__remove_cv and use __remove_cv_t instead.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test __remove_cv,
	__remove_reference and __remove_cvref.
	* g++.dg/ext/remove_cv.C: New test.
	* g++.dg/ext/remove_reference.C: New test.
	* g++.dg/ext/remove_cvref.C: New test.
---
 gcc/c-family/c-common.cc                    |  3 +++
 gcc/c-family/c-common.h                     |  1 +
 gcc/cp/constraint.cc                        |  3 +++
 gcc/cp/cp-objcp-common.cc                   |  3 +++
 gcc/cp/cp-tree.h                            |  5 +++-
 gcc/cp/cxx-pretty-print.cc                  |  9 +++++++
 gcc/cp/parser.cc                            | 18 ++++++++++++++
 gcc/cp/semantics.cc                         | 10 ++++++++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |  9 +++++++
 gcc/testsuite/g++.dg/ext/remove_cv.C        | 26 +++++++++++++++++++++
 gcc/testsuite/g++.dg/ext/remove_cvref.C     | 26 +++++++++++++++++++++
 gcc/testsuite/g++.dg/ext/remove_reference.C | 26 +++++++++++++++++++++
 libstdc++-v3/include/bits/unique_ptr.h      |  5 +---
 13 files changed, 139 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_cv.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_cvref.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_reference.C

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index cda6910e8c5..6e0af863a49 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -547,6 +547,9 @@ const struct c_common_resword c_common_reswords[] =
 					D_CXXONLY },
   { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY,
 					D_CXXONLY },
+  { "__remove_cv", RID_REMOVE_CV, D_CXXONLY },
+  { "__remove_reference", RID_REMOVE_REFERENCE, D_CXXONLY },
+  { "__remove_cvref", RID_REMOVE_CVREF, D_CXXONLY },
 
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 50a4691cda6..d5c98d306ce 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -187,6 +187,7 @@ enum rid
   RID_IS_CONVERTIBLE,		RID_IS_NOTHROW_CONVERTIBLE,
   RID_REF_CONSTRUCTS_FROM_TEMPORARY,
   RID_REF_CONVERTS_FROM_TEMPORARY,
+  RID_REMOVE_CV, RID_REMOVE_REFERENCE, RID_REMOVE_CVREF,
 
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 266ec581a20..ca73aff3f38 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_BASES:
     case CPTK_DIRECT_BASES:
     case CPTK_UNDERLYING_TYPE:
+    case CPTK_REMOVE_CV:
+    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       /* We shouldn't see these non-expression traits.  */
       gcc_unreachable ();
     /* We deliberately omit the default case so that when adding a new
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 380f288a7f1..2d3f206b530 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -467,6 +467,9 @@ names_builtin_p (const char *name)
     case RID_IS_NOTHROW_CONVERTIBLE:
     case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
     case RID_REF_CONVERTS_FROM_TEMPORARY:
+    case RID_REMOVE_CV:
+    case RID_REMOVE_REFERENCE:
+    case RID_REMOVE_CVREF:
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c9adf1b3822..5c8f585b821 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1411,7 +1411,10 @@ enum cp_trait_kind
   CPTK_IS_CONVERTIBLE,
   CPTK_IS_NOTHROW_CONVERTIBLE,
   CPTK_REF_CONSTRUCTS_FROM_TEMPORARY,
-  CPTK_REF_CONVERTS_FROM_TEMPORARY
+  CPTK_REF_CONVERTS_FROM_TEMPORARY,
+  CPTK_REMOVE_CV,
+  CPTK_REMOVE_REFERENCE,
+  CPTK_REMOVE_CVREF,
 };
 
 /* The types that we are processing.  */
diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index d484019a539..9ca158f1453 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -2724,6 +2724,15 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t)
     case CPTK_UNDERLYING_TYPE:
       pp_cxx_ws_string (pp, "__underlying_type");
       break;
+    case CPTK_REMOVE_CV:
+      pp_cxx_ws_string (pp, "__remove_cv");
+      break;
+    case CPTK_REMOVE_REFERENCE:
+      pp_cxx_ws_string (pp, "__remove_reference");
+      break;
+    case CPTK_REMOVE_CVREF:
+      pp_cxx_ws_string (pp, "__remove_cvref");
+      break;
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 9f5e2c292b3..d592d783250 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -1147,6 +1147,9 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
       /* C++11 extensions.  */
     case RID_DECLTYPE:
     case RID_UNDERLYING_TYPE:
+    case RID_REMOVE_CV:
+    case RID_REMOVE_REFERENCE:
+    case RID_REMOVE_CVREF:
     case RID_CONSTEXPR:
       /* C++20 extensions.  */
     case RID_CONSTINIT:
@@ -11027,6 +11030,18 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
       kind = CPTK_REF_CONVERTS_FROM_TEMPORARY;
       binary = true;
       break;
+    case RID_REMOVE_CV:
+      kind = CPTK_REMOVE_CV;
+      type = true;
+      break;
+    case RID_REMOVE_REFERENCE:
+      kind = CPTK_REMOVE_REFERENCE;
+      type = true;
+      break;
+    case RID_REMOVE_CVREF:
+      kind = CPTK_REMOVE_CVREF;
+      type = true;
+      break;
     default:
       gcc_unreachable ();
     }
@@ -19867,6 +19882,9 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       return type;
 
     case RID_UNDERLYING_TYPE:
+    case RID_REMOVE_CV:
+    case RID_REMOVE_REFERENCE:
+    case RID_REMOVE_CVREF:
       type = cp_parser_trait (parser, token->keyword);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index ea00805c97d..a73a07d468d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12236,6 +12236,16 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2)
     {
     case CPTK_UNDERLYING_TYPE:
       return finish_underlying_type (type1);
+    case CPTK_REMOVE_CV:
+      return cv_unqualified (type1);
+    case CPTK_REMOVE_REFERENCE:
+      if (TYPE_REF_P (type1))
+	type1 = TREE_TYPE (type1);
+      return type1;
+    case CPTK_REMOVE_CVREF:
+      if (TYPE_REF_P (type1))
+	type1 = TREE_TYPE (type1);
+      return cv_unqualified (type1);
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 17dabf648cf..f343e153e56 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -137,3 +137,12 @@
 #if !__has_builtin (__is_nothrow_convertible)
 # error "__has_builtin (__is_nothrow_convertible) failed"
 #endif
+#if !__has_builtin (__remove_cv)
+# error "__has_builtin (__remove_cv) failed"
+#endif
+#if !__has_builtin (__remove_reference)
+# error "__has_builtin (__remove_reference) failed"
+#endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_cv.C b/gcc/testsuite/g++.dg/ext/remove_cv.C
new file mode 100644
index 00000000000..941aa9e4c11
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_cv.C
@@ -0,0 +1,26 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_cv(void), void));
+SA(__is_same(__remove_cv(int*), int*));
+
+SA(__is_same(__remove_cv(int&), int&));
+SA(__is_same(__remove_cv(const int&), const int&));
+SA(__is_same(__remove_cv(volatile int&), volatile int&));
+SA(__is_same(__remove_cv(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_cv(int&&), int&&));
+SA(__is_same(__remove_cv(const int&&), const int&&));
+SA(__is_same(__remove_cv(volatile int&&), volatile int&&));
+SA(__is_same(__remove_cv(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_cv(int[3]), int[3]));
+SA(__is_same(__remove_cv(const int[3]), int[3]));
+SA(__is_same(__remove_cv(volatile int[3]), int[3]));
+SA(__is_same(__remove_cv(const volatile int[3]), int[3]));
+
+SA(__is_same(__remove_cv(int(int)), int(int)));
+SA(__is_same(__remove_cv(int(*const)(int)), int(*)(int)));
+SA(__is_same(__remove_cv(int(*volatile)(int)), int(*)(int)));
+SA(__is_same(__remove_cv(int(*const volatile)(int)), int(*)(int)));
diff --git a/gcc/testsuite/g++.dg/ext/remove_cvref.C b/gcc/testsuite/g++.dg/ext/remove_cvref.C
new file mode 100644
index 00000000000..22725c08f63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_cvref.C
@@ -0,0 +1,26 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_cvref(void), void));
+SA(__is_same(__remove_cvref(int*), int*));
+
+SA(__is_same(__remove_cvref(int&), int));
+SA(__is_same(__remove_cvref(const int&), int));
+SA(__is_same(__remove_cvref(volatile int&), int));
+SA(__is_same(__remove_cvref(const volatile int&), int));
+
+SA(__is_same(__remove_cvref(int&&), int));
+SA(__is_same(__remove_cvref(const int&&), int));
+SA(__is_same(__remove_cvref(volatile int&&), int));
+SA(__is_same(__remove_cvref(const volatile int&&), int));
+
+SA(__is_same(__remove_cvref(int[3]), int[3]));
+SA(__is_same(__remove_cvref(const int[3]), int[3]));
+SA(__is_same(__remove_cvref(volatile int[3]), int[3]));
+SA(__is_same(__remove_cvref(const volatile int[3]), int[3]));
+
+SA(__is_same(__remove_cvref(int(int)), int(int)));
+SA(__is_same(__remove_cvref(int(*const)(int)), int(*)(int)));
+SA(__is_same(__remove_cvref(int(*volatile)(int)), int(*)(int)));
+SA(__is_same(__remove_cvref(int(*const volatile)(int)), int(*)(int)));
diff --git a/gcc/testsuite/g++.dg/ext/remove_reference.C b/gcc/testsuite/g++.dg/ext/remove_reference.C
new file mode 100644
index 00000000000..af3c354b670
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_reference.C
@@ -0,0 +1,26 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_reference(void), void));
+SA(__is_same(__remove_reference(int*), int*));
+
+SA(__is_same(__remove_reference(int&), int));
+SA(__is_same(__remove_reference(const int&), const int));
+SA(__is_same(__remove_reference(volatile int&), volatile int));
+SA(__is_same(__remove_reference(const volatile int&), const volatile int));
+
+SA(__is_same(__remove_reference(int&&), int));
+SA(__is_same(__remove_reference(const int&&), const int));
+SA(__is_same(__remove_reference(volatile int&&), volatile int));
+SA(__is_same(__remove_reference(const volatile int&&), const volatile int));
+
+SA(__is_same(__remove_reference(int[3]), int[3]));
+SA(__is_same(__remove_reference(const int[3]), const int[3]));
+SA(__is_same(__remove_reference(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_reference(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_reference(int(int)), int(int)));
+SA(__is_same(__remove_reference(int(*const)(int)), int(*const)(int)));
+SA(__is_same(__remove_reference(int(*volatile)(int)), int(*volatile)(int)));
+SA(__is_same(__remove_reference(int(*const volatile)(int)), int(*const volatile)(int)));
diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h
index 1086f408374..34c3a766179 100644
--- a/libstdc++-v3/include/bits/unique_ptr.h
+++ b/libstdc++-v3/include/bits/unique_ptr.h
@@ -541,14 +541,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       __uniq_ptr_data<_Tp, _Dp> _M_t;
 
-      template<typename _Up>
-	using __remove_cv = typename remove_cv<_Up>::type;
-
       // like is_base_of<_Tp, _Up> but false if unqualified types are the same
       template<typename _Up>
 	using __is_derived_Tp
 	  = __and_< is_base_of<_Tp, _Up>,
-		    __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >;
+		    __not_<is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up>>> >;
 
     public:
       using pointer	  = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
-- 
2.38.0.rc1.2.g4b79ee4b0c


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] c++: implement __remove_cv, __remove_reference and __remove_cvref
  2022-09-27 19:50 ` [PATCH 2/2] c++: implement __remove_cv, __remove_reference and __remove_cvref Patrick Palka
@ 2022-09-27 20:27   ` Jonathan Wakely
  2022-09-27 21:09   ` Jason Merrill
  1 sibling, 0 replies; 7+ messages in thread
From: Jonathan Wakely @ 2022-09-27 20:27 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches, libstdc++, jason

On Tue, 27 Sept 2022 at 20:50, Patrick Palka via Libstdc++
<libstdc++@gcc.gnu.org> wrote:
> libstdc++-v3/ChangeLog:
>
>         * include/bits/unique_ptr.h (unique_ptr<_Tp[], _Dp>): Remove
>         __remove_cv and use __remove_cv_t instead.

This part is OK. I added that __remove_cv in 2012, and could have
replaced it with __remove_cv_t when I added that in 2019.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR
  2022-09-27 19:50 [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR Patrick Palka
  2022-09-27 19:50 ` [PATCH 2/2] c++: implement __remove_cv, __remove_reference and __remove_cvref Patrick Palka
@ 2022-09-27 21:07 ` Jason Merrill
  2022-09-28 16:36   ` Patrick Palka
  1 sibling, 1 reply; 7+ messages in thread
From: Jason Merrill @ 2022-09-27 21:07 UTC (permalink / raw)
  To: Patrick Palka, gcc-patches; +Cc: libstdc++

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()


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] c++: implement __remove_cv, __remove_reference and __remove_cvref
  2022-09-27 19:50 ` [PATCH 2/2] c++: implement __remove_cv, __remove_reference and __remove_cvref Patrick Palka
  2022-09-27 20:27   ` Jonathan Wakely
@ 2022-09-27 21:09   ` Jason Merrill
  1 sibling, 0 replies; 7+ messages in thread
From: Jason Merrill @ 2022-09-27 21:09 UTC (permalink / raw)
  To: Patrick Palka, gcc-patches; +Cc: libstdc++

On 9/27/22 15:50, Patrick Palka wrote:
> This uses TRAIT_TYPE from the previous patch to implement efficient
> built-ins for std::remove_cv, std::remove_reference and std::remove_cvref.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk?

OK once the previous patch goes in.

> gcc/c-family/ChangeLog:
> 
> 	* c-common.cc (c_common_reswords): Add __remove_cv,
> 	__remove_reference and __remove_cvref.
> 	* c-common.h (enum rid): Add RID_REMOVE_CV, RID_REMOVE_REFERENCE
> 	and RID_REMOVE_CVREF.
> 
> gcc/cp/ChangeLog:
> 
> 	* constraint.cc (diagnose_trait_expr): Handle CPTK_REMOVE_CV,
> 	CPTK_REMOVE_REFERENCE and CPTK_REMOVE_CVREF.
> 	* cp-objcp-common.cc (names_builtin_p): Likewise.
> 	* cp-tree.h (enum cp_trait_kind): Add CPTK_REMOVE_CV,
> 	CPTK_REMOVE_REFERENCE and CPTK_REMOVE_CVREF.
> 	* cxx-pretty-print.cc (pp_cxx_trait): Handle CPTK_REMOVE_CV,
> 	CPTK_REMOVE_REFERENCE and CPTK_REMOVE_CVREF.
> 	* parser.cc (cp_keyword_starts_decl_specifier_p): Return true
> 	for RID_REMOVE_CV, RID_REMOVE_REFERENCE and RID_REMOVE_CVREF.
> 	(cp_parser_trait): Handle RID_REMOVE_CV, RID_REMOVE_REFERENCE
> 	and RID_REMOVE_CVREF.
> 	(cp_parser_simple_type_specifier): Likewise.
> 	* semantics.cc (finish_trait_type): Likewise.
> 
> libstdc++-v3/ChangeLog:
> 
> 	* include/bits/unique_ptr.h (unique_ptr<_Tp[], _Dp>): Remove
> 	__remove_cv and use __remove_cv_t instead.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/ext/has-builtin-1.C: Test __remove_cv,
> 	__remove_reference and __remove_cvref.
> 	* g++.dg/ext/remove_cv.C: New test.
> 	* g++.dg/ext/remove_reference.C: New test.
> 	* g++.dg/ext/remove_cvref.C: New test.
> ---
>   gcc/c-family/c-common.cc                    |  3 +++
>   gcc/c-family/c-common.h                     |  1 +
>   gcc/cp/constraint.cc                        |  3 +++
>   gcc/cp/cp-objcp-common.cc                   |  3 +++
>   gcc/cp/cp-tree.h                            |  5 +++-
>   gcc/cp/cxx-pretty-print.cc                  |  9 +++++++
>   gcc/cp/parser.cc                            | 18 ++++++++++++++
>   gcc/cp/semantics.cc                         | 10 ++++++++
>   gcc/testsuite/g++.dg/ext/has-builtin-1.C    |  9 +++++++
>   gcc/testsuite/g++.dg/ext/remove_cv.C        | 26 +++++++++++++++++++++
>   gcc/testsuite/g++.dg/ext/remove_cvref.C     | 26 +++++++++++++++++++++
>   gcc/testsuite/g++.dg/ext/remove_reference.C | 26 +++++++++++++++++++++
>   libstdc++-v3/include/bits/unique_ptr.h      |  5 +---
>   13 files changed, 139 insertions(+), 5 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/ext/remove_cv.C
>   create mode 100644 gcc/testsuite/g++.dg/ext/remove_cvref.C
>   create mode 100644 gcc/testsuite/g++.dg/ext/remove_reference.C
> 
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index cda6910e8c5..6e0af863a49 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -547,6 +547,9 @@ const struct c_common_resword c_common_reswords[] =
>   					D_CXXONLY },
>     { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY,
>   					D_CXXONLY },
> +  { "__remove_cv", RID_REMOVE_CV, D_CXXONLY },
> +  { "__remove_reference", RID_REMOVE_REFERENCE, D_CXXONLY },
> +  { "__remove_cvref", RID_REMOVE_CVREF, D_CXXONLY },
>   
>     /* C++ transactional memory.  */
>     { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 50a4691cda6..d5c98d306ce 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -187,6 +187,7 @@ enum rid
>     RID_IS_CONVERTIBLE,		RID_IS_NOTHROW_CONVERTIBLE,
>     RID_REF_CONSTRUCTS_FROM_TEMPORARY,
>     RID_REF_CONVERTS_FROM_TEMPORARY,
> +  RID_REMOVE_CV, RID_REMOVE_REFERENCE, RID_REMOVE_CVREF,
>   
>     /* C++11 */
>     RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 266ec581a20..ca73aff3f38 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
>       case CPTK_BASES:
>       case CPTK_DIRECT_BASES:
>       case CPTK_UNDERLYING_TYPE:
> +    case CPTK_REMOVE_CV:
> +    case CPTK_REMOVE_REFERENCE:
> +    case CPTK_REMOVE_CVREF:
>         /* We shouldn't see these non-expression traits.  */
>         gcc_unreachable ();
>       /* We deliberately omit the default case so that when adding a new
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 380f288a7f1..2d3f206b530 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -467,6 +467,9 @@ names_builtin_p (const char *name)
>       case RID_IS_NOTHROW_CONVERTIBLE:
>       case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
>       case RID_REF_CONVERTS_FROM_TEMPORARY:
> +    case RID_REMOVE_CV:
> +    case RID_REMOVE_REFERENCE:
> +    case RID_REMOVE_CVREF:
>         return true;
>       default:
>         break;
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index c9adf1b3822..5c8f585b821 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1411,7 +1411,10 @@ enum cp_trait_kind
>     CPTK_IS_CONVERTIBLE,
>     CPTK_IS_NOTHROW_CONVERTIBLE,
>     CPTK_REF_CONSTRUCTS_FROM_TEMPORARY,
> -  CPTK_REF_CONVERTS_FROM_TEMPORARY
> +  CPTK_REF_CONVERTS_FROM_TEMPORARY,
> +  CPTK_REMOVE_CV,
> +  CPTK_REMOVE_REFERENCE,
> +  CPTK_REMOVE_CVREF,
>   };
>   
>   /* The types that we are processing.  */
> diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
> index d484019a539..9ca158f1453 100644
> --- a/gcc/cp/cxx-pretty-print.cc
> +++ b/gcc/cp/cxx-pretty-print.cc
> @@ -2724,6 +2724,15 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t)
>       case CPTK_UNDERLYING_TYPE:
>         pp_cxx_ws_string (pp, "__underlying_type");
>         break;
> +    case CPTK_REMOVE_CV:
> +      pp_cxx_ws_string (pp, "__remove_cv");
> +      break;
> +    case CPTK_REMOVE_REFERENCE:
> +      pp_cxx_ws_string (pp, "__remove_reference");
> +      break;
> +    case CPTK_REMOVE_CVREF:
> +      pp_cxx_ws_string (pp, "__remove_cvref");
> +      break;
>       default:
>         gcc_unreachable ();
>       }
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 9f5e2c292b3..d592d783250 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -1147,6 +1147,9 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>         /* C++11 extensions.  */
>       case RID_DECLTYPE:
>       case RID_UNDERLYING_TYPE:
> +    case RID_REMOVE_CV:
> +    case RID_REMOVE_REFERENCE:
> +    case RID_REMOVE_CVREF:
>       case RID_CONSTEXPR:
>         /* C++20 extensions.  */
>       case RID_CONSTINIT:
> @@ -11027,6 +11030,18 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>         kind = CPTK_REF_CONVERTS_FROM_TEMPORARY;
>         binary = true;
>         break;
> +    case RID_REMOVE_CV:
> +      kind = CPTK_REMOVE_CV;
> +      type = true;
> +      break;
> +    case RID_REMOVE_REFERENCE:
> +      kind = CPTK_REMOVE_REFERENCE;
> +      type = true;
> +      break;
> +    case RID_REMOVE_CVREF:
> +      kind = CPTK_REMOVE_CVREF;
> +      type = true;
> +      break;
>       default:
>         gcc_unreachable ();
>       }
> @@ -19867,6 +19882,9 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>         return type;
>   
>       case RID_UNDERLYING_TYPE:
> +    case RID_REMOVE_CV:
> +    case RID_REMOVE_REFERENCE:
> +    case RID_REMOVE_CVREF:
>         type = cp_parser_trait (parser, token->keyword);
>         if (decl_specs)
>   	cp_parser_set_decl_spec_type (decl_specs, type,
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index ea00805c97d..a73a07d468d 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12236,6 +12236,16 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2)
>       {
>       case CPTK_UNDERLYING_TYPE:
>         return finish_underlying_type (type1);
> +    case CPTK_REMOVE_CV:
> +      return cv_unqualified (type1);
> +    case CPTK_REMOVE_REFERENCE:
> +      if (TYPE_REF_P (type1))
> +	type1 = TREE_TYPE (type1);
> +      return type1;
> +    case CPTK_REMOVE_CVREF:
> +      if (TYPE_REF_P (type1))
> +	type1 = TREE_TYPE (type1);
> +      return cv_unqualified (type1);
>       default:
>         gcc_unreachable ();
>       }
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index 17dabf648cf..f343e153e56 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -137,3 +137,12 @@
>   #if !__has_builtin (__is_nothrow_convertible)
>   # error "__has_builtin (__is_nothrow_convertible) failed"
>   #endif
> +#if !__has_builtin (__remove_cv)
> +# error "__has_builtin (__remove_cv) failed"
> +#endif
> +#if !__has_builtin (__remove_reference)
> +# error "__has_builtin (__remove_reference) failed"
> +#endif
> +#if !__has_builtin (__remove_cvref)
> +# error "__has_builtin (__remove_cvref) failed"
> +#endif
> diff --git a/gcc/testsuite/g++.dg/ext/remove_cv.C b/gcc/testsuite/g++.dg/ext/remove_cv.C
> new file mode 100644
> index 00000000000..941aa9e4c11
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/remove_cv.C
> @@ -0,0 +1,26 @@
> +// { dg-do compile { target c++11 } }
> +
> +#define SA(X) static_assert((X),#X)
> +
> +SA(__is_same(__remove_cv(void), void));
> +SA(__is_same(__remove_cv(int*), int*));
> +
> +SA(__is_same(__remove_cv(int&), int&));
> +SA(__is_same(__remove_cv(const int&), const int&));
> +SA(__is_same(__remove_cv(volatile int&), volatile int&));
> +SA(__is_same(__remove_cv(const volatile int&), const volatile int&));
> +
> +SA(__is_same(__remove_cv(int&&), int&&));
> +SA(__is_same(__remove_cv(const int&&), const int&&));
> +SA(__is_same(__remove_cv(volatile int&&), volatile int&&));
> +SA(__is_same(__remove_cv(const volatile int&&), const volatile int&&));
> +
> +SA(__is_same(__remove_cv(int[3]), int[3]));
> +SA(__is_same(__remove_cv(const int[3]), int[3]));
> +SA(__is_same(__remove_cv(volatile int[3]), int[3]));
> +SA(__is_same(__remove_cv(const volatile int[3]), int[3]));
> +
> +SA(__is_same(__remove_cv(int(int)), int(int)));
> +SA(__is_same(__remove_cv(int(*const)(int)), int(*)(int)));
> +SA(__is_same(__remove_cv(int(*volatile)(int)), int(*)(int)));
> +SA(__is_same(__remove_cv(int(*const volatile)(int)), int(*)(int)));
> diff --git a/gcc/testsuite/g++.dg/ext/remove_cvref.C b/gcc/testsuite/g++.dg/ext/remove_cvref.C
> new file mode 100644
> index 00000000000..22725c08f63
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/remove_cvref.C
> @@ -0,0 +1,26 @@
> +// { dg-do compile { target c++11 } }
> +
> +#define SA(X) static_assert((X),#X)
> +
> +SA(__is_same(__remove_cvref(void), void));
> +SA(__is_same(__remove_cvref(int*), int*));
> +
> +SA(__is_same(__remove_cvref(int&), int));
> +SA(__is_same(__remove_cvref(const int&), int));
> +SA(__is_same(__remove_cvref(volatile int&), int));
> +SA(__is_same(__remove_cvref(const volatile int&), int));
> +
> +SA(__is_same(__remove_cvref(int&&), int));
> +SA(__is_same(__remove_cvref(const int&&), int));
> +SA(__is_same(__remove_cvref(volatile int&&), int));
> +SA(__is_same(__remove_cvref(const volatile int&&), int));
> +
> +SA(__is_same(__remove_cvref(int[3]), int[3]));
> +SA(__is_same(__remove_cvref(const int[3]), int[3]));
> +SA(__is_same(__remove_cvref(volatile int[3]), int[3]));
> +SA(__is_same(__remove_cvref(const volatile int[3]), int[3]));
> +
> +SA(__is_same(__remove_cvref(int(int)), int(int)));
> +SA(__is_same(__remove_cvref(int(*const)(int)), int(*)(int)));
> +SA(__is_same(__remove_cvref(int(*volatile)(int)), int(*)(int)));
> +SA(__is_same(__remove_cvref(int(*const volatile)(int)), int(*)(int)));
> diff --git a/gcc/testsuite/g++.dg/ext/remove_reference.C b/gcc/testsuite/g++.dg/ext/remove_reference.C
> new file mode 100644
> index 00000000000..af3c354b670
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/remove_reference.C
> @@ -0,0 +1,26 @@
> +// { dg-do compile { target c++11 } }
> +
> +#define SA(X) static_assert((X),#X)
> +
> +SA(__is_same(__remove_reference(void), void));
> +SA(__is_same(__remove_reference(int*), int*));
> +
> +SA(__is_same(__remove_reference(int&), int));
> +SA(__is_same(__remove_reference(const int&), const int));
> +SA(__is_same(__remove_reference(volatile int&), volatile int));
> +SA(__is_same(__remove_reference(const volatile int&), const volatile int));
> +
> +SA(__is_same(__remove_reference(int&&), int));
> +SA(__is_same(__remove_reference(const int&&), const int));
> +SA(__is_same(__remove_reference(volatile int&&), volatile int));
> +SA(__is_same(__remove_reference(const volatile int&&), const volatile int));
> +
> +SA(__is_same(__remove_reference(int[3]), int[3]));
> +SA(__is_same(__remove_reference(const int[3]), const int[3]));
> +SA(__is_same(__remove_reference(volatile int[3]), volatile int[3]));
> +SA(__is_same(__remove_reference(const volatile int[3]), const volatile int[3]));
> +
> +SA(__is_same(__remove_reference(int(int)), int(int)));
> +SA(__is_same(__remove_reference(int(*const)(int)), int(*const)(int)));
> +SA(__is_same(__remove_reference(int(*volatile)(int)), int(*volatile)(int)));
> +SA(__is_same(__remove_reference(int(*const volatile)(int)), int(*const volatile)(int)));
> diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h
> index 1086f408374..34c3a766179 100644
> --- a/libstdc++-v3/include/bits/unique_ptr.h
> +++ b/libstdc++-v3/include/bits/unique_ptr.h
> @@ -541,14 +541,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>   
>         __uniq_ptr_data<_Tp, _Dp> _M_t;
>   
> -      template<typename _Up>
> -	using __remove_cv = typename remove_cv<_Up>::type;
> -
>         // like is_base_of<_Tp, _Up> but false if unqualified types are the same
>         template<typename _Up>
>   	using __is_derived_Tp
>   	  = __and_< is_base_of<_Tp, _Up>,
> -		    __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >;
> +		    __not_<is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up>>> >;
>   
>       public:
>         using pointer	  = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR
  2022-09-27 21:07 ` [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR Jason Merrill
@ 2022-09-28 16:36   ` Patrick Palka
  2022-09-28 18:49     ` Jason Merrill
  0 siblings, 1 reply; 7+ messages in thread
From: Patrick Palka @ 2022-09-28 16:36 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Patrick Palka, gcc-patches, libstdc++

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()
-- 
2.38.0.rc2


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR
  2022-09-28 16:36   ` Patrick Palka
@ 2022-09-28 18:49     ` Jason Merrill
  0 siblings, 0 replies; 7+ messages in thread
From: Jason Merrill @ 2022-09-28 18:49 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches, libstdc++

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()


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-09-28 18:49 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-27 19:50 [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR Patrick Palka
2022-09-27 19:50 ` [PATCH 2/2] c++: implement __remove_cv, __remove_reference and __remove_cvref Patrick Palka
2022-09-27 20:27   ` Jonathan Wakely
2022-09-27 21:09   ` Jason Merrill
2022-09-27 21:07 ` [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR Jason Merrill
2022-09-28 16:36   ` Patrick Palka
2022-09-28 18:49     ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).