Skip to content

Commit 7394c15

Browse files
committed
[Sema] SequenceChecker: C++17 sequencing rules for built-in operators <<, >>, .*, ->*, =, op=
Implement the C++17 sequencing rules for the built-in operators <<, >>, .*, ->*, = and op=. Differential Revision: https://reviews.llvm.org/D58297 Reviewed By: rsmith
1 parent 8a57153 commit 7394c15

File tree

4 files changed

+164
-48
lines changed

4 files changed

+164
-48
lines changed

clang/lib/Sema/SemaChecking.cpp

Lines changed: 83 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12832,8 +12832,37 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
1283212832
// expression E1 is sequenced before the expression E2.
1283312833
if (SemaRef.getLangOpts().CPlusPlus17)
1283412834
VisitSequencedExpressions(ASE->getLHS(), ASE->getRHS());
12835-
else
12836-
Base::VisitStmt(ASE);
12835+
else {
12836+
Visit(ASE->getLHS());
12837+
Visit(ASE->getRHS());
12838+
}
12839+
}
12840+
12841+
void VisitBinPtrMemD(const BinaryOperator *BO) { VisitBinPtrMem(BO); }
12842+
void VisitBinPtrMemI(const BinaryOperator *BO) { VisitBinPtrMem(BO); }
12843+
void VisitBinPtrMem(const BinaryOperator *BO) {
12844+
// C++17 [expr.mptr.oper]p4:
12845+
// Abbreviating pm-expression.*cast-expression as E1.*E2, [...]
12846+
// the expression E1 is sequenced before the expression E2.
12847+
if (SemaRef.getLangOpts().CPlusPlus17)
12848+
VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
12849+
else {
12850+
Visit(BO->getLHS());
12851+
Visit(BO->getRHS());
12852+
}
12853+
}
12854+
12855+
void VisitBinShl(const BinaryOperator *BO) { VisitBinShlShr(BO); }
12856+
void VisitBinShr(const BinaryOperator *BO) { VisitBinShlShr(BO); }
12857+
void VisitBinShlShr(const BinaryOperator *BO) {
12858+
// C++17 [expr.shift]p4:
12859+
// The expression E1 is sequenced before the expression E2.
12860+
if (SemaRef.getLangOpts().CPlusPlus17)
12861+
VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
12862+
else {
12863+
Visit(BO->getLHS());
12864+
Visit(BO->getRHS());
12865+
}
1283712866
}
1283812867

1283912868
void VisitBinComma(const BinaryOperator *BO) {
@@ -12845,38 +12874,67 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
1284512874
}
1284612875

