diff mbox

[C++] Add __underlying_type

Message ID 4DB5BB86.5060709@oracle.com
State New
Headers show

Commit Message

Paolo Carlini April 25, 2011, 6:20 p.m. UTC
Hi,

this is the work I did over the last days, with the off-list guidance of 
Jason, on a C++ front-end "builtin" necessary in order to implement the 
C++1x std::underlying_type, part of <type_traits>.

Most of the code is rather straightforward, in my opinion, maybe the 
most interesting bits are in finish_underlying_type, where we can't just 
use ENUM_UNDERLYING_TYPE unconditionally, because, for "old-style" 
enums, aka non-fixed underlying type enums in C++1x, the plain 
ENUM_UNDERLYING_TYPE isn't just an integral type, it includes 
information on the MIN and MAX values, etc, thus we have to "simplify" 
it by way of the rather low-level c_common_type_for_mode.

Also, note that we are not going to mangle the new "builtin", at least 
not now (also see c++/36797), a minor annoyance, which will not affect 
people using the C++1x std::underlying_type.

Tested x86_64-linux. Ok?

Thanks,
Paolo.

////////////////////////////
/gcc
2011-04-25  Paolo Carlini  <paolo.carlini@oracle.com>

	* c-family/c-common.c (struct c_common_resword): Add
	__underlying_type.
	* c-family/c-common.h (enum rid): Add RID_UNDERLYING_TYPE.

/cp
2011-04-25  Paolo Carlini  <paolo.carlini@oracle.com>

	* cp-tree.def: Add a new UNDERLYING_TYPE tree code.
	* cp-tree.h (enum cp_trait_kind): Add CPTK_UNDERLYING_TYPE, tidy.
	(UNDERLYING_TYPE_TYPE): Add.
	* cp-objcp-common.c (cp_common_init_ts): Mark UNDERLYING_TYPE
	as TS_COMMON.
	* parser.c (cp_lexer_next_token_is_decl_specifier_keyword,
	cp_parser_simple_type_specifier): Handle UNDERLYING_TYPE.
	(cp_parser_trait_expr): Deal with RID_UNDERLYING_TYPE; tidy.
	* semantics.c (finish_underlying_type): New.
	* typeck.c (structural_comptypes): Handle UNDERLYING_TYPE.
	* error.c (dump_type, dump_type_prefix, dump_type_suffix): Likewise.
	* cxx-pretty-print.c (p_cxx_type_id): Likewise.
	* tree.c (cp_walk_subtrees): Likewise.
	* pt.c (for_each_template_parm_r, tsubst, unify,
	dependent_type_p_r): Likewise.
	* mangle.c (write_type): Sorry for __underlying_type.
	* doc/extend.texi: Document __underlying_type.

/testsuite
2011-04-25  Paolo Carlini  <paolo.carlini@oracle.com>

	* g++.dg/ext/underlying_type1.C: New.
	* g++.dg/ext/underlying_type2.C: Likewise.
	* g++.dg/ext/underlying_type3.C: Likewise.
	* g++.dg/ext/underlying_type4.C: Likewise.
	* g++.dg/ext/underlying_type5.C: Likewise.
	* g++.dg/ext/underlying_type6.C: Likewise.
	* g++.dg/ext/underlying_type7.C: Likewise.
	* g++.dg/ext/underlying_type8.C: Likewise.
	* g++.dg/ext/underlying_type9.C: Likewise.
	* g++.dg/ext/underlying_type10.C: Likewise.

Comments

Jason Merrill April 25, 2011, 9:50 p.m. UTC | #1
OK.

Jason
Paolo Carlini April 25, 2011, 11:05 p.m. UTC | #2
On 04/25/2011 11:50 PM, Jason Merrill wrote:
> OK.
Committed. Thanks again!

Paolo.
diff mbox

