summaryrefslogtreecommitdiffstats
path: root/test/SemaCXX/warn-unsequenced.cpp
blob: 9e8a5b46c218a56e9aaf12473be2bcee2bc63eb1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wno-unused %s

int f(int, int = 0);

struct A {
  int x, y;
};
struct S {
  S(int, int);
  int n;
};

void test() {
  int a;
  int xs[10];
  ++a = 0; // ok
  a + ++a; // expected-warning {{unsequenced modification and access to 'a'}}
  a = ++a; // ok
  a + a++; // expected-warning {{unsequenced modification and access to 'a'}}
  a = a++; // expected-warning {{multiple unsequenced modifications to 'a'}}
  ++ ++a; // ok
  (a++, a++); // ok
  ++a + ++a; // expected-warning {{multiple unsequenced modifications to 'a'}}
  a++ + a++; // expected-warning {{multiple unsequenced modifications}}
  (a++, a) = 0; // ok, increment is sequenced before value computation of LHS
  a = xs[++a]; // ok
  a = xs[a++]; // expected-warning {{multiple unsequenced modifications}}
  (a ? xs[0] : xs[1]) = ++a; // expected-warning {{unsequenced modification and access}}
  a = (++a, ++a); // ok
  a = (a++, ++a); // ok
  a = (a++, a++); // expected-warning {{multiple unsequenced modifications}}
  f(a, a); // ok
  f(a = 0, a); // expected-warning {{unsequenced modification and access}}
  f(a, a += 0); // expected-warning {{unsequenced modification and access}}
  f(a = 0, a = 0); // expected-warning {{multiple unsequenced modifications}}
  a = f(++a); // ok
  a = f(a++); // ok
  a = f(++a, a++); // expected-warning {{multiple unsequenced modifications}}

  // Compound assignment "A OP= B" is equivalent to "A = A OP B" except that A
  // is evaluated only once.
  (++a, a) = 1; // ok
  (++a, a) += 1; // ok
  a = ++a; // ok
  a += ++a; // expected-warning {{unsequenced modification and access}}

  A agg1 = { a++, a++ }; // ok
  A agg2 = { a++ + a, a++ }; // expected-warning {{unsequenced modification and access}}

  S str1(a++, a++); // expected-warning {{multiple unsequenced modifications}}
  S str2 = { a++, a++ }; // ok
  S str3 = { a++ + a, a++ }; // expected-warning {{unsequenced modification and access}}

  struct Z { A a; S s; } z = { { ++a, ++a }, { ++a, ++a } }; // ok
  a = S { ++a, a++ }.n; // ok
  A { ++a, a++ }.x; // ok
  a = A { ++a, a++ }.x; // expected-warning {{unsequenced modifications}}
  A { ++a, a++ }.x + A { ++a, a++ }.y; // expected-warning {{unsequenced modifications}}

  (xs[2] && (a = 0)) + a; // ok
  (0 && (a = 0)) + a; // ok
  (1 && (a = 0)) + a; // expected-warning {{unsequenced modification and access}}

  (xs[3] || (a = 0)) + a; // ok
  (0 || (a = 0)) + a; // expected-warning {{unsequenced modification and access}}
  (1 || (a = 0)) + a; // ok

  (xs[4] ? a : ++a) + a; // ok
  (0 ? a : ++a) + a; // expected-warning {{unsequenced modification and access}}
  (1 ? a : ++a) + a; // ok
  (0 ? a : a++) + a; // expected-warning {{unsequenced modification and access}}
  (1 ? a : a++) + a; // ok
  (xs[5] ? ++a : ++a) + a; // FIXME: warn here

  (++a, xs[6] ? ++a : 0) + a; // expected-warning {{unsequenced modification and access}}

  // Here, the read of the fourth 'a' might happen before or after the write to
  // the second 'a'.
  a += (a++, a) + a; // expected-warning {{unsequenced modification and access}}

  int *p = xs;
  a = *(a++, p); // ok
  a = a++ && a; // ok

  A *q = &agg1;
  (q = &agg2)->y = q->x; // expected-warning {{unsequenced modification and access to 'q'}}

  // This has undefined behavior if a == 0; otherwise, the side-effect of the
  // increment is sequenced before the value computation of 'f(a, a)', which is
  // sequenced before the value computation of the '&&', which is sequenced
  // before the assignment. We treat the sequencing in '&&' as being
  // unconditional.
  a = a++ && f(a, a);

  // This has undefined behavior if a != 0. FIXME: We should diagnose this.
  (a && a++) + a;

  (xs[7] && ++a) * (!xs[7] && ++a); // ok

  xs[0] = (a = 1, a); // ok
  (a -= 128) &= 128; // ok
  ++a += 1; // ok

  xs[8] ? ++a + a++ : 0; // expected-warning {{multiple unsequenced modifications}}
  xs[8] ? 0 : ++a + a++; // expected-warning {{multiple unsequenced modifications}}
  xs[8] ? ++a : a++; // ok

  xs[8] && (++a + a++); // expected-warning {{multiple unsequenced modifications}}
  xs[8] || (++a + a++); // expected-warning {{multiple unsequenced modifications}}

  (__builtin_classify_type(++a) ? 1 : 0) + ++a; // ok
  (__builtin_constant_p(++a) ? 1 : 0) + ++a; // ok
  (__builtin_object_size(&(++a, a), 0) ? 1 : 0) + ++a; // ok
  (__builtin_expect(++a, 0) ? 1 : 0) + ++a; // expected-warning {{multiple unsequenced modifications}}
}

namespace templates {

template <typename T>
struct Bar {
  T get() { return 0; }
};

template <typename X>
struct Foo {
  int Run();
  Bar<int> bar;
};

enum E {e1, e2};
bool operator&&(E, E);

void foo(int, int);

template <typename X>
int Foo<X>::Run() {
  char num = 0;

  // Before instantiation, Clang may consider the builtin operator here as
  // unresolved function calls, and treat the arguments as unordered when
  // the builtin operator evaluatation is well-ordered.  Waiting until
  // instantiation to check these expressions will prevent false positives.
  if ((num = bar.get()) < 5 && num < 10) { }
  if ((num = bar.get()) < 5 || num < 10) { }
  if (static_cast<E>((num = bar.get()) < 5) || static_cast<E>(num < 10)) { }

  if (static_cast<E>((num = bar.get()) < 5) && static_cast<E>(num < 10)) { }
  // expected-warning@-1 {{unsequenced modification and access to 'num'}}

  foo(num++, num++);
  // expected-warning@-1 2{{multiple unsequenced modifications to 'num'}}
  return 1;
}

int x = Foo<int>().Run();
// expected-note@-1 {{in instantiation of member function 'templates::Foo<int>::Run'}}


template <typename T>
int Run2() {
  T t = static_cast<T>(0);
  return (t = static_cast<T>(1)) && t;
  // expected-warning@-1 {{unsequenced modification and access to 't'}}
}

int y = Run2<bool>();
int z = Run2<E>();
// expected-note@-1{{in instantiation of function template specialization 'templates::Run2<templates::E>' requested here}}

}