Skip to content

Commit 7198279

Browse files
authored
[clang][bytecode] Implement case ranges (llvm#168418)
Fixes llvm#165969 Implement GNU case ranges for constexpr bytecode interpreter.
1 parent 47b756a commit 7198279

File tree

2 files changed

+133
-3
lines changed

2 files changed

+133
-3
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6016,11 +6016,38 @@ bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
60166016
for (const SwitchCase *SC = S->getSwitchCaseList(); SC;
60176017
SC = SC->getNextSwitchCase()) {
60186018
if (const auto *CS = dyn_cast<CaseStmt>(SC)) {
6019-
// FIXME: Implement ranges.
6020-
if (CS->caseStmtIsGNURange())
6021-
return false;
60226019
CaseLabels[SC] = this->getLabel();
60236020

6021+
if (CS->caseStmtIsGNURange()) {
6022+
LabelTy EndOfRangeCheck = this->getLabel();
6023+
const Expr *Low = CS->getLHS();
6024+
const Expr *High = CS->getRHS();
6025+
if (Low->isValueDependent() || High->isValueDependent())
6026+
return false;
6027+
6028+
if (!this->emitGetLocal(CondT, CondVar, CS))
6029+
return false;
6030+
if (!this->visit(Low))
6031+
return false;
6032+
PrimType LT = this->classifyPrim(Low->getType());
6033+
if (!this->emitGE(LT, S))
6034+
return false;
6035+
if (!this->jumpFalse(EndOfRangeCheck))
6036+
return false;
6037+
6038+
if (!this->emitGetLocal(CondT, CondVar, CS))
6039+
return false;
6040+
if (!this->visit(High))
6041+
return false;
6042+
PrimType HT = this->classifyPrim(High->getType());
6043+
if (!this->emitLE(HT, S))
6044+
return false;
6045+
if (!this->jumpTrue(CaseLabels[CS]))
6046+
return false;
6047+
this->emitLabel(EndOfRangeCheck);
6048+
continue;
6049+
}
6050+
60246051
const Expr *Value = CS->getLHS();
60256052
if (Value->isValueDependent())
60266053
return false;

clang/test/AST/ByteCode/switch.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,106 @@ constexpr int another_test(int val) { // both-note {{declared here}}
8686
}
8787
static_assert(another_test(1) == 100, ""); // both-error {{static assertion failed}} \
8888
// both-note {{evaluates to}}
89+
90+
namespace gnurange {
91+
constexpr int l(int n) {
92+
return n + 1;
93+
}
94+
constexpr int h(int n) {
95+
return 2 * n + 1;
96+
}
97+
constexpr int f(int x) {
98+
const int n = 2;
99+
constexpr struct {
100+
char lo {'a'};
101+
char hi {'z'};
102+
} s;
103+
104+
switch (x) {
105+
case l(n) ... h(n):
106+
return 1;
107+
case -1 ... 1:
108+
return 2;
109+
case 9 ... 14:
110+
return 3;
111+
case 15:
112+
return 4;
113+
case 16 ... 20:
114+
return 5;
115+
case s.lo ... s.hi:
116+
return 6;
117+
default:
118+
return -1;
119+
}
120+
}
121+
static_assert(f(0) == 2);
122+
static_assert(f(2) == -1);
123+
static_assert(f(3) == 1);
124+
static_assert(f(4) == 1);
125+
static_assert(f(5) == 1);
126+
static_assert(f(6) == -1);
127+
static_assert(f(14) == 3);
128+
static_assert(f(15) == 4);
129+
static_assert(f(16) == 5);
130+
static_assert(f(20) == 5);
131+
static_assert(f('d') == 6);
132+
133+
template <int Lo, int Hi>
134+
constexpr bool g(int x) {
135+
switch (x) {
136+
case Lo ... Hi:
137+
break;
138+
default:
139+
return false;
140+
}
141+
return true;
142+
}
143+
static_assert(g<100, 200>(132));
144+
145+
constexpr bool m(int x) {
146+
switch (x) {
147+
case 10 ... 1: // both-warning {{empty case range specified}}
148+
return true;
149+
default:
150+
return false;
151+
}
152+
}
153+
static_assert(m(3)); // both-error {{static assertion failed due to requirement 'm(3)'}}
154+
static_assert(!m(3));
155+
156+
constexpr bool j(int x) { // both-note {{declared here}}
157+
switch (x) {
158+
case bad(x) ... 100: // both-error {{case value is not a constant expression}} \
159+
// both-note {{cannot be used in a constant expression}}
160+
return true;
161+
default:
162+
break;
163+
}
164+
return false;
165+
}
166+
static_assert(j(1)); // both-error {{static assertion failed}}
167+
168+
constexpr bool d(int x) { // both-note {{declared here}}
169+
switch (x) {
170+
case -100 ... bad(x): // both-error {{case value is not a constant expression}} \
171+
// both-note {{cannot be used in a constant expression}}
172+
return true;
173+
default:
174+
break;
175+
}
176+
return false;
177+
}
178+
static_assert(d(1)); // both-error {{static assertion failed}}
179+
180+
constexpr bool s(int x) { // both-note {{declared here}}
181+
switch (x) {
182+
case bad(x) - 100 ... bad(x) + 100: // both-error {{case value is not a constant expression}} \
183+
// both-note {{cannot be used in a constant expression}}
184+
return true;
185+
default:
186+
break;
187+
}
188+
return false;
189+
}
190+
static_assert(s(1)); // both-error {{static assertion failed}}
191+
}

0 commit comments

Comments
 (0)