summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/gcc/gcc-4.6.0/gcc-4_6-branch-backports/0342-PR-c-44311.patch
blob: 6ebd5118697b85fa313d07d8f8c1243a3f77ecf3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
From f6945c41cc9a66590ea92a1d0d7c862d14ccd23c Mon Sep 17 00:00:00 2001
From: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
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