Skip to content

Commit 0031efe

Browse files
authored
Remove warnings from -Wchar-subscripts for known positive constants (#69061)
Fixes #18763 Remove warnings when using a signed char as an array bound if the char is a known positive constant. This goes one step farther than gcc does. For example given the following code ```c++ char upper[300]; int main() { upper['a'] = 'A'; char b = 'a'; upper[b] = 'A'; const char c = 'a'; upper[c] = 'A'; constexpr char d = 'a'; upper[d] = 'A'; char e = -1; upper[e] = 'A'; const char f = -1; upper[f] = 'A'; constexpr char g = -1; upper[g] = 'A'; return 1; } ``` clang currently gives warnings for all cases, while gcc gives warnings for all cases except for 'a' (https://godbolt.org/z/5ahjETTv3) With the change there is no longer any warning for 'a', 'c', or 'd'.
1 parent f4b1f44 commit 0031efe

File tree

4 files changed

+138
-3
lines changed

4 files changed

+138
-3
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,8 @@ Bug Fixes in This Version
651651
- Fixed false positive error emitted by clang when performing qualified name
652652
lookup and the current class instantiation has dependent bases.
653653
Fixes (`#13826 <https://github.com/llvm/llvm-project/issues/13826>`_)
654+
- Clang's ``-Wchar-subscripts`` no longer warns on chars whose values are known non-negative constants.
655+
Fixes (`#18763 <https://github.com/llvm/llvm-project/issues/18763>`_)
654656

655657
Bug Fixes to Compiler Builtins
656658
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaExpr.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6053,9 +6053,14 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
60536053
<< IndexExpr->getSourceRange());
60546054

60556055
if ((IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_S) ||
6056-
IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_U))
6057-
&& !IndexExpr->isTypeDependent())
6058-
Diag(LLoc, diag::warn_subscript_is_char) << IndexExpr->getSourceRange();
6056+
IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_U)) &&
6057+
!IndexExpr->isTypeDependent()) {
6058+
std::optional<llvm::APSInt> IntegerContantExpr =
6059+
IndexExpr->getIntegerConstantExpr(getASTContext());
6060+
if (!IntegerContantExpr.has_value() ||
6061+
IntegerContantExpr.value().isNegative())
6062+
Diag(LLoc, diag::warn_subscript_is_char) << IndexExpr->getSourceRange();
6063+
}
60596064

60606065
// C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly,
60616066
// C++ [expr.sub]p1: The type "T" shall be a completely-defined object

clang/test/Sema/warn-char-subscripts.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,28 @@ void t10(void) {
6262
UnsignedCharTy subscript = 0;
6363
int val = array[subscript]; // no warning for unsigned char
6464
}
65+
66+
void t11(void) {
67+
int array[256] = { 0 };
68+
int val = array['a']; // no warning for char with known positive value
69+
}
70+
71+
void t12(void) {
72+
int array[256] = { 0 };
73+
char b = 'a';
74+
int val = array[b]; // expected-warning{{array subscript is of type 'char'}}
75+
}
76+
77+
void t13(void) {
78+
int array[256] = { 0 };
79+
const char b = 'a';
80+
int val = array[b]; // expected-warning{{array subscript is of type 'char'}}
81+
}
82+
83+
void t14(void) {
84+
int array[256] = { 0 }; // expected-note {{array 'array' declared here}}
85+
const char b = -1;
86+
// expected-warning@+2 {{array subscript is of type 'char'}}
87+
// expected-warning@+1 {{array index -1 is before the beginning of the array}}
88+
int val = array[b];
89+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// RUN: %clang_cc1 -Wchar-subscripts -fsyntax-only -verify %s
2+
3+
void t1(void) {
4+
int array[1] = { 0 };
5+
char subscript = 0;
6+
int val = array[subscript]; // expected-warning{{array subscript is of type 'char'}}
7+
}
8+
9+
void t2(void) {
10+
int array[1] = { 0 };
11+
char subscript = 0;
12+
int val = subscript[array]; // expected-warning{{array subscript is of type 'char'}}
13+
}
14+
15+
void t3(void) {
16+
int *array = 0;
17+
char subscript = 0;
18+
int val = array[subscript]; // expected-warning{{array subscript is of type 'char'}}
19+
}
20+
21+
void t4(void) {
22+
int *array = 0;
23+
char subscript = 0;
24+
int val = subscript[array]; // expected-warning{{array subscript is of type 'char'}}
25+
}
26+
27+
char returnsChar(void);
28+
void t5(void) {
29+
int *array = 0;
30+
int val = array[returnsChar()]; // expected-warning{{array subscript is of type 'char'}}
31+
}
32+
33+
void t6(void) {
34+
int array[1] = { 0 };
35+
signed char subscript = 0;
36+
int val = array[subscript]; // no warning for explicit signed char
37+
}
38+
39+
void t7(void) {
40+
int array[1] = { 0 };
41+
unsigned char subscript = 0;
42+
int val = array[subscript]; // no warning for unsigned char
43+
}
44+
45+
typedef char CharTy;
46+
void t8(void) {
47+
int array[1] = { 0 };
48+
CharTy subscript = 0;
49+
int val = array[subscript]; // expected-warning{{array subscript is of type 'char'}}
50+
}
51+
52+
typedef signed char SignedCharTy;
53+
void t9(void) {
54+
int array[1] = { 0 };
55+
SignedCharTy subscript = 0;
56+
int val = array[subscript]; // no warning for explicit signed char
57+
}
58+
59+
typedef unsigned char UnsignedCharTy;
60+
void t10(void) {
61+
int array[1] = { 0 };
62+
UnsignedCharTy subscript = 0;
63+
int val = array[subscript]; // no warning for unsigned char
64+
}
65+
66+
void t11(void) {
67+
int array[256] = { 0 };
68+
int val = array['a']; // no warning for char with known positive value
69+
}
70+
71+
void t12(void) {
72+
int array[256] = { 0 };
73+
char b = 'a';
74+
int val = array[b]; // expected-warning{{array subscript is of type 'char'}}
75+
}
76+
77+
void t13(void) {
78+
int array[256] = { 0 };
79+
const char b = 'a';
80+
int val = array[b]; // no warning for char with known positive value
81+
}
82+
83+
void t14(void) {
84+
int array[256] = { 0 };
85+
constexpr char b = 'a';
86+
int val = array[b]; // no warning for char with known positive value
87+
}
88+
89+
void t15(void) {
90+
int array[256] = { 0 }; // expected-note {{array 'array' declared here}}
91+
const char b = -1;
92+
// expected-warning@+2 {{array subscript is of type 'char'}}
93+
// expected-warning@+1 {{array index -1 is before the beginning of the array}}
94+
int val = array[b];
95+
}
96+
97+
void t16(void) {
98+
int array[256] = { 0 }; // expected-note {{array 'array' declared here}}
99+
constexpr char b = -1;
100+
// expected-warning@+2 {{array subscript is of type 'char'}}
101+
// expected-warning@+1 {{array index -1 is before the beginning of the array}}
102+
int val = array[b];
103+
}

0 commit comments

Comments
 (0)