Patch

Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 172932)
+++ doc/extend.texi	(working copy)
@@ -14422,6 +14422,10 @@  type, (possibly cv-qualified) @code{void}, or an a
 If @code{type} is a cv union type ([basic.compound]) the trait is
 true, else it is false.
 
+@item __underlying_type (type)
+The underlying type of @code{type}.  Requires: @code{type} shall be
+an enumeration type ([dcl.enum]).
+
 @end table
 
 @node Java Exceptions
Index: c-family/c-common.c
===================================================================
--- c-family/c-common.c	(revision 172932)
+++ c-family/c-common.c	(working copy)
@@ -450,6 +450,7 @@  const struct c_common_resword c_common_reswords[]
   { "__is_trivial",     RID_IS_TRIVIAL, D_CXXONLY },
   { "__is_union",	RID_IS_UNION,	D_CXXONLY },
   { "__is_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY },
+  { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
   { "__imag",		RID_IMAGPART,	0 },
   { "__imag__",		RID_IMAGPART,	0 },
   { "__inline",		RID_INLINE,	0 },
Index: c-family/c-common.h
===================================================================
--- c-family/c-common.h	(revision 172932)
+++ c-family/c-common.h	(working copy)
@@ -138,6 +138,7 @@  enum rid
   RID_IS_POD,                  RID_IS_POLYMORPHIC,
   RID_IS_STD_LAYOUT,           RID_IS_TRIVIAL,
   RID_IS_UNION,                RID_IS_LITERAL_TYPE,
+  RID_UNDERLYING_TYPE,
 
   /* C++0x */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
Index: testsuite/g++.dg/ext/underlying_type5.C
===================================================================
--- testsuite/g++.dg/ext/underlying_type5.C	(revision 0)
+++ testsuite/g++.dg/ext/underlying_type5.C	(revision 0)
@@ -0,0 +1,43 @@ 
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+enum E1 : unsigned { };
+enum E2 : char { };
+enum class E3 { };
+enum class E4 : unsigned char { c = 1 };
+enum class E5 : int { a = -1, b = 1 };
+enum class E6 : long { c = __LONG_MAX__ };
+
+typedef __underlying_type(E1) UTE1;
+typedef __underlying_type(E2) UTE2;
+typedef __underlying_type(E3) UTE3;
+typedef __underlying_type(E4) UTE4;
+typedef __underlying_type(E5) UTE5;
+typedef __underlying_type(E6) UTE6;
+
+template<typename T>
+  struct underlying_type
+  { typedef __underlying_type(T) type; };
+
+static_assert(is_same<underlying_type<E1>::type, UTE1>::value, "Error");
+static_assert(is_same<underlying_type<E2>::type, UTE2>::value, "Error");
+static_assert(is_same<underlying_type<E3>::type, UTE3>::value, "Error");
+static_assert(is_same<underlying_type<E4>::type, UTE4>::value, "Error");
+static_assert(is_same<underlying_type<E5>::type, UTE5>::value, "Error");
+static_assert(is_same<underlying_type<E6>::type, UTE6>::value, "Error");
+
+static_assert(is_same<underlying_type<E1>::type, unsigned>::value, "Error");
+static_assert(is_same<underlying_type<E2>::type, char>::value, "Error");
+static_assert(is_same<underlying_type<E3>::type, int>::value, "Error");
+static_assert(is_same<underlying_type<E4>::type, 
+	              unsigned char>::value, "Error");
+static_assert(is_same<underlying_type<E5>::type, int>::value, "Error");
+static_assert(is_same<underlying_type<E6>::type, long>::value, "Error");
Index: testsuite/g++.dg/ext/underlying_type6.C
===================================================================
--- testsuite/g++.dg/ext/underlying_type6.C	(revision 0)
+++ testsuite/g++.dg/ext/underlying_type6.C	(revision 0)
@@ -0,0 +1,31 @@ 
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+enum E1 : unsigned { };
+enum E2 : char { };
+enum class E3 { };
+enum class E4 : unsigned char { c = 1 };
+enum class E5 : int { a = -1, b = 1 };
+enum class E6 : long { c = __LONG_MAX__ };
+
+template<typename T, typename U,
+	 typename V = __underlying_type(T)>
+  struct test
+  {
+    static_assert(is_same<U, V>::value, "Error");
+  };
+
+template class test<E1, unsigned>;
+template class test<E2, char>;
+template class test<E3, int>;
+template class test<E4, unsigned char>;
+template class test<E5, int>;
+template class test<E6, long>;
Index: testsuite/g++.dg/ext/underlying_type7.C
===================================================================
--- testsuite/g++.dg/ext/underlying_type7.C	(revision 0)
+++ testsuite/g++.dg/ext/underlying_type7.C	(revision 0)
@@ -0,0 +1,24 @@ 
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+enum E1 : unsigned { E1_en = 1 };
+enum E2 : char { E2_en = 1 };
+enum class E3 { a = -1 };
+enum class E4 : unsigned char { c = 1 };
+enum class E5 : int { a = -1, b = 1 };
+enum class E6 : long { c = __LONG_MAX__ };
+
+template<typename T>
+  void
+  test(T, __underlying_type(T)) // { dg-message "sorry, unimplemented: mangling" }
+  { }
+
+int main()
+{
+  test(E1::E1_en, 1);
+  test(E2::E2_en, 1);
+  test(E3::a, -1);
+  test(E4::c, 1);
+  test(E5::a, -1);
+  test(E6::c, __LONG_MAX__);
+}
Index: testsuite/g++.dg/ext/underlying_type8.C
===================================================================
--- testsuite/g++.dg/ext/underlying_type8.C	(revision 0)
+++ testsuite/g++.dg/ext/underlying_type8.C	(revision 0)
@@ -0,0 +1,46 @@ 
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+enum E1 : unsigned { E1_en = 1 };
+enum E2 : char { E2_en = 1 };
+enum class E3 { a = -1 };
+enum class E4 : unsigned char { c = 1 };
+enum class E5 : int { a = -1, b = 1 };
+enum class E6 : long { c = __LONG_MAX__ };
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+template<typename>
+  struct underlying_type;
+
+template<typename T, typename U>
+  void
+  test(T, U, typename underlying_type<T>::type);
+
+template<typename T>
+  struct underlying_type
+  { typedef __underlying_type(T) type; };
+
+template<typename T, typename U>
+  void
+  test(T, U, typename underlying_type<T>::type)
+  {
+    static_assert(is_same<typename underlying_type<T>::type, U>::value,
+		  "Error");
+  }
+
+int main()
+{
+  test(E1::E1_en, unsigned(), 1);
+  test(E2::E2_en, char(), 1);
+  test(E3::a, int(), -1);
+  test(E4::c, (unsigned char)(1), 1);
+  test(E5::a, int(), -1);
+  test(E6::c, long(), __LONG_MAX__);
+}
Index: testsuite/g++.dg/ext/underlying_type1.C
===================================================================
--- testsuite/g++.dg/ext/underlying_type1.C	(revision 0)
+++ testsuite/g++.dg/ext/underlying_type1.C	(revision 0)
@@ -0,0 +1,18 @@ 
+// { dg-do compile }
+
+struct B { };
+union U { };
+
+template<typename T>
+  struct underlying_type
+  { typedef __underlying_type(T) type; }; // { dg-error "not an enumeration" }
+
+__underlying_type(int) i1; // { dg-error "not an enumeration|invalid" }
+__underlying_type(A)   i2; // { dg-error "expected" }
+__underlying_type(B)   i3; // { dg-error "not an enumeration|invalid" }
+__underlying_type(U)   i4; // { dg-error "not an enumeration|invalid" }
+
+underlying_type<int>::type i5;
+underlying_type<A>::type   i6; // { dg-error "not declared|template|expected" }
+underlying_type<B>::type   i7;
+underlying_type<U>::type   i8;
Index: testsuite/g++.dg/ext/underlying_type9.C
===================================================================
--- testsuite/g++.dg/ext/underlying_type9.C	(revision 0)
+++ testsuite/g++.dg/ext/underlying_type9.C	(revision 0)
@@ -0,0 +1,30 @@ 
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+enum E1 : unsigned { };
+enum E2 : char { };
+enum class E3 { };
+enum class E4 : unsigned char { c = 1 };
+enum class E5 : int { a = -1, b = 1 };
+enum class E6 : long { c = __LONG_MAX__ };
+
+template<typename T, typename U>
+  struct test
+  {
+    static_assert(is_same<T, U>::value, "Error");
+  };
+
+test<__underlying_type(E1), unsigned>       t1;
+test<__underlying_type(E2), char>           t2;
+test<__underlying_type(E3), int>            t3;
+test<__underlying_type(E4), unsigned char>  t4;
+test<__underlying_type(E5), int>            t5;
+test<__underlying_type(E6), long>           t6;
Index: testsuite/g++.dg/ext/underlying_type2.C
===================================================================
--- testsuite/g++.dg/ext/underlying_type2.C	(revision 0)
+++ testsuite/g++.dg/ext/underlying_type2.C	(revision 0)
@@ -0,0 +1,9 @@ 
+// { dg-do compile }
+
+enum E1 { };
+enum E2 { a = -1, b = 1 };
+enum E3 { c = __LONG_MAX__ };
+
+__underlying_type(E1) e1 = 0;
+__underlying_type(E2) e2 = b;
+__underlying_type(E3) e3 = __LONG_MAX__;
Index: testsuite/g++.dg/ext/underlying_type3.C
===================================================================
--- testsuite/g++.dg/ext/underlying_type3.C	(revision 0)
+++ testsuite/g++.dg/ext/underlying_type3.C	(revision 0)
@@ -0,0 +1,33 @@ 
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+enum E1 : unsigned { };
+enum E2 : char { };
+enum class E3 { };
+enum class E4 : unsigned char { c = 1 };
+enum class E5 : int { a = -1, b = 1 };
+enum class E6 : long { c = __LONG_MAX__ };
+
+__underlying_type(E1) i1 = __INT_MAX__ * 2U + 1;
+__underlying_type(E2) i2 = (char(-1) < 0
+			    ? __SCHAR_MAX__
+			    : __SCHAR_MAX__ * 2U + 1);
+__underlying_type(E3) i3 = __INT_MAX__;
+__underlying_type(E4) i4 = __SCHAR_MAX__ * 2U + 1;
+__underlying_type(E5) i5 = int(E5::b);
+__underlying_type(E6) i6 = __LONG_MAX__;
+
+static_assert(is_same<__underlying_type(E1), unsigned>::value, "Error");
+static_assert(is_same<__underlying_type(E2), char>::value, "Error");
+static_assert(is_same<__underlying_type(E3), int>::value, "Error");
+static_assert(is_same<__underlying_type(E4), unsigned char>::value, "Error");
+static_assert(is_same<__underlying_type(E5), int>::value, "Error");
+static_assert(is_same<__underlying_type(E6), long>::value, "Error");
Index: testsuite/g++.dg/ext/underlying_type10.C
===================================================================
--- testsuite/g++.dg/ext/underlying_type10.C	(revision 0)
+++ testsuite/g++.dg/ext/underlying_type10.C	(revision 0)
@@ -0,0 +1,32 @@ 
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+#include <cassert>
+
+enum E1 : unsigned { E1_en = 1 };
+enum E2 : char { E2_en = 1 };
+enum class E3 { a = -1 };
+enum class E4 : unsigned char { c = 1 };
+enum class E5 : int { a = -1, b = 1 };
+enum class E6 : long { c = __LONG_MAX__ };
+
+template<typename T>
+  struct underlying_type
+  { typedef __underlying_type(T) type; };
+
+template<typename T>
+  void
+  test(T t, typename underlying_type<T>::type v)
+  {
+    assert( t == T(v) );
+  }
+
+int main()
+{
+  test(E1::E1_en, 1);
+  test(E2::E2_en, 1);
+  test(E3::a, -1);
+  test(E4::c, 1);
+  test(E5::a, -1);
+  test(E6::c, __LONG_MAX__);
+}
Index: testsuite/g++.dg/ext/underlying_type4.C
===================================================================
--- testsuite/g++.dg/ext/underlying_type4.C	(revision 0)
+++ testsuite/g++.dg/ext/underlying_type4.C	(revision 0)
@@ -0,0 +1,25 @@ 
+// { dg-do compile }
+
+#include <tr1/type_traits>
+
+using namespace std::tr1;
+
+enum E1 { };
+enum E2 { a = -1, b = 1 };
+enum E3 { c = __LONG_MAX__ };
+
+typedef __underlying_type(E1) UTE1;
+typedef __underlying_type(E2) UTE2;
+typedef __underlying_type(E3) UTE3;
+
+template<typename T>
+  struct underlying_type
+  { typedef __underlying_type(T) type; };
+
+int test1[is_same<underlying_type<E1>::type, UTE1>::value ? 1 : -1];
+int test2[is_same<underlying_type<E2>::type, UTE2>::value ? 1 : -1];
+int test3[is_same<underlying_type<E3>::type, UTE3>::value ? 1 : -1];
+
+int test4[is_integral<underlying_type<E1>::type>::value ? 1 : -1];
+int test5[is_integral<underlying_type<E2>::type>::value ? 1 : -1];
+int test6[is_integral<underlying_type<E3>::type>::value ? 1 : -1];
Index: cp/typeck.c
===================================================================
--- cp/typeck.c	(revision 172932)
+++ cp/typeck.c	(working copy)
@@ -1331,6 +1331,10 @@  structural_comptypes (tree t1, tree t2, int strict
         return false;
       break;
 
+    case UNDERLYING_TYPE:
+      return same_type_p (UNDERLYING_TYPE_TYPE (t1), 
+			  UNDERLYING_TYPE_TYPE (t2));
+
     default:
       return false;
     }
Index: cp/error.c
===================================================================
--- cp/error.c	(revision 172932)
+++ cp/error.c	(working copy)
@@ -1,7 +1,8 @@ 
 /* Call-backs for C++ error reporting.
    This code is non-reentrant.
    Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   Free Software Foundation, Inc.
    This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
@@ -483,6 +484,14 @@  dump_type (tree t, int flags)
       pp_cxx_right_paren (cxx_pp);
       break;
 
+    case UNDERLYING_TYPE:
+      pp_cxx_ws_string (cxx_pp, "__underlying_type");
+      pp_cxx_whitespace (cxx_pp);
+      pp_cxx_left_paren (cxx_pp);
+      dump_expr (UNDERLYING_TYPE_TYPE (t), flags & ~TFF_EXPR_IN_PARENS);
+      pp_cxx_right_paren (cxx_pp);
+      break;
+
     case TYPE_PACK_EXPANSION:
       dump_type (PACK_EXPANSION_PATTERN (t), flags);
       pp_cxx_ws_string (cxx_pp, "...");
@@ -731,6 +740,7 @@  dump_type_prefix (tree t, int flags)
     case COMPLEX_TYPE:
     case VECTOR_TYPE:
     case TYPEOF_TYPE:
+    case UNDERLYING_TYPE:
     case DECLTYPE_TYPE:
     case TYPE_PACK_EXPANSION:
     case FIXED_POINT_TYPE:
@@ -834,6 +844,7 @@  dump_type_suffix (tree t, int flags)
     case COMPLEX_TYPE:
     case VECTOR_TYPE:
     case TYPEOF_TYPE:
+    case UNDERLYING_TYPE:
     case DECLTYPE_TYPE:
     case TYPE_PACK_EXPANSION:
     case FIXED_POINT_TYPE:
Index: cp/tree.c
===================================================================
--- cp/tree.c	(revision 172932)
+++ cp/tree.c	(working copy)
@@ -2831,6 +2831,7 @@  cp_walk_subtrees (tree *tp, int *walk_subtrees_p,
     case TEMPLATE_TYPE_PARM:
     case TYPENAME_TYPE:
     case TYPEOF_TYPE:
+    case UNDERLYING_TYPE:
       /* None of these have subtrees other than those already walked
 	 above.  */
       *walk_subtrees_p = 0;
Index: cp/cxx-pretty-print.c
===================================================================
--- cp/cxx-pretty-print.c	(revision 172932)
+++ cp/cxx-pretty-print.c	(working copy)
@@ -1,6 +1,6 @@ 
 /* Implementation of subroutines for the GNU C++ pretty-printer.
    Copyright (C) 2003, 2004, 2005, 2007, 2008,
-   2009, 2010 Free Software Foundation, Inc.
+   2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
 
 This file is part of GCC.
@@ -1694,6 +1694,7 @@  pp_cxx_type_id (cxx_pretty_printer *pp, tree t)
     case TEMPLATE_PARM_INDEX:
     case TEMPLATE_DECL:
     case TYPEOF_TYPE:
+    case UNDERLYING_TYPE:
     case DECLTYPE_TYPE:
     case TEMPLATE_ID_EXPR:
       pp_cxx_type_specifier_seq (pp, t);
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 172932)
+++ cp/pt.c	(working copy)
@@ -7255,6 +7255,7 @@  for_each_template_parm_r (tree *tp, int *walk_subt
       break;
 
     case TYPEOF_TYPE:
+    case UNDERLYING_TYPE:
       if (pfd->include_nondeduced_p
 	  && for_each_template_parm (TYPE_FIELDS (t), fn, data,
 				     pfd->visited, 
@@ -11032,6 +11033,13 @@  tsubst (tree t, tree args, tsubst_flags_t complain
 					     complain);
       }
 
+    case UNDERLYING_TYPE:
+      {
+	tree type = tsubst (UNDERLYING_TYPE_TYPE (t), args,
+			    complain, in_decl);
+	return finish_underlying_type (type);
+      }
+
     case TYPE_ARGUMENT_PACK:
     case NONTYPE_ARGUMENT_PACK:
       {
@@ -15692,8 +15700,9 @@  unify (tree tparms, tree targs, tree parm, tree ar
 
     case TYPEOF_TYPE:
     case DECLTYPE_TYPE:
-      /* Cannot deduce anything from TYPEOF_TYPE or DECLTYPE_TYPE
-         nodes.  */
+    case UNDERLYING_TYPE:
+      /* Cannot deduce anything from TYPEOF_TYPE, DECLTYPE_TYPE,
+	 or UNDERLYING_TYPE nodes.  */
       return 0;
 
     case ERROR_MARK:
@@ -17952,11 +17961,12 @@  dependent_type_p_r (tree type)
 	       (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)))))
     return true;
 