1284712876
void VisitBinAssign(const BinaryOperator *BO) {
12848-
// The modification is sequenced after the value computation of the LHS
12849-
// and RHS, so check it before inspecting the operands and update the
12877+
SequenceTree::Seq RHSRegion;
12878+
SequenceTree::Seq LHSRegion;
12879+
if (SemaRef.getLangOpts().CPlusPlus17) {
12880+
RHSRegion = Tree.allocate(Region);
12881+
LHSRegion = Tree.allocate(Region);
12882+
} else {
12883+
RHSRegion = Region;
12884+
LHSRegion = Region;
12885+
}
12886+
SequenceTree::Seq OldRegion = Region;
12887+
12888+
// C++11 [expr.ass]p1:
12889+
// [...] the assignment is sequenced after the value computation
12890+
// of the right and left operands, [...]
12891+
//
12892+
// so check it before inspecting the operands and update the
1285012893
// map afterwards.
12851-
Object O = getObject(BO->getLHS(), true);
12852-
if (!O)
12853-
return VisitExpr(BO);
12894+
Object O = getObject(BO->getLHS(), /*Mod=*/true);
12895+
if (O)
12896+
notePreMod(O, BO);
12897+
12898+
if (SemaRef.getLangOpts().CPlusPlus17) {
12899+
// C++17 [expr.ass]p1:
12900+
// [...] The right operand is sequenced before the left operand. [...]
12901+
{
12902+
SequencedSubexpression SeqBefore(*this);
12903+
Region = RHSRegion;
12904+
Visit(BO->getRHS());
12905+
}
1285412906

12855-
notePreMod(O, BO);
12907+
Region = LHSRegion;
12908+
Visit(BO->getLHS());
1285612909

12857-
// C++11 [expr.ass]p7:
12858-
// E1 op= E2 is equivalent to E1 = E1 op E2, except that E1 is evaluated
12859-
// only once.
12860-
//
12861-
// Therefore, for a compound assignment operator, O is considered used
12862-
// everywhere except within the evaluation of E1 itself.
12863-
if (isa<CompoundAssignOperator>(BO))
12864-
notePreUse(O, BO);
12910+
if (O && isa<CompoundAssignOperator>(BO))
12911+
notePostUse(O, BO);
1286512912

12866-
Visit(BO->getLHS());
12913+
} else {
12914+
// C++11 does not specify any sequencing between the LHS and RHS.
12915+
Region = LHSRegion;
12916+
Visit(BO->getLHS());
1286712917

12868-
if (isa<CompoundAssignOperator>(BO))
12869-
notePostUse(O, BO);
12918+
if (O && isa<CompoundAssignOperator>(BO))
12919+
notePostUse(O, BO);
1287012920

12871-
Visit(BO->getRHS());
12921+
Region = RHSRegion;
12922+
Visit(BO->getRHS());
12923+
}
1287212924

1287312925
// C++11 [expr.ass]p1:
12874-
// the assignment is sequenced [...] before the value computation of the
12875-
// assignment expression.
12926+
// the assignment is sequenced [...] before the value computation of the
12927+
// assignment expression.
1287612928
// C11 6.5.16/3 has no such rule.
12877-
notePostMod(O, BO,
12878-
SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
12879-
: UK_ModAsSideEffect);
12929+
Region = OldRegion;
12930+
if (O)
12931+
notePostMod(O, BO,
12932+
SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
12933+
: UK_ModAsSideEffect);
12934+
if (SemaRef.getLangOpts().CPlusPlus17) {
12935+
Tree.merge(RHSRegion);
12936+
Tree.merge(LHSRegion);
12937+
}
1288012938
}
1288112939

