Skip to content

Commit 3d0b283

Browse files
authored
[C2y] Add test coverage for WG14 N3370 (llvm#115054)
This paper added case ranges in switch statements, which is a GNU extension Clang has supported since at least Clang 3.0. It updates the diagnostics to no longer call this a GNU extension except in C++ mode.
1 parent 9470945 commit 3d0b283

File tree

6 files changed

+130
-18
lines changed

6 files changed

+130
-18
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,12 @@ C Language Changes
274274
C2y Feature Support
275275
^^^^^^^^^^^^^^^^^^^
276276

277+
- Clang updated conformance for `N3370 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3370.htm>`_
278+
case range expressions. This feature was previously supported by Clang as a
279+
GNU extension, so ``-Wgnu-case-range`` no longer has effect in C modes, as
280+
this is now a C2y extension in C. ``-Wgnu-case-range`` still applies in C++
281+
modes.
282+
277283
C23 Feature Support
278284
^^^^^^^^^^^^^^^^^^^
279285

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,13 @@ def err_expected_equal_designator : Error<"expected '=' or another designator">;
203203
def ext_gnu_old_style_field_designator : ExtWarn<
204204
"use of GNU old-style field designator extension">,
205205
InGroup<GNUDesignator>;
206-
def ext_gnu_case_range : Extension<"use of GNU case range extension">,
207-
InGroup<GNUCaseRange>;
206+
def ext_gnu_case_range : Extension<
207+
"case ranges are a GNU extension">, InGroup<GNUCaseRange>;
208+
def warn_c23_compat_case_range : Warning<
209+
"case ranges are incompatible with C standards before C2y">,
210+
DefaultIgnore, InGroup<CPre2yCompat>;
211+
def ext_c2y_case_range : Extension<
212+
"case ranges are a C2y extension">, InGroup<C2y>;
208213

209214
// Generic errors.
210215
def err_expected_expression : Error<"expected expression">;

clang/lib/Parse/ParseStmt.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,15 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
890890
SourceLocation DotDotDotLoc;
891891
ExprResult RHS;
892892
if (TryConsumeToken(tok::ellipsis, DotDotDotLoc)) {
893-
Diag(DotDotDotLoc, diag::ext_gnu_case_range);
893+
// In C++, this is a GNU extension. In C, it's a C2y extension.
894+
unsigned DiagId;
895+
if (getLangOpts().CPlusPlus)
896+
DiagId = diag::ext_gnu_case_range;
897+
else if (getLangOpts().C2y)
898+
DiagId = diag::warn_c23_compat_case_range;
899+
else
900+
DiagId = diag::ext_c2y_case_range;
901+
Diag(DotDotDotLoc, DiagId);
894902
RHS = ParseCaseExpression(CaseLoc);
895903
if (RHS.isInvalid()) {
896904
if (!SkipUntil(tok::colon, tok::r_brace, StopAtSemi | StopBeforeMatch))

clang/test/C/C2y/n3370.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// RUN: %clang_cc1 -verify=expected,c-expected -std=c2y -Wall -pedantic %s
2+
// RUN: %clang_cc1 -verify=expected,c-expected,ped -std=c23 -Wall -pedantic %s
3+
// RUN: %clang_cc1 -verify=expected,cxx-expected,gnu -Wall -pedantic -x c++ %s
4+
// RUN: %clang_cc1 -verify=expected,c-expected,pre -std=c2y -Wpre-c2y-compat -Wall -pedantic %s
5+
6+
/* WG14 N3370: Yes
7+
* Case range expressions v3.1
8+
*
9+
* This introduces the ability to specify closed ranges in case statements in a
10+
* switch statement. This was already a well-supported Clang extension before
11+
* it was standardized.
12+
*/
13+
14+
void correct(int i) {
15+
constexpr int j = 100, k = 200;
16+
switch (i) {
17+
case 12 ... 14: break; /* gnu-warning {{case ranges are a GNU extension}}
18+
ped-warning {{case ranges are a C2y extension}}
19+
pre-warning {{case ranges are incompatible with C standards before C2y}}
20+
*/
21+
// Implementations are encouraged to diagnose empty ranges.
22+
case 15 ... 11: break; /* expected-warning {{empty case range specified}}
23+
gnu-warning {{case ranges are a GNU extension}}
24+
ped-warning {{case ranges are a C2y extension}}
25+
pre-warning {{case ranges are incompatible with C standards before C2y}}
26+
*/
27+
// This is not an empty range, it's a range of a single value.
28+
case 10 ... 10: break; /* gnu-warning {{case ranges are a GNU extension}}
29+
ped-warning {{case ranges are a C2y extension}}
30+
pre-warning {{case ranges are incompatible with C standards before C2y}}
31+
*/
32+
case j ... k: break; /* gnu-warning {{case ranges are a GNU extension}}
33+
ped-warning {{case ranges are a C2y extension}}
34+
pre-warning {{case ranges are incompatible with C standards before C2y}}
35+
*/
36+
}
37+
}
38+
39+
void incorrect(int i) { // cxx-expected-note 2 {{declared here}}
40+
switch (i) {
41+
// The values have to be integer constant expressions. Note that when the
42+
// initial value in the range is an error, we don't issue the warnings about
43+
// extensions or incompatibility.
44+
case i ... 10: break; /* c-expected-error {{expression is not an integer constant expression}}
45+
cxx-expected-error {{case value is not a constant expression}}
46+
cxx-expected-note {{function parameter 'i' with unknown value cannot be used in a constant expression}}
47+
*/
48+
case 10 ... i: break; /* c-expected-error {{expression is not an integer constant expression}}
49+
cxx-expected-error {{case value is not a constant expression}}
50+
cxx-expected-note {{function parameter 'i' with unknown value cannot be used in a constant expression}}
51+
gnu-warning {{case ranges are a GNU extension}}
52+
ped-warning {{case ranges are a C2y extension}}
53+
pre-warning {{case ranges are incompatible with C standards before C2y}}
54+
*/
55+
case 1.3f ... 10: break; /* c-expected-error {{integer constant expression must have integer type, not 'float'}}
56+
cxx-expected-error {{conversion from 'float' to 'int' is not allowed in a converted constant expression}}
57+
*/
58+
case 10 ... "a": break; /* c-expected-error {{integer constant expression must have integer type, not 'char[2]'}}
59+
cxx-expected-error {{value of type 'const char[2]' is not implicitly convertible to 'int'}}
60+
gnu-warning {{case ranges are a GNU extension}}
61+
ped-warning {{case ranges are a C2y extension}}
62+
pre-warning {{case ranges are incompatible with C standards before C2y}}
63+
*/
64+
}
65+
66+
switch (i) {
67+
// Cannot have multiple cases covering the same value.
68+
// FIXME: diagnostic quality here is poor. The "previous case" note is
69+
// showing up on a subsequent line (I'd expect the error and note to be
70+
// reversed), and "duplicate case value 20" is showing up on a line where
71+
// there is no duplicate value 20 to begin with.
72+
case 10 ... 20: break; /* expected-error {{duplicate case value '11'}}
73+
expected-note {{previous case defined here}}
74+
gnu-warning {{case ranges are a GNU extension}}
75+
ped-warning {{case ranges are a C2y extension}}
76+
pre-warning {{case ranges are incompatible with C standards before C2y}}
77+
*/
78+
case 11: break; /* expected-note {{previous case defined here}}
79+
*/
80+
case 11 ... 14: break; /* expected-error {{duplicate case value '20'}}
81+
gnu-warning {{case ranges are a GNU extension}}
82+
ped-warning {{case ranges are a C2y extension}}
83+
pre-warning {{case ranges are incompatible with C standards before C2y}}
84+
*/
85+
}
86+
87+
// The values specified by the range shall not change as a result of
88+
// conversion to the promoted type of the controlling expression.
89+
// FIXME: the overflow warnings seem like they probably should also trigger
90+
// in C++ as they do in C.
91+
switch ((unsigned char)i) {
92+
case 254 ... 256: break; /* c-expected-warning {{overflow converting case value to switch condition type (256 to 0)}}
93+
gnu-warning {{case ranges are a GNU extension}}
94+
ped-warning {{case ranges are a C2y extension}}
95+
pre-warning {{case ranges are incompatible with C standards before C2y}}
96+
*/
97+
case 257 ... 258: break; /* c-expected-warning {{overflow converting case value to switch condition type (257 to 1)}}
98+
c-expected-warning {{overflow converting case value to switch condition type (258 to 2)}}
99+
gnu-warning {{case ranges are a GNU extension}}
100+
ped-warning {{case ranges are a C2y extension}}
101+
pre-warning {{case ranges are incompatible with C standards before C2y}}
102+
*/
103+
}
104+
}
105+

clang/test/Sema/gnu-flags.c

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wno-gnu
22
// RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wgnu
33
// RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wno-gnu \
4-
// RUN: -Wgnu-alignof-expression -Wgnu-case-range -Wgnu-complex-integer -Wgnu-conditional-omitted-operand \
4+
// RUN: -Wgnu-alignof-expression -Wgnu-complex-integer -Wgnu-conditional-omitted-operand \
55
// RUN: -Wgnu-label-as-value -Wgnu-statement-expression \
66
// RUN: -Wgnu-compound-literal-initializer -Wgnu-flexible-array-initializer \
77
// RUN: -Wgnu-redeclared-enum -Wgnu-folding-constant -Wgnu-empty-struct \
88
// RUN: -Wgnu-union-cast -Wgnu-variable-sized-type-not-at-end
99
// RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wgnu \
10-
// RUN: -Wno-gnu-alignof-expression -Wno-gnu-case-range -Wno-gnu-complex-integer -Wno-gnu-conditional-omitted-operand \
10+
// RUN: -Wno-gnu-alignof-expression -Wno-gnu-complex-integer -Wno-gnu-conditional-omitted-operand \
1111
// RUN: -Wno-gnu-label-as-value -Wno-gnu-statement-expression \
1212
// RUN: -Wno-gnu-compound-literal-initializer -Wno-gnu-flexible-array-initializer \
1313
// RUN: -Wno-gnu-redeclared-enum -Wno-gnu-folding-constant -Wno-gnu-empty-struct \
1414
// RUN: -Wno-gnu-union-cast -Wno-gnu-variable-sized-type-not-at-end
1515
// Additional disabled tests:
1616
// %clang_cc1 -fsyntax-only -verify %s -DALIGNOF -Wno-gnu -Wgnu-alignof-expression
17-
// %clang_cc1 -fsyntax-only -verify %s -DCASERANGE -Wno-gnu -Wgnu-case-range
1817
// %clang_cc1 -fsyntax-only -verify %s -DCOMPLEXINT -Wno-gnu -Wgnu-complex-integer
1918
// %clang_cc1 -fsyntax-only -verify %s -DOMITTEDOPERAND -Wno-gnu -Wgnu-conditional-omitted-operand
2019
// %clang_cc1 -fsyntax-only -verify %s -DLABELVALUE -Wno-gnu -Wgnu-label-as-value
@@ -41,17 +40,6 @@ char align;
4140
_Static_assert(_Alignof(align) > 0, "align's alignment is wrong");
4241

4342

44-
#if ALL || CASERANGE
45-
// expected-warning@+5 {{use of GNU case range extension}}
46-
#endif
47-
48-
void caserange(int x) {
49-
switch (x) {
50-
case 42 ... 44: ;
51-
}
52-
}
53-
54-
5543
#if ALL || COMPLEXINT
5644
// expected-warning@+3 {{complex integer types are a GNU extension}}
5745
#endif

clang/www/c_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ <h2 id="c2y">C2y implementation status</h2>
236236
<tr>
237237
<td>Case range expressions v3.1</td>
238238
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3370.htm">N3370</a></td>
239-
<td class="unknown" align="center">Unknown</td>
239+
<td class="full" align="center">Yes</td>
240240
</tr>
241241
<tr>
242242
<td>New _Lengthof() operator (v4)</td>

0 commit comments

Comments
 (0)