-  /* All TYPEOF_TYPEs and DECLTYPE_TYPEs are dependent; if the
-     argument of the `typeof' expression is not type-dependent, then
-     it should already been have resolved.  */
+  /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and UNDERLYING_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) == DECLTYPE_TYPE
+      || TREE_CODE (type) == UNDERLYING_TYPE)
     return true;
 
   /* A template argument pack is dependent if any of its packed
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 172932)
+++ cp/semantics.c	(working copy)
@@ -3366,6 +3366,44 @@  finish_typeof (tree expr)
   return type;
 }
 
+/* Implement the __underlying_type keyword: Return the underlying
+   type of TYPE, suitable for use as a type-specifier.  */
+
+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;
+    }
+
+  complete_type (type);
+
+  if (TREE_CODE (type) != ENUMERAL_TYPE)
+    {
+      error ("%qE is not an enumeration type", type);
+      return error_mark_node;
+    }
+
+  underlying_type = ENUM_UNDERLYING_TYPE (type);
+
+  /* Fixup necessary in this case because ENUM_UNDERLYING_TYPE
+     includes TYPE_MIN_VALUE and TYPE_MAX_VALUE information.
+     See finish_enum_value_list for details.  */
+  if (!ENUM_FIXED_UNDERLYING_TYPE_P (type))
+    underlying_type
+      = c_common_type_for_mode (TYPE_MODE (underlying_type),
+				TYPE_UNSIGNED (underlying_type));
+
+  return underlying_type;
+}
+
 /* Perform C++-specific checks for __builtin_offsetof before calling
    fold_offsetof.  */
 
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 172932)
+++ cp/parser.c	(working copy)
@@ -1,6 +1,6 @@ 
 /* C++ Parser.
    Copyright (C) 2000, 2001, 2002, 2003, 2004,
-   2005, 2007, 2008, 2009, 2010  Free Software Foundation, Inc.
+   2005, 2007, 2008, 2009, 2010, 2011  Free Software Foundation, Inc.
    Written by Mark Mitchell <mark@codesourcery.com>.
 
    This file is part of GCC.
@@ -654,6 +654,7 @@  cp_lexer_next_token_is_decl_specifier_keyword (cp_
     case RID_TYPEOF:
       /* C++0x extensions.  */
     case RID_DECLTYPE:
