Skip to content

Commit 4e3f44a

Browse files
Control transfers and loops in constant evaluation [GH #401, GH #402, GH #403, GH #404, GH #411]
1 parent f51894d commit 4e3f44a

31 files changed

Lines changed: 1527 additions & 766 deletions

‎src/interpret.c‎

Lines changed: 837 additions & 594 deletions
Large diffs are not rendered by default.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[GH #401]
2+
break and continue in GNU statement expressions in constant evaluation
3+
4+
In GNU modes, a break or continue statement inside a statement expression
5+
did not correctly transfer control out of the enclosing full-expression
6+
during constant evaluation: the evaluation of the enclosing expression
7+
continued with an indeterminate value for the statement expression, and the
8+
enclosing loop or switch statement was not exited. For example, with
9+
--c++20 --gnu_version 130000:
10+
11+
constexpr int f(int v) {
12+
int n = 0;
13+
for (int i = 0; i < 5; ++i) {
14+
n += ({ if (i == v) break; i; });
15+
}
16+
return n;
17+
}
18+
static_assert(f(3) == 3); // Previously failed.
19+
20+
This is now fixed. To that end, the interpretation of control transfers
21+
(break, continue, and return statements, and the entry of a switch statement
22+
at a case label) and of loops was reorganized.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[GH #402]
2+
Variables declared before a case label in constant evaluation
3+
4+
During constant evaluation, a variable declared (without initializer) after
5+
one case label of a switch statement and used after a subsequent case label
6+
was treated as inaccessible when the switch statement transferred control
7+
to the subsequent label. The same happened for a variable declared without
8+
initializer in the init-statement of an if- or for-statement whose
9+
substatement contains the case label. For example, with --c++20:
10+
11+
constexpr int f() {
12+
switch (1) {
13+
for (int x; ;) {
14+
case 1:
15+
x = 3;
16+
return x;
17+
}
18+
}
19+
return 0;
20+
}
21+
static_assert(f() == 3); // Previously failed.
22+
23+
This is now fixed.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[GH #403]
2+
Lifetime of condition variables in constant evaluation
3+
4+
During constant evaluation, a variable declared in the condition of an if-,
5+
switch-, while-, or for-statement was destroyed before the substatement
6+
(and, for a for-statement, the increment expression) was evaluated, instead
7+
of at the end of the statement (or, for a loop, of the iteration). The same
8+
was true for a variable declared in the init-statement of an if- or
9+
switch-statement. For example, with --c++20:
10+
11+
struct S {
12+
int* p;
13+
constexpr ~S() { *p = *p * 10 + 2; }
14+
constexpr explicit operator bool() const { return true; }
15+
};
16+
constexpr int f() {
17+
int n = 0;
18+
if (S s{&n}) n = n * 10 + 1;
19+
return n;
20+
}
21+
static_assert(f() == 12); // Previously failed.
22+
23+
This is now fixed.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[GH #404]
2+
Lifetime of the variable of a range-based for-statement in constant evaluation
3+
4+
During constant evaluation, the variable declared by the for-range-declaration
5+
of a range-based for-statement was not destroyed at the end of each
6+
iteration. For example, with --c++20:
7+
8+
struct R { int* p; constexpr ~R() { ++*p; } };
9+
constexpr int g() {
10+
int n = 0;
11+
R a[2] = {{&n}, {&n}};
12+
for (R r : a) {}
13+
return n;
14+
}
15+
static_assert(g() == 2); // Previously failed.
16+
17+
This is now fixed.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[GH #411]
2+
For loops entered through a case label in constant evaluation
3+
4+
During constant evaluation, when a switch statement transferred control to a
5+
case label in the body of a for loop that was followed by other statements,
6+
the loop was not continued after the body completed: The loop condition was
7+
not evaluated again. For example, with --c++20:
8+
9+
constexpr int f(int k) {
10+
bool b = false;
11+
int z = 0;
12+
switch (k) {
13+
for (; b;) {
14+
return 5;
15+
case 1:
16+
b = true;
17+
z = 9;
18+
}
19+
return z;
20+
}
21+
return -1;
22+
}
23+
static_assert(f(1) == 5); // Previously failed.
24+
25+
This is now fixed.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fe_only -DTEST_NUMBER=1 --c++20 --gnu_version 130000 Test_name.c
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fe_only -DTEST_NUMBER=1 --c++20 Test_name.c
2+
"Test_name.c", line 45: warning: statement is unreachable
3+
if (int x; false) {
4+
^
5+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fe_only -DTEST_NUMBER=1 --c++20 Test_name.c
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fe_only -DTEST_NUMBER=1 --c++20 Test_name.c

0 commit comments

Comments
 (0)