1288212940
void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) {

clang/test/CXX/drs/dr2xx.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,17 @@ namespace dr222 { // dr222: dup 637
225225
void((a += b) += c);
226226
void((a += b) + (a += c)); // expected-warning {{multiple unsequenced modifications to 'a'}}
227227

228-
x[a++] = a; // expected-warning {{unsequenced modification and access to 'a'}}
228+
x[a++] = a;
229+
#if __cplusplus < 201703L
230+
// expected-warning@-2 {{unsequenced modification and access to 'a'}}
231+
#endif
229232

230233
a = b = 0; // ok, read and write of 'b' are sequenced
231234

232-
a = (b = a++); // expected-warning {{multiple unsequenced modifications to 'a'}}
235+
a = (b = a++);
236+
#if __cplusplus < 201703L
237+
// expected-warning@-2 {{multiple unsequenced modifications to 'a'}}
238+
#endif
233239
a = (b = ++a);
234240
#pragma clang diagnostic pop
235241
}

clang/test/CXX/drs/dr6xx.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,10 @@ namespace dr635 { // dr635: yes
317317
namespace dr637 { // dr637: yes
318318
void f(int i) {
319319
i = ++i + 1;
320-
i = i++ + 1; // expected-warning {{unsequenced}}
320+
i = i++ + 1;
321+
#if __cplusplus < 201703L
322+
// expected-warning@-2 {{unsequenced}}
323+
#endif
321324
}
322325
}
323326

clang/test/SemaCXX/warn-unsequenced.cpp

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ void test() {
2626
a + a++; // cxx11-warning {{unsequenced modification and access to 'a'}}
2727
// cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
2828
a = a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
29-
// TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
3029
++ ++a; // ok
3130
(a++, a++); // ok
3231
++a + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
@@ -36,13 +35,10 @@ void test() {
3635
(a++, a) = 0; // ok, increment is sequenced before value computation of LHS
3736
a = xs[++a]; // ok
3837
a = xs[a++]; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
39-
// TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
4038
(a ? xs[0] : xs[1]) = ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
41-
// TODO cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
4239
a = (++a, ++a); // ok
4340
a = (a++, ++a); // ok
4441
a = (a++, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
45-
// TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
4642
f(a, a); // ok
4743
f(a = 0, a); // cxx11-warning {{unsequenced modification and access to 'a'}}
4844
// cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
@@ -61,7 +57,6 @@ void test() {
6157
(++a, a) += 1; // ok
6258
a = ++a; // ok
6359
a += ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
64-
// TODO cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
6560

6661
A agg1 = { a++, a++ }; // ok
6762
A agg2 = { a++ + a, a++ }; // cxx11-warning {{unsequenced modification and access to 'a'}}
@@ -77,7 +72,6 @@ void test() {
7772
a = S { ++a, a++ }.n; // ok
7873
A { ++a, a++ }.x; // ok
7974
a = A { ++a, a++ }.x; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
80-
// TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
8175
A { ++a, a++ }.x + A { ++a, a++ }.y; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
8276
// cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
8377

@@ -112,14 +106,10 @@ void test() {
112106
a += (a++, a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
113107
// cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
114108

115-
int *p = xs;
116-
a = *(a++, p); // ok
117109
a = a++ && a; // ok
118-
p[(long long unsigned)(p = 0)]; // cxx11-warning {{unsequenced modification and access to 'p'}}
119110

120111
A *q = &agg1;
121112
(q = &agg2)->y = q->x; // cxx11-warning {{unsequenced modification and access to 'q'}}
122-
// TODO cxx17-warning@-1 {{unsequenced modification and access to 'q'}}
123113

124114
// This has undefined behavior if a == 0; otherwise, the side-effect of the
125115
// increment is sequenced before the value computation of 'f(a, a)', which is
@@ -147,20 +137,14 @@ void test() {
147137
xs[8] ? ++a : a++; // no-warning
148138
xs[8] ? a+=1 : a+= 2; // no-warning
149139
(xs[8] ? a+=1 : a+= 2) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
150-
// TODO cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
151140
(xs[8] ? a+=1 : a) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
152-
// TODO cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
153141
(xs[8] ? a : a+= 2) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
154-
// TODO cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
155142
a = (xs[8] ? a+=1 : a+= 2); // no-warning
156143
a += (xs[8] ? a+=1 : a+= 2); // cxx11-warning {{unsequenced modification and access to 'a'}}
157-
// TODO cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
158144

159145
(false ? a+=1 : a) = a; // no-warning
160146
(true ? a+=1 : a) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
161-
// TODO cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
162147
(false ? a : a+=2) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
163-
// TODO cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
164148
(true ? a : a+=2) = a; // no-warning
165149

166150
xs[8] && (++a + a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
@@ -180,19 +164,15 @@ void test() {
180164
a = ((a++, false) || (a++, false) || (a++, false) || (a++, false)); // no-warning
181165
a = ((a++, true) && (a++, true) && (a++, true) && (a++, true)); // no-warning
182166
a = ((a++, false) || (a++, false) || (a++, false) || a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
183-
// TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
184167
a = ((a++, true) && (a++, true) && (a++, true) && a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
185-
// TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
186168
a = ((a++, false) || (a++, false) || (a++, false) || (a + a, false)); // no-warning
187169
a = ((a++, true) && (a++, true) && (a++, true) && (a + a, true)); // no-warning
188170

189171
a = (false && a++); // no-warning
190172
a = (true && a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
191-
// TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
192173
a = (true && ++a); // no-warning
193174
a = (true || a++); // no-warning
194175
a = (false || a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
195-
// TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
196176
a = (false || ++a); // no-warning
197177

198178
(a++) | (a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
@@ -207,6 +187,75 @@ void test() {
207187
(__builtin_object_size(&(++a, a), 0) ? 1 : 0) + ++a; // ok
208188
(__builtin_expect(++a, 0) ? 1 : 0) + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
209189
// cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
190+
191+
192+
int *p = xs;
193+
a = *(a++, p); // no-warning
194+
p[(long long unsigned)(p = 0)]; // cxx11-warning {{unsequenced modification and access to 'p'}}
195+
(i++, xs)[i++]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
196+
(++i, xs)[++i]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
197+
(i, xs)[++i + ++i]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
198+
// cxx17-warning@-1 {{multiple unsequenced modifications to 'i'}}
199+
p++[p == xs]; // cxx11-warning {{unsequenced modification and access to 'p'}}
200+
++p[p++ == xs]; // cxx11-warning {{unsequenced modification and access to 'p'}}
201+
202+
struct S { int x; } s, *ps = &s;
203+
int (S::*PtrMem);
204+
(PtrMem = &S::x ,s).*(PtrMem); // cxx11-warning {{unsequenced modification and access to 'PtrMem'}}
205+
(PtrMem = &S::x ,s).*(PtrMem = &S::x); // cxx11-warning {{multiple unsequenced modifications to 'PtrMem'}}
206+
(PtrMem = &S::x ,ps)->*(PtrMem); // cxx11-warning {{unsequenced modification and access to 'PtrMem'}}
207+
(PtrMem = &S::x ,ps)->*(PtrMem = &S::x); // cxx11-warning {{multiple unsequenced modifications to 'PtrMem'}}
208+
(PtrMem = nullptr) == (PtrMem = nullptr); // cxx11-warning {{multiple unsequenced modifications to 'PtrMem'}}
209+
// cxx17-warning@-1 {{multiple unsequenced modifications to 'PtrMem'}}
210+
(PtrMem = nullptr) == PtrMem; // cxx11-warning {{unsequenced modification and access to 'PtrMem'}}
211+
// cxx17-warning@-1 {{unsequenced modification and access to 'PtrMem'}}
212+
213+
i++ << i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
214+
++i << ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
215+
i++ << i; // cxx11-warning {{unsequenced modification and access to 'i'}}
216+
i << i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
217+
i++ >> i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
218+
++i >> ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
219+
i++ >> i; // cxx11-warning {{unsequenced modification and access to 'i'}}
220+
i >> i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
221+
(i++ << i) + i; // cxx11-warning {{unsequenced modification and access to 'i'}}
222+
// cxx17-warning@-1 {{unsequenced modification and access to 'i'}}
223+
(i++ << i) << i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
224+
225+
++i = i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
226+
i = i+= 1; // no-warning
227+
i = i++ + ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
228+
// cxx17-warning@-1 {{multiple unsequenced modifications to 'i'}}
229+
++i += ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
230+
++i += i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
231+
(i++, i) += ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
232+
(i++, i) += i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
233+
i += i+= 1; // cxx11-warning {{unsequenced modification and access to 'i'}}
234+
i += i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
235+
i += ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
236+
i -= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
237+
i -= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
238+
i *= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
239+
i *= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
240+
i /= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
241+
i /= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
242+
i %= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
243+
i %= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
244+
i ^= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
245+
i ^= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
246+
i |= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
247+
i |= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
248+
i &= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
249+
i &= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
250+
i <<= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
251+
i <<= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
252+
i >>= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
253+
i >>= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
254+
255+
p[i++] = i; // cxx11-warning {{unsequenced modification and access to 'i'}}
256+
p[i++] = (i = 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}}
257+
p++[i++] = (i = p ? i++ : i++); // cxx11-warning {{unsequenced modification and access to 'p'}}
258+
// cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
210259
}
211260

212261
namespace members {

0 commit comments

Comments
 (0)