+    case RID_UNDERLYING_TYPE:
       return true;
 
     default:
@@ -7129,8 +7130,11 @@  cp_parser_builtin_offsetof (cp_parser *parser)
   return expr;
 }
 
-/* Parse a trait expression.  */
+/* Parse a trait expression.
 
+   Returns a representation of the expression, the underyling type
+   of the type at issue when KEYWORD is RID_UNDERLYING_TYPE.  */
+
 static tree
 cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
 {
@@ -7185,6 +7189,9 @@  cp_parser_trait_expr (cp_parser* parser, enum rid
     case RID_IS_ENUM:
       kind = CPTK_IS_ENUM;
       break;
+    case RID_IS_LITERAL_TYPE:
+      kind = CPTK_IS_LITERAL_TYPE;
+      break;
     case RID_IS_POD:
       kind = CPTK_IS_POD;
       break;
@@ -7200,8 +7207,8 @@  cp_parser_trait_expr (cp_parser* parser, enum rid
     case RID_IS_UNION:
       kind = CPTK_IS_UNION;
       break;
-    case RID_IS_LITERAL_TYPE:
-      kind = CPTK_IS_LITERAL_TYPE;
+    case RID_UNDERLYING_TYPE:
+      kind = CPTK_UNDERLYING_TYPE;
       break;
     default:
       gcc_unreachable ();
@@ -7247,7 +7254,9 @@  cp_parser_trait_expr (cp_parser* parser, enum rid
 
   /* Complete the trait expression, which may mean either processing
      the trait expr now or saving it for template instantiation.  */
-  return finish_trait_expr (kind, type1, type2);
+  return kind != CPTK_UNDERLYING_TYPE
+    ? finish_trait_expr (kind, type1, type2)
+    : finish_underlying_type (type1);
 }
 
 /* Lambdas that appear in variable initializer or default argument scope
@@ -12505,6 +12514,7 @@  cp_parser_type_specifier (cp_parser* parser,
      decltype ( expression )   
      char16_t
      char32_t
+     __underlying_type ( type-id )
 
    GNU Extension:
 
@@ -12621,6 +12631,16 @@  cp_parser_simple_type_specifier (cp_parser* parser
 
       return type;
 
+    case RID_UNDERLYING_TYPE:
+      type = cp_parser_trait_expr (parser, RID_UNDERLYING_TYPE);
+
+      if (decl_specs)
+	cp_parser_set_decl_spec_type (decl_specs, type,
+				      token->location,
+				      /*user_defined_p=*/true);
+
+      return type;
+
     default:
       break;
     }
Index: cp/cp-tree.def
===================================================================
--- cp/cp-tree.def	(revision 172932)
+++ cp/cp-tree.def	(working copy)
@@ -2,7 +2,7 @@ 
    additional tree codes used in the GNU C++ compiler (see tree.def
    for the standard codes).
    Copyright (C) 1987, 1988, 1990, 1993, 1997, 1998, 2003, 2004, 2005,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2010
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2010, 2011
    Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
@@ -450,6 +450,10 @@  DEFTREECODE (LAMBDA_EXPR, "lambda_expr", tcc_excep
    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)
+
 /* Used to represent the template information stored by template
    specializations.
    The accessors are:
Index: cp/cp-objcp-common.c
===================================================================
--- cp/cp-objcp-common.c	(revision 172932)
+++ cp/cp-objcp-common.c	(working copy)
@@ -238,6 +238,7 @@  cp_common_init_ts (void)
   MARK_TS_COMMON (TEMPLATE_INFO);
   MARK_TS_COMMON (TYPENAME_TYPE);
   MARK_TS_COMMON (TYPEOF_TYPE);
+  MARK_TS_COMMON (UNDERLYING_TYPE);
   MARK_TS_COMMON (BASELINK);
   MARK_TS_COMMON (TYPE_PACK_EXPANSION);
   MARK_TS_COMMON (EXPR_PACK_EXPANSION);
Index: cp/mangle.c
===================================================================
--- cp/mangle.c	(revision 172932)
+++ cp/mangle.c	(working copy)
@@ -1991,6 +1991,10 @@  write_type (tree type)
 	      sorry ("mangling typeof, use decltype instead");
 	      break;
 
+	    case UNDERLYING_TYPE:
+	      sorry ("mangling __underlying_type");
+	      break;
+
 	    case LANG_TYPE:
 	      /* fall through.  */
 
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 172932)
+++ cp/cp-tree.h	(working copy)
@@ -556,12 +556,13 @@  typedef enum cp_trait_kind
   CPTK_IS_CONVERTIBLE_TO,
   CPTK_IS_EMPTY,
   CPTK_IS_ENUM,
