aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2011-05-25 16:02:41 -0400
committerJason Merrill <jason@gcc.gnu.org>2011-05-25 16:02:41 -0400
commitde69121325ce8e05adb106c87acaeadf1bba61e0 (patch)
treef31e62ba5d84a403470febb8740f225d5c3578b9 /gcc
parentf03a54024372021a572dd23893982ef2ba0e941e (diff)
downloadgcc-de69121325ce8e05adb106c87acaeadf1bba61e0.zip
gcc-de69121325ce8e05adb106c87acaeadf1bba61e0.tar.gz
gcc-de69121325ce8e05adb106c87acaeadf1bba61e0.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/decl.c34
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-switch2.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/enum15.C20
5 files changed, 78 insertions, 6 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index c0677cc..1b61193 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,9 @@
2011-05-25 Jason Merrill <jason@redhat.com>
+ 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 2b6a777..7fc1945 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 2a30f6e..e8a335f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,8 @@
2011-05-25 Jason Merrill <jason@redhat.com>
+ * 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 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;
+ }
+}