Clang Project

clang_source_code/test/SemaCXX/warn-unsequenced.cpp
1// RUN: %clang_cc1 -fsyntax-only -verify=cxx11 -std=c++11 -Wno-unused -Wno-uninitialized \
2// RUN:            -Wunsequenced -Wno-c++17-extensions -Wno-c++14-extensions %s
3// RUN: %clang_cc1 -fsyntax-only -verify=cxx17 -std=c++17 -Wno-unused -Wno-uninitialized \
4// RUN:            -Wunsequenced -Wno-c++17-extensions -Wno-c++14-extensions %s
5
6int f(int, int = 0);
7
8struct A {
9  int x, y;
10};
11struct S {
12  S(int, int);
13  int n;
14};
15
16// TODO: Implement the C++17 sequencing rules.
17void test() {
18  int a;
19  int xs[10];
20  ++a = 0; // ok
21  a + ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
22           // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
23  a = ++a; // ok
24  a + a++; // cxx11-warning {{unsequenced modification and access to 'a'}}
25           // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
26  a = a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
27           // TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
28  ++ ++a; // ok
29  (a++, a++); // ok
30  ++a + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
31             // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
32  a++ + a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
33             // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
34  (a++, a) = 0; // ok, increment is sequenced before value computation of LHS
35  a = xs[++a]; // ok
36  a = xs[a++]; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
37               // TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
38  (a ? xs[0] : xs[1]) = ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
39                             // TODO cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
40  a = (++a, ++a); // ok
41  a = (a++, ++a); // ok
42  a = (a++, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
43                  // TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
44  f(a, a); // ok
45  f(a = 0, a); // cxx11-warning {{unsequenced modification and access to 'a'}}
46               // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
47  f(a, a += 0); // cxx11-warning {{unsequenced modification and access to 'a'}}
48                // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
49  f(a = 0, a = 0); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
50                   // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
51  a = f(++a); // ok
52  a = f(a++); // ok
53  a = f(++a, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
54                   // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
55
56  // Compound assignment "A OP= B" is equivalent to "A = A OP B" except that A
57  // is evaluated only once.
58  (++a, a) = 1; // ok
59  (++a, a) += 1; // ok
60  a = ++a; // ok
61  a += ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
62            // TODO cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
63
64  A agg1 = { a++, a++ }; // ok
65  A agg2 = { a++ + a, a++ }; // cxx11-warning {{unsequenced modification and access to 'a'}}
66                             // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
67
68  S str1(a++, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
69                    // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
70  S str2 = { a++, a++ }; // ok
71  S str3 = { a++ + a, a++ }; // cxx11-warning {{unsequenced modification and access to 'a'}}
72                             // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
73
74  struct Z { A a; S s; } z = { { ++a, ++a }, { ++a, ++a } }; // ok
75  a = S { ++a, a++ }.n; // ok
76  A { ++a, a++ }.x; // ok
77  a = A { ++a, a++ }.x; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
78                        // TODO cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
79  A { ++a, a++ }.x + A { ++a, a++ }.y; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
80                                       // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
81
82  (xs[2] && (a = 0)) + a; // ok
83  (0 && (a = 0)) + a; // ok
84  (1 && (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
85                      // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
86
87  (xs[3] || (a = 0)) + a; // ok
88  (0 || (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
89                      // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
90  (1 || (a = 0)) + a; // ok
91
92  (xs[4] ? a : ++a) + a; // ok
93  (0 ? a : ++a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
94                     // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
95  (1 ? a : ++a) + a; // ok
96  (0 ? a : a++) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
97                     // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
98  (1 ? a : a++) + a; // ok
99  (xs[5] ? ++a : ++a) + a; // FIXME: warn here
100
101  (++a, xs[6] ? ++a : 0) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
102                              // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
103
104  // Here, the read of the fourth 'a' might happen before or after the write to
105  // the second 'a'.
106  a += (a++, a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
107                     // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
108
109  int *p = xs;
110  a = *(a++, p); // ok
111  a = a++ && a; // ok
112  p[(long long unsigned)(p = 0)]; // cxx11-warning {{unsequenced modification and access to 'p'}}
113
114  A *q = &agg1;
115  (q = &agg2)->y = q->x; // cxx11-warning {{unsequenced modification and access to 'q'}}
116                         // TODO cxx17-warning@-1 {{unsequenced modification and access to 'q'}}
117
118  // This has undefined behavior if a == 0; otherwise, the side-effect of the
119  // increment is sequenced before the value computation of 'f(a, a)', which is
120  // sequenced before the value computation of the '&&', which is sequenced
121  // before the assignment. We treat the sequencing in '&&' as being
122  // unconditional.
123  a = a++ && f(a, a);
124
125  // This has undefined behavior if a != 0. FIXME: We should diagnose this.
126  (a && a++) + a;
127
128  (xs[7] && ++a) * (!xs[7] && ++a); // ok
129
130  xs[0] = (a = 1, a); // ok
131  (a -= 128) &= 128; // ok
132  ++a += 1; // ok
133
134  xs[8] ? ++a + a++ : 0; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
135                         // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
136  xs[8] ? 0 : ++a + a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
137                         // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
138  xs[8] ? ++a : a++; // ok
139
140  xs[8] && (++a + a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
141                        // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
142  xs[8] || (++a + a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
143                        // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
144
145  (__builtin_classify_type(++a) ? 1 : 0) + ++a; // ok
146  (__builtin_constant_p(++a) ? 1 : 0) + ++a; // ok
147  (__builtin_object_size(&(++a, a), 0) ? 1 : 0) + ++a; // ok
148  (__builtin_expect(++a, 0) ? 1 : 0) + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
149                                            // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
150}
151
152namespace members {
153
154struct S1 {
155  unsigned bf1 : 2;
156  unsigned bf2 : 2;
157  unsigned a;
158  unsigned b;
159  static unsigned x;
160  void member_f(S1 &s);
161};
162
163void S1::member_f(S1 &s) {
164  ++a + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
165             // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
166  a + ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
167           // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
168  ++a + ++b; // no-warning
169  a + ++b; // no-warning
170
171  // TODO: Warn here.
172  ++s.a + ++s.a; // no-warning TODO {{multiple unsequenced modifications to}}
173  s.a + ++s.a; // no-warning TODO {{unsequenced modification and access to}}
174  ++s.a + ++s.b; // no-warning
175  s.a + ++s.b; // no-warning
176
177  ++a + ++s.a; // no-warning
178  a + ++s.a; // no-warning
179  ++a + ++s.b; // no-warning
180  a + ++s.b; // no-warning
181
182  // TODO Warn here for bit-fields in the same memory location.
183  ++bf1 + ++bf1; // cxx11-warning {{multiple unsequenced modifications to 'bf1'}}
184                 // cxx17-warning@-1 {{multiple unsequenced modifications to 'bf1'}}
185  bf1 + ++bf1; // cxx11-warning {{unsequenced modification and access to 'bf1'}}
186               // cxx17-warning@-1 {{unsequenced modification and access to 'bf1'}}
187  ++bf1 + ++bf2; // no-warning TODO {{multiple unsequenced modifications to}}
188  bf1 + ++bf2; // no-warning TODO {{unsequenced modification and access to}}
189
190  // TODO Warn here for bit-fields in the same memory location.
191  ++s.bf1 + ++s.bf1; // no-warning TODO {{multiple unsequenced modifications to}}
192  s.bf1 + ++s.bf1; // no-warning TODO {{unsequenced modification and access to}}
193  ++s.bf1 + ++s.bf2; // no-warning TODO {{multiple unsequenced modifications to}}
194  s.bf1 + ++s.bf2; // no-warning TODO {{unsequenced modification and access to}}
195
196  ++bf1 + ++s.bf1; // no-warning
197  bf1 + ++s.bf1; // no-warning
198  ++bf1 + ++s.bf2; // no-warning
199  bf1 + ++s.bf2; // no-warning
200
201  struct Der : S1 {};
202  Der d;
203  Der &d_ref = d;
204  S1 &s1_ref = d_ref;
205
206  ++s1_ref.a + ++d_ref.a; // no-warning TODO {{multiple unsequenced modifications to member 'a' of 'd'}}
207  ++s1_ref.a + d_ref.a; // no-warning TODO {{unsequenced modification and access to member 'a' of 'd'}}
208  ++s1_ref.a + ++d_ref.b; // no-warning
209  ++s1_ref.a + d_ref.b; // no-warning
210
211  ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
212             // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
213  ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
214           // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
215  ++s.x + x; // no-warning TODO {{unsequenced modification and access to static member 'x' of 'S1'}}
216  ++this->x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
217                 // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
218  ++d_ref.x + ++S1::x; // no-warning TODO {{unsequenced modification and access to static member 'x' of 'S1'}}
219}
220
221struct S2 {
222  union { unsigned x, y; };
223  void f2();
224};
225
226void S2::f2() {
227  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
228  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
229  ++x + ++y; // no-warning
230  x + ++y; // no-warning
231}
232
233void f2(S2 &s) {
234  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
235  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
236  ++s.x + ++s.y; // no-warning
237  s.x + ++s.y; // no-warning
238}
239
240struct S3 {
241  union {
242    union {
243      unsigned x;
244    };
245  };
246  unsigned y;
247  void f3();
248};
249
250void S3::f3() {
251  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
252  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
253  ++x + ++y; // no-warning
254  x + ++y; // no-warning
255}
256
257void f3(S3 &s) {
258  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
259  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
260  ++s.x + ++s.y; // no-warning
261  s.x + ++s.y; // no-warning
262}
263
264struct S4 : S3 {
265  unsigned y;
266  void f4();
267};
268
269void S4::f4() {
270  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
271  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
272  ++x + ++y; // no-warning
273  x + ++y; // no-warning
274  ++S3::y + ++y; // no-warning
275  S3::y + ++y; // no-warning
276}
277
278void f4(S4 &s) {
279  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
280  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
281  ++s.x + ++s.y; // no-warning
282  s.x + ++s.y; // no-warning
283  ++s.S3::y + ++s.y; // no-warning
284  s.S3::y + ++s.y; // no-warning
285}
286
287static union {
288  unsigned Ux;
289  unsigned Uy;
290};
291
292void f5() {
293  ++Ux + ++Ux; // no-warning TODO {{multiple unsequenced modifications to}}
294  Ux + ++Ux; // no-warning TODO {{unsequenced modification and access to}}
295  ++Ux + ++Uy; // no-warning
296  Ux + ++Uy; // no-warning
297}
298
299void f6() {
300  struct S { unsigned x, y; } s;
301  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
302  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
303  ++s.x + ++s.y; // no-warning
304  s.x + ++s.y; // no-warning
305
306  struct { unsigned x, y; } t;
307  ++t.x + ++t.x; // no-warning TODO {{multiple unsequenced modifications to}}
308  t.x + ++t.x; // no-warning TODO {{unsequenced modification and access to}}
309  ++t.x + ++t.y; // no-warning
310  t.x + ++t.y; // no-warning
311}
312
313} // namespace members
314
315namespace references {
316void reference_f() {
317  // TODO: Check that we can see through references.
318  // For now this is completely unhandled.
319  int a;
320  int xs[10];
321  int &b = a;
322  int &c = b;
323  int &ra1 = c;
324  int &ra2 = b;
325  int other;
326
327  ++ra1 + ++ra2; // no-warning TODO {{multiple unsequenced modifications to}}
328  ra1 + ++ra2; // no-warning TODO {{unsequenced modification and access to}}
329  ++ra1 + ++other; // no-warning
330  ra1 + ++other; // no-warning
331
332  // Make sure we handle reference cycles.
333  int &ref_cycle = ref_cycle;
334  ++ref_cycle + ++ref_cycle; // cxx11-warning {{multiple unsequenced modifications to 'ref_cycle'}}
335                             // cxx17-warning@-1 {{multiple unsequenced modifications to 'ref_cycle'}}
336  ref_cycle + ++ref_cycle; // cxx11-warning {{unsequenced modification and access to 'ref_cycle'}}
337                           // cxx17-warning@-1 {{unsequenced modification and access to 'ref_cycle'}}
338}
339} // namespace references
340
341namespace std {
342  using size_t = decltype(sizeof(0));
343  template<typename> struct tuple_size;
344  template<size_t, typename> struct tuple_element { using type = int; };
345}
346namespace bindings {
347
348  struct A { int x, y; };
349  typedef int B[2];
350  struct C { template<int> int get(); };
351  struct D : A {};
352
353} // namespace bindings
354template<> struct std::tuple_size<bindings::C> { enum { value = 2 }; };
355namespace bindings {
356void testa() {
357  A a;
358  {
359    auto [x, y] = a;
360    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
361               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
362    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
363             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
364    ++x + ++y; // no-warning
365    ++x + y; // no-warning
366    ++x + ++a.x; // no-warning
367    ++x + a.x; // no-warning
368  }
369  {
370    auto &[x, y] = a;
371    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
372               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
373    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
374             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
375    ++x + ++y; // no-warning
376    ++x + y; // no-warning
377    ++x + ++a.x; // no-warning TODO
378    ++x + a.x; // no-warning TODO
379  }
380}
381void testb() {
382  B b;
383  {
384    auto [x, y] = b;
385    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
386               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
387    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
388             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
389    ++x + ++y; // no-warning
390    ++x + y; // no-warning
391    ++x + ++b[0]; // no-warning
392    ++x + b[0]; // no-warning
393  }
394  {
395    auto &[x, y] = b;
396    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
397               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
398    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
399             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
400    ++x + ++y; // no-warning
401    ++x + y; // no-warning
402    ++x + ++b[0]; // no-warning TODO
403    ++x + b[0]; // no-warning TODO
404  }
405}
406void testc() {
407  C c;
408  {
409    auto [x, y] = c;
410    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
411               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
412    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
413             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
414    ++x + ++y; // no-warning
415    ++x + y; // no-warning
416  }
417  {
418    auto &[x, y] = c;
419    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
420               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
421    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
422             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
423    ++x + ++y; // no-warning
424    ++x + y; // no-warning
425  }
426}
427void testd() {
428  D d;
429  {
430    auto [x, y] = d;
431    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
432               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
433    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
434             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
435    ++x + ++y; // no-warning
436    ++x + y; // no-warning
437    ++x + ++d.x; // no-warning
438    ++x + d.x; // no-warning
439  }
440  {
441    auto &[x, y] = d;
442    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
443               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
444    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
445             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
446    ++x + ++y; // no-warning
447    ++x + y; // no-warning
448    ++x + ++d.x; // no-warning TODO
449    ++x + d.x; // no-warning TODO
450  }
451}
452} // namespace bindings
453
454namespace templates {
455
456template <typename T>
457struct Bar {
458  T get() { return 0; }
459};
460
461template <typename X>
462struct Foo {
463  int Run();
464  Bar<int> bar;
465};
466
467enum E {e1, e2};
468bool operator&&(E, E);
469
470void foo(int, int);
471
472template <typename X>
473int Foo<X>::Run() {
474  char num = 0;
475
476  // Before instantiation, Clang may consider the builtin operator here as
477  // unresolved function calls, and treat the arguments as unordered when
478  // the builtin operator evaluatation is well-ordered.  Waiting until
479  // instantiation to check these expressions will prevent false positives.
480  if ((num = bar.get()) < 5 && num < 10) { }
481  if ((num = bar.get()) < 5 || num < 10) { }
482  if (static_cast<E>((num = bar.get()) < 5) || static_cast<E>(num < 10)) { }
483
484  if (static_cast<E>((num = bar.get()) < 5) && static_cast<E>(num < 10)) { }
485  // cxx11-warning@-1 {{unsequenced modification and access to 'num'}}
486  // cxx17-warning@-2 {{unsequenced modification and access to 'num'}}
487
488  foo(num++, num++);
489  // cxx11-warning@-1 2{{multiple unsequenced modifications to 'num'}}
490  // cxx17-warning@-2 2{{multiple unsequenced modifications to 'num'}}
491  return 1;
492}
493
494int x = Foo<int>().Run();
495// cxx11-note@-1 {{in instantiation of member function 'templates::Foo<int>::Run'}}
496// cxx17-note@-2 {{in instantiation of member function 'templates::Foo<int>::Run'}}
497
498
499template <typename T>
500int Run2() {
501  T t = static_cast<T>(0);
502  return (t = static_cast<T>(1)) && t;
503  // cxx11-warning@-1 {{unsequenced modification and access to 't'}}
504  // cxx17-warning@-2 {{unsequenced modification and access to 't'}}
505}
506
507int y = Run2<bool>();
508int z = Run2<E>();
509// cxx11-note@-1{{in instantiation of function template specialization 'templates::Run2<templates::E>' requested here}}
510// cxx17-note@-2{{in instantiation of function template specialization 'templates::Run2<templates::E>' requested here}}
511
512template <typename T> int var = sizeof(T);
513void test_var() {
514  var<int>++ + var<int>++; // cxx11-warning {{multiple unsequenced modifications to 'var<int>'}}
515                           // cxx17-warning@-1 {{multiple unsequenced modifications to 'var<int>'}}
516  var<int>++ + var<int>; // cxx11-warning {{unsequenced modification and access to 'var<int>'}}
517                         // cxx17-warning@-1 {{unsequenced modification and access to 'var<int>'}}
518  int &r = var<int>;
519  r++ + var<int>++; // no-warning TODO {{multiple unsequenced modifications to 'var<int>'}}
520  r++ + var<long>++; // no-warning
521}
522
523} // namespace templates
524