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.carl...@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.carl...@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.carl...@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.
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 <g...@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 <m...@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 (tiem...@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);