From f6945c41cc9a66590ea92a1d0d7c862d14ccd23c Mon Sep 17 00:00:00 2001 From: jason Date: Wed, 25 May 2011 20:30:21 +0000 Subject: [PATCH] PR c++/44311 * decl.c (case_conversion): New. (finish_case_label): Use it. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_6-branch@174237 138bc75d-0d04-0410-961f-82ee72b054a4 index cc7a155..de53541 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2920,6 +2920,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. */ @@ -2928,6 +2950,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) { @@ -2947,13 +2970,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 new file mode 100644 index 0000000..55cf2ad --- /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 0000000..d653216 --- /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; + } +} -- 1.7.0.4