On Tue, 29 Oct 2024, Jakub Jelinek wrote:
> Hi!
>
> The following patch adds the C2Y N3370 paper support.
> We had the case ranges as a GNU extension for decades, so this patch
> simply:
> 1) adds different diagnostics when it is used in C (depending on flag_isoc2y
> and pedantic and warn_c23_c2y_compat)
> 2) emits a pedwarn in C if in a range conversion changes the value of
> the low or high bounds and in that case doesn't emit -Woverflow and
> similar warnings anymore if the pedwarn has been diagnosed
> 3) changes the handling of empty ranges both in C and C++; previously
> we just warned but let the values be still looked up in the splay
> tree/entered into it (and let only gimplification throw away those
> empty cases), so e.g. case -6 ... -8: break; case -6: break;
> complained about duplicate case label. But that actually isn't
> duplicate case label, case -6 ... -8: stands for nothing at all
> and that is how it is treated later on (thrown away)
>
> Older version has been bootstrapped/regtested on x86_64-linux and i686-linux
> successfully (without the last hunk in c_add_case_label and some of testcase
> additions), ok for trunk if even this updated patch passes
> bootstrap/regtest?
OK.
@@ -5186,13 +5186,41 @@ c_add_case_label (location_t loc, splay_
/* Case ranges are a GNU extension. */
if (high_value)
- pedwarn (loc, OPT_Wpedantic,
- "range expressions in switch statements are non-standard");
+ {
+ if (c_dialect_cxx ())
+ pedwarn (loc, OPT_Wpedantic,
+ "range expressions in switch statements are non-standard");
+ else if (warn_c23_c2y_compat > 0)
+ {
+ if (pedantic && !flag_isoc2y)
+ pedwarn (loc, OPT_Wc23_c2y_compat,
+ "ISO C does not support range expressions in switch "
+ "statements before C2Y");
+ else
+ warning_at (loc, OPT_Wc23_c2y_compat,
+ "ISO C does not support range expressions in switch "
+ "statements before C2Y");
+ }
+ else if (warn_c23_c2y_compat && pedantic && !flag_isoc2y)
+ pedwarn (loc, OPT_Wpedantic,
+ "ISO C does not support range expressions in switch "
+ "statements before C2Y");
+ }
type = TREE_TYPE (cond);
if (low_value)
{
low_value = check_case_value (loc, low_value);
+ tree tem = NULL_TREE;
+ if (high_value
+ && !c_dialect_cxx ()
+ && low_value != error_mark_node
+ && !int_fits_type_p (low_value, type)
+ && pedwarn (loc, OPT_Wpedantic,
+ "conversion of %qE to %qT in range expression changes "
+ "value to %qE", low_value, type,
+ (tem = fold_convert (type, low_value))))
+ low_value = tem;
low_value = convert_and_check (loc, type, low_value);
low_value = fold (low_value);
if (low_value == error_mark_node)
@@ -5201,6 +5229,15 @@ c_add_case_label (location_t loc, splay_
if (high_value)
{
high_value = check_case_value (loc, high_value);
+ tree tem = NULL_TREE;
+ if (!c_dialect_cxx ()
+ && high_value != error_mark_node
+ && !int_fits_type_p (high_value, type)
+ && pedwarn (loc, OPT_Wpedantic,
+ "conversion of %qE to %qT in range expression changes "
+ "value to %qE", high_value, type,
+ (tem = fold_convert (type, high_value))))
+ high_value = tem;
high_value = convert_and_check (loc, type, high_value);
high_value = fold (high_value);
if (high_value == error_mark_node)
@@ -5215,7 +5252,10 @@ c_add_case_label (location_t loc, splay_
if (tree_int_cst_equal (low_value, high_value))
high_value = NULL_TREE;
else if (!tree_int_cst_lt (low_value, high_value))
- warning_at (loc, 0, "empty range specified");
+ {
+ warning_at (loc, 0, "empty range specified");
+ goto error_out;
+ }
}
/* Look up the LOW_VALUE in the table of case labels we already
@@ -2,13 +2,13 @@
for case ranges with -pedantic. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
-/* { dg-options "-pedantic" } */
+/* { dg-options "-pedantic -std=gnu23" } */
void
f (int a)
{
switch (a)
{
- case 0 ... 0: ; /* { dg-warning "range expressions in switch statements are non-standard" } */
+ case 0 ... 0: ; /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
}
}
@@ -2,13 +2,13 @@
for case ranges with -pedantic-errors. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
-/* { dg-options "-pedantic-errors" } */
+/* { dg-options "-pedantic-errors -std=c23" } */
void
f (int a)
{
switch (a)
{
- case 0 ... 0: ; /* { dg-error "range expressions in switch statements are non-standard" } */
+ case 0 ... 0: ; /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
}
}
@@ -0,0 +1,100 @@
+/* C2Y N3370 - Case range expressions. */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu23 -pedantic -W -Wall" } */
+
+enum E { F = 10, G = 20 };
+
+void
+foo (unsigned x)
+{
+ switch (x)
+ {
+ case -1:
+ break;
+ case ~0U + 1ULL: /* { dg-warning "conversion from 'long long unsigned int' to 'unsigned int' changes value from '\[0-9]*' to '0'" } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+bar (unsigned x)
+{
+ switch (x)
+ {
+ case -2 ... -1: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "conversion of '-2' to 'unsigned int' in range expression changes value to '\[0-9]*'" "" { target *-*-* } .-1 } */
+ /* { dg-warning "conversion of '-1' to 'unsigned int' in range expression changes value to '\[0-9]*'" "" { target *-*-* } .-2 } */
+ break;
+ case ~0U + 1ULL ... ~0U + 2ULL: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '0'" "" { target *-*-* } .-1 } */
+ /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '1'" "" { target *-*-* } .-2 } */
+ break;
+ case 70 ... 70: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ break;
+ case 80 ... 78: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -4 ... -4: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "conversion of '-4' to 'unsigned int' in range expression changes value to '\[0-9]*'" "" { target *-*-* } .-1 } */
+ break;
+ case ~0U + 6ULL ... ~0U + 6ULL: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '5'" "" { target *-*-* } .-1 } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+baz (unsigned char x)
+{
+ switch (x)
+ {
+ case -32 ... -30: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "case label value is less than minimum value for type" "" { target *-*-* } .-1 } */
+ break;
+ case -31: /* { dg-error "duplicate case value" } */
+ break;
+ case -42: /* { dg-warning "case label value is less than minimum value for type" } */
+ break;
+ case -43 ... -41: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-error "duplicate \\\(or overlapping\\\) case value" "" { target *-*-* } .-1 } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+qux (int x)
+{
+ switch (x)
+ {
+ case -6 ... -8: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -6:
+ break;
+ case -7:
+ break;
+ case -8:
+ break;
+ case F...G: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ break;
+ case -10:
+ break;
+ case -10 ... -11: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -14 ... -15: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -14 ... -15: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ default:
+ break;
+ }
+}
@@ -0,0 +1,89 @@
+/* C2Y N3370 - Case range expressions. */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu23 -pedantic -W -Wall -Wno-c23-c2y-compat" } */
+
+enum E { F = 10, G = 20 };
+
+void
+foo (unsigned x)
+{
+ switch (x)
+ {
+ case -1:
+ break;
+ case ~0U + 1ULL: /* { dg-warning "conversion from 'long long unsigned int' to 'unsigned int' changes value from '\[0-9]*' to '0'" } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+bar (unsigned x)
+{
+ switch (x)
+ {
+ case -2 ... -1: /* { dg-warning "conversion of '-2' to 'unsigned int' in range expression changes value to '\[0-9]*'" } */
+ /* { dg-warning "conversion of '-1' to 'unsigned int' in range expression changes value to '\[0-9]*'" "" { target *-*-* } .-1 } */
+ break;
+ case ~0U + 1ULL ... ~0U + 2ULL: /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '0'" } */
+ /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '1'" "" { target *-*-* } .-1 } */
+ break;
+ case 70 ... 70:
+ break;
+ case 80 ... 78: /* { dg-warning "empty range specified" } */
+ break;
+ case -4 ... -4: /* { dg-warning "conversion of '-4' to 'unsigned int' in range expression changes value to '\[0-9]*'" } */
+ break;
+ case ~0U + 6ULL ... ~0U + 6ULL: /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '5'" } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+baz (unsigned char x)
+{
+ switch (x)
+ {
+ case -32 ... -30: /* { dg-warning "case label value is less than minimum value for type" } */
+ break;
+ case -31: /* { dg-error "duplicate case value" } */
+ break;
+ case -42: /* { dg-warning "case label value is less than minimum value for type" } */
+ break;
+ case -43 ... -41: /* { dg-error "duplicate \\\(or overlapping\\\) case value" } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+qux (int x)
+{
+ switch (x)
+ {
+ case -6 ... -8: /* { dg-warning "empty range specified" } */
+ break;
+ case -6:
+ break;
+ case -7:
+ break;
+ case -8:
+ break;
+ case F...G:
+ break;
+ case -10:
+ break;
+ case -10 ... -11: /* { dg-warning "empty range specified" } */
+ break;
+ case -14 ... -15: /* { dg-warning "empty range specified" } */
+ break;
+ case -14 ... -15: /* { dg-warning "empty range specified" } */
+ break;
+ default:
+ break;
+ }
+}
@@ -0,0 +1,100 @@
+/* C2Y N3370 - Case range expressions. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -W -Wall" } */
+
+enum E { F = 10, G = 20 };
+
+void
+foo (unsigned x)
+{
+ switch (x)
+ {
+ case -1:
+ break;
+ case ~0U + 1ULL: /* { dg-warning "conversion from 'long long unsigned int' to 'unsigned int' changes value from '\[0-9]*' to '0'" } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+bar (unsigned x)
+{
+ switch (x)
+ {
+ case -2 ... -1: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-error "conversion of '-2' to 'unsigned int' in range expression changes value to '\[0-9]*'" "" { target *-*-* } .-1 } */
+ /* { dg-error "conversion of '-1' to 'unsigned int' in range expression changes value to '\[0-9]*'" "" { target *-*-* } .-2 } */
+ break;
+ case ~0U + 1ULL ... ~0U + 2ULL: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-error "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '0'" "" { target *-*-* } .-1 } */
+ /* { dg-error "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '1'" "" { target *-*-* } .-2 } */
+ break;
+ case 70 ... 70: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ break;
+ case 80 ... 78: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -4 ... -4: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-error "conversion of '-4' to 'unsigned int' in range expression changes value to '\[0-9]*'" "" { target *-*-* } .-1 } */
+ break;
+ case ~0U + 6ULL ... ~0U + 6ULL: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-error "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '5'" "" { target *-*-* } .-1 } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+baz (unsigned char x)
+{
+ switch (x)
+ {
+ case -32 ... -30: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "case label value is less than minimum value for type" "" { target *-*-* } .-1 } */
+ break;
+ case -31: /* { dg-error "duplicate case value" } */
+ break;
+ case -42: /* { dg-warning "case label value is less than minimum value for type" } */
+ break;
+ case -43 ... -41: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-error "duplicate \\\(or overlapping\\\) case value" "" { target *-*-* } .-1 } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+qux (int x)
+{
+ switch (x)
+ {
+ case -6 ... -8: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -6:
+ break;
+ case -7:
+ break;
+ case -8:
+ break;
+ case F...G: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ break;
+ case -10:
+ break;
+ case -10 ... -11: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -14 ... -15: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -14 ... -15: /* { dg-error "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ default:
+ break;
+ }
+}
@@ -0,0 +1,89 @@
+/* C2Y N3370 - Case range expressions. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic -W -Wall" } */
+
+enum E { F = 10, G = 20 };
+
+void
+foo (unsigned x)
+{
+ switch (x)
+ {
+ case -1:
+ break;
+ case ~0U + 1ULL: /* { dg-warning "conversion from 'long long unsigned int' to 'unsigned int' changes value from '\[0-9]*' to '0'" } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+bar (unsigned x)
+{
+ switch (x)
+ {
+ case -2 ... -1: /* { dg-warning "conversion of '-2' to 'unsigned int' in range expression changes value to '\[0-9]*'" } */
+ /* { dg-warning "conversion of '-1' to 'unsigned int' in range expression changes value to '\[0-9]*'" "" { target *-*-* } .-1 } */
+ break;
+ case ~0U + 1ULL ... ~0U + 2ULL: /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '0'" } */
+ /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '1'" "" { target *-*-* } .-1 } */
+ break;
+ case 70 ... 70:
+ break;
+ case 80 ... 78: /* { dg-warning "empty range specified" } */
+ break;
+ case -4 ... -4: /* { dg-warning "conversion of '-4' to 'unsigned int' in range expression changes value to '\[0-9]*'" } */
+ break;
+ case ~0U + 6ULL ... ~0U + 6ULL: /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '5'" } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+baz (unsigned char x)
+{
+ switch (x)
+ {
+ case -32 ... -30: /* { dg-warning "case label value is less than minimum value for type" } */
+ break;
+ case -31: /* { dg-error "duplicate case value" } */
+ break;
+ case -42: /* { dg-warning "case label value is less than minimum value for type" } */
+ break;
+ case -43 ... -41: /* { dg-error "duplicate \\\(or overlapping\\\) case value" } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+qux (int x)
+{
+ switch (x)
+ {
+ case -6 ... -8: /* { dg-warning "empty range specified" } */
+ break;
+ case -6:
+ break;
+ case -7:
+ break;
+ case -8:
+ break;
+ case F...G:
+ break;
+ case -10:
+ break;
+ case -10 ... -11: /* { dg-warning "empty range specified" } */
+ break;
+ case -14 ... -15: /* { dg-warning "empty range specified" } */
+ break;
+ case -14 ... -15: /* { dg-warning "empty range specified" } */
+ break;
+ default:
+ break;
+ }
+}
@@ -0,0 +1,100 @@
+/* C2Y N3370 - Case range expressions. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic -W -Wall -Wc23-c2y-compat" } */
+
+enum E { F = 10, G = 20 };
+
+void
+foo (unsigned x)
+{
+ switch (x)
+ {
+ case -1:
+ break;
+ case ~0U + 1ULL: /* { dg-warning "conversion from 'long long unsigned int' to 'unsigned int' changes value from '\[0-9]*' to '0'" } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+bar (unsigned x)
+{
+ switch (x)
+ {
+ case -2 ... -1: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "conversion of '-2' to 'unsigned int' in range expression changes value to '\[0-9]*'" "" { target *-*-* } .-1 } */
+ /* { dg-warning "conversion of '-1' to 'unsigned int' in range expression changes value to '\[0-9]*'" "" { target *-*-* } .-2 } */
+ break;
+ case ~0U + 1ULL ... ~0U + 2ULL: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '0'" "" { target *-*-* } .-1 } */
+ /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '1'" "" { target *-*-* } .-2 } */
+ break;
+ case 70 ... 70: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ break;
+ case 80 ... 78: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -4 ... -4: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "conversion of '-4' to 'unsigned int' in range expression changes value to '\[0-9]*'" "" { target *-*-* } .-1 } */
+ break;
+ case ~0U + 6ULL ... ~0U + 6ULL: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "conversion of '\[0-9]*' to 'unsigned int' in range expression changes value to '5'" "" { target *-*-* } .-1 } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+baz (unsigned char x)
+{
+ switch (x)
+ {
+ case -32 ... -30: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "case label value is less than minimum value for type" "" { target *-*-* } .-1 } */
+ break;
+ case -31: /* { dg-error "duplicate case value" } */
+ break;
+ case -42: /* { dg-warning "case label value is less than minimum value for type" } */
+ break;
+ case -43 ... -41: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-error "duplicate \\\(or overlapping\\\) case value" "" { target *-*-* } .-1 } */
+ break;
+ default:
+ break;
+ }
+}
+
+void
+qux (int x)
+{
+ switch (x)
+ {
+ case -6 ... -8: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -6:
+ break;
+ case -7:
+ break;
+ case -8:
+ break;
+ case F...G: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ break;
+ case -10:
+ break;
+ case -10 ... -11: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -14 ... -15: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ case -14 ... -15: /* { dg-warning "ISO C does not support range expressions in switch statements before C2Y" } */
+ /* { dg-warning "empty range specified" "" { target *-*-* } .-1 } */
+ break;
+ default:
+ break;
+ }
+}
@@ -0,0 +1,40 @@
+/* C2Y N3370 - Case range expressions. */
+/* { dg-do run } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+extern void abort ();
+
+void
+foo (int x)
+{
+ switch (x)
+ {
+ case -42 ... 42:
+ if (x < -42 || x > 42)
+ abort ();
+ break;
+ case 43 ... 43:
+ if (x != 43)
+ abort ();
+ break;
+ case 44:
+ if (x != 44)
+ abort ();
+ break;
+ case 45 ... 46:
+ if (x < 45 || x > 46)
+ abort ();
+ break;
+ default:
+ if (x >= -42 && x <= 46)
+ abort ();
+ break;
+ }
+}
+
+int
+main ()
+{
+ for (int i = -44; i <= 48; ++i)
+ foo (i);
+}