+  CPTK_IS_LITERAL_TYPE,
   CPTK_IS_POD,
   CPTK_IS_POLYMORPHIC,
   CPTK_IS_STD_LAYOUT,
   CPTK_IS_TRIVIAL,
-  CPTK_IS_LITERAL_TYPE,
-  CPTK_IS_UNION
+  CPTK_IS_UNION,
+  CPTK_UNDERLYING_TYPE
 } cp_trait_kind;
 
 /* The types that we are processing.  */
@@ -3360,6 +3361,10 @@  more_aggr_init_expr_args_p (const aggr_init_expr_a
 /* The expression in question for a TYPEOF_TYPE.  */
 #define TYPEOF_TYPE_EXPR(NODE) (TYPEOF_TYPE_CHECK (NODE))->type.values
 
+/* The type in question for an UNDERLYING_TYPE.  */
+#define UNDERLYING_TYPE_TYPE(NODE) \
+  (UNDERLYING_TYPE_CHECK (NODE))->type.values
+
 /* The expression in question for a DECLTYPE_TYPE.  */
 #define DECLTYPE_TYPE_EXPR(NODE) (DECLTYPE_TYPE_CHECK (NODE))->type.values
 
@@ -5320,6 +5325,7 @@  extern tree finish_id_expression		(tree, tree, tre
 						 const char **,
                                                  location_t);
 extern tree finish_typeof			(tree);
+extern tree finish_underlying_type	        (tree);
 extern tree finish_offsetof			(tree);
 extern void finish_decl_cleanup			(tree, tree);
 extern void finish_eh_cleanup			(tree);