+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.
+
2011-04-25 Segher Boessenkool <segher@kernel.crashing.org>
* config/rs6000/titan.md (automata_option "progress"): Remove.
{ "__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 },
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,
+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.
+
2011-04-25 Jason Merrill <jason@redhat.com>
PR c++/48707
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);
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)
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:
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. */
/* 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
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);
/* 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.
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);
/* 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
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, "...");
case COMPLEX_TYPE:
case VECTOR_TYPE:
case TYPEOF_TYPE:
+ case UNDERLYING_TYPE:
case DECLTYPE_TYPE:
case TYPE_PACK_EXPANSION:
case FIXED_POINT_TYPE:
case COMPLEX_TYPE:
case VECTOR_TYPE:
case TYPEOF_TYPE:
+ case UNDERLYING_TYPE:
case DECLTYPE_TYPE:
case TYPE_PACK_EXPANSION:
case FIXED_POINT_TYPE:
sorry ("mangling typeof, use decltype instead");
break;
+ case UNDERLYING_TYPE:
+ sorry ("mangling __underlying_type");
+ break;
+
case LANG_TYPE:
/* fall through. */
/* 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.
case RID_TYPEOF:
/* C++0x extensions. */
case RID_DECLTYPE:
+ case RID_UNDERLYING_TYPE:
return true;
default:
return expr;
}
-/* Parse a trait expression. */
+/* Parse a trait expression.
+
+ Returns a representation of the expression, the underlying type
+ of the type at issue when KEYWORD is RID_UNDERLYING_TYPE. */
static tree
cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
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;
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 ();
/* 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
decltype ( expression )
char16_t
char32_t
+ __underlying_type ( type-id )
GNU Extension:
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;
}
break;
case TYPEOF_TYPE:
+ case UNDERLYING_TYPE:
if (pfd->include_nondeduced_p
&& for_each_template_parm (TYPE_FIELDS (t), fn, data,
pfd->visited,
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:
{
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:
(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
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. */
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;
return false;
break;
+ case UNDERLYING_TYPE:
+ return same_type_p (UNDERLYING_TYPE_TYPE (t1),
+ UNDERLYING_TYPE_TYPE (t2));
+
default:
return false;
}
+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.
+
2011-04-25 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/regress/template-const2.C: New.
--- /dev/null
+// { 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;
--- /dev/null
+// { 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__);
+}
--- /dev/null
+// { 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__;
--- /dev/null
+// { 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");
--- /dev/null
+// { 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];
--- /dev/null
+// { 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");
--- /dev/null
+// { 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>;
--- /dev/null
+// { 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__);
+}
--- /dev/null
+// { 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__);
+}
--- /dev/null
+// { 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;