From de69121325ce8e05adb106c87acaeadf1bba61e0 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 25 May 2011 16:02:41 -0400 Subject: [PATCH] re PR c++/44311 ([C++0x] no error with switch over enum class and integer case) PR c++/44311 * decl.c (case_conversion): New. (finish_case_label): Use it. From-SVN: r174231 --- gcc/cp/ChangeLog | 4 +++ gcc/cp/decl.c | 34 +++++++++++++++---- gcc/testsuite/ChangeLog | 3 ++ .../g++.dg/cpp0x/constexpr-switch2.C | 23 +++++++++++++ gcc/testsuite/g++.dg/cpp0x/enum15.C | 20 +++++++++++ 5 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-switch2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/enum15.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c0677ccf55d..1b611936af4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2011-05-25 Jason Merrill + PR c++/44311 + * decl.c (case_conversion): New. + (finish_case_label): Use it. + * ptree.c (cxx_print_xnode): Handle ARGUMENT_PACK_SELECT. PR c++/45698 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 2b6a7770e2d..7fc194554b9 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2957,6 +2957,28 @@ pop_switch (void) free (cs); } +/* Convert a case constant VALUE in a switch to the type TYPE of the switch + condition. Note that if TYPE and VALUE are already integral we don't + really do the conversion because the language-independent + warning/optimization code will work better that way. */ + +static tree +case_conversion (tree type, tree value) +{ + if (value == NULL_TREE) + return value; + + if (cxx_dialect >= cxx0x + && (SCOPED_ENUM_P (type) + || !INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (value)))) + { + if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type)) + type = type_promotes_to (type); + value = perform_implicit_conversion (type, value, tf_warning_or_error); + } + return cxx_constant_value (value); +} + /* Note that we've seen a definition of a case label, and complain if this is a bad place for one. */ @@ -2965,6 +2987,7 @@ finish_case_label (location_t loc, tree low_value, tree high_value) { tree cond, r; struct cp_binding_level *p; + tree type; if (processing_template_decl) { @@ -2984,13 +3007,12 @@ finish_case_label (location_t loc, tree low_value, tree high_value) if (!check_switch_goto (switch_stack->level)) return error_mark_node; - if (low_value) - low_value = cxx_constant_value (low_value); - if (high_value) - high_value = cxx_constant_value (high_value); + type = SWITCH_STMT_TYPE (switch_stack->switch_stmt); + + low_value = case_conversion (type, low_value); + high_value = case_conversion (type, high_value); - r = c_add_case_label (loc, switch_stack->cases, cond, - SWITCH_STMT_TYPE (switch_stack->switch_stmt), + r = c_add_case_label (loc, switch_stack->cases, cond, type, low_value, high_value); /* After labels, make any new cleanups in the function go into their diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2a30f6e8bbc..e8a335ff813 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2011-05-25 Jason Merrill + * g++.dg/cpp0x/enum15.C: New. + * g++.dg/cpp0x/constexpr-switch2.C: New. + * g++.dg/cpp0x/variadic110.C: New. * g++.dg/cpp0x/auto9.C: Add typedef test. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-switch2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-switch2.C new file mode 100644 index 00000000000..55cf2ad7ce8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-switch2.C @@ -0,0 +1,23 @@ +// Test for constexpr conversion in case context +// { dg-options -std=c++0x } + +enum class E { e1, e2 }; + +struct A +{ + E e; + constexpr operator E() { return e; } + constexpr A(E e): e(e) { } +}; + +E e; + +int main() +{ + switch (e) + { + case A(E::e1): + case A(E::e2): + ; + } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/enum15.C b/gcc/testsuite/g++.dg/cpp0x/enum15.C new file mode 100644 index 00000000000..d653216498e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/enum15.C @@ -0,0 +1,20 @@ +// PR c++/44311 +// { dg-options -std=c++0x } + +enum class A { Val0, Val1 }; + +void foo (A a, int i) +{ + switch (a) + { + case A::Val0: break; + case 1: break; // { dg-error "" } + } + + switch (i) + { + case A::Val0: break; // { dg-error "" } + case 1: break; + case 2.0: break; + } +} -- 2.30.2