1 // RUN: %check_clang_tidy %s bugprone-macro-repeated-side-effects %t
2 
3 #define badA(x,y)  ((x)+((x)+(y))+(y))
bad(int ret,int a,int b)4 void bad(int ret, int a, int b) {
5   ret = badA(a++, b);
6   // CHECK-NOTES: :[[@LINE-1]]:14: warning: side effects in the 1st macro argument 'x' are repeated in macro expansion [bugprone-macro-repeated-side-effects]
7   // CHECK-NOTES: :[[@LINE-4]]:9: note: macro 'badA' defined here
8   ret = badA(++a, b);
9   // CHECK-NOTES: :[[@LINE-1]]:14: warning: side effects in the 1st macro argument 'x'
10   // CHECK-NOTES: :[[@LINE-7]]:9: note: macro 'badA' defined here
11   ret = badA(a--, b);
12   // CHECK-NOTES: :[[@LINE-1]]:14: warning: side effects in the 1st macro argument 'x'
13   // CHECK-NOTES: :[[@LINE-10]]:9: note: macro 'badA' defined here
14   ret = badA(--a, b);
15   // CHECK-NOTES: :[[@LINE-1]]:14: warning: side effects in the 1st macro argument 'x'
16   // CHECK-NOTES: :[[@LINE-13]]:9: note: macro 'badA' defined here
17   ret = badA(a, b++);
18   // CHECK-NOTES: :[[@LINE-1]]:17: warning: side effects in the 2nd macro argument 'y'
19   // CHECK-NOTES: :[[@LINE-16]]:9: note: macro 'badA' defined here
20   ret = badA(a, ++b);
21   // CHECK-NOTES: :[[@LINE-1]]:17: warning: side effects in the 2nd macro argument 'y'
22   // CHECK-NOTES: :[[@LINE-19]]:9: note: macro 'badA' defined here
23   ret = badA(a, b--);
24   // CHECK-NOTES: :[[@LINE-1]]:17: warning: side effects in the 2nd macro argument 'y'
25   // CHECK-NOTES: :[[@LINE-22]]:9: note: macro 'badA' defined here
26   ret = badA(a, --b);
27   // CHECK-NOTES: :[[@LINE-1]]:17: warning: side effects in the 2nd macro argument 'y'
28   // CHECK-NOTES: :[[@LINE-25]]:9: note: macro 'badA' defined here
29 }
30 
31 
32 #define MIN(A,B)     ((A) < (B) ? (A) : (B))                        // single ?:
33 #define LIMIT(X,A,B) ((X) < (A) ? (A) : ((X) > (B) ? (B) : (X)))    // two ?:
question(int x)34 void question(int x) {
35   MIN(x++, 12);
36   // CHECK-NOTES: :[[@LINE-1]]:7: warning: side effects in the 1st macro argument 'A'
37   // CHECK-NOTES: :[[@LINE-5]]:9: note: macro 'MIN' defined here
38   MIN(34, x++);
39   // CHECK-NOTES: :[[@LINE-1]]:11: warning: side effects in the 2nd macro argument 'B'
40   // CHECK-NOTES: :[[@LINE-8]]:9: note: macro 'MIN' defined here
41   LIMIT(x++, 0, 100);
42   // CHECK-NOTES: :[[@LINE-1]]:9: warning: side effects in the 1st macro argument 'X'
43   // CHECK-NOTES: :[[@LINE-10]]:9: note: macro 'LIMIT' defined here
44   LIMIT(20, x++, 100);
45   // CHECK-NOTES: :[[@LINE-1]]:13: warning: side effects in the 2nd macro argument 'A'
46   // CHECK-NOTES: :[[@LINE-13]]:9: note: macro 'LIMIT' defined here
47   LIMIT(20, 0, x++);
48   // CHECK-NOTES: :[[@LINE-1]]:16: warning: side effects in the 3rd macro argument 'B'
49   // CHECK-NOTES: :[[@LINE-16]]:9: note: macro 'LIMIT' defined here
50 }
51 
52 // False positive: Repeated side effects is intentional.
53 // It is hard to know when it's done by intention so right now we warn.
54 #define UNROLL(A)    {A A}
fp1(int i)55 void fp1(int i) {
56   UNROLL({ i++; });
57   // CHECK-NOTES: :[[@LINE-1]]:10: warning: side effects in the 1st macro argument 'A'
58   // CHECK-NOTES: :[[@LINE-4]]:9: note: macro 'UNROLL' defined here
59 }
60 
61 // Do not produce a false positive on a strchr() macro. Explanation; Currently the '?'
62 // triggers the test to bail out, because it cannot evaluate __builtin_constant_p(c).
63 #  define strchrs(s, c) \
64   (__extension__ (__builtin_constant_p (c) && !__builtin_constant_p (s)	      \
65 		  && (c) == '\0'					      \
66 		  ? (char *) __rawmemchr (s, c)				      \
67 		  : __builtin_strchr (s, c)))
__rawmemchr(char * a,char b)68 char* __rawmemchr(char* a, char b) {
69   return a;
70 }
pass(char * pstr,char ch)71 void pass(char* pstr, char ch) {
72   strchrs(pstr, ch++); // No error.
73 }
74 
75 // Check large arguments (t=20, u=21).
76 #define largeA(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, x, y, z) \
77   ((a) + (a) + (b) + (b) + (c) + (c) + (d) + (d) + (e) + (e) + (f) + (f) + (g) + (g) +    \
78    (h) + (h) + (i) + (i) + (j) + (j) + (k) + (k) + (l) + (l) + (m) + (m) + (n) + (n) +    \
79    (o) + (o) + (p) + (p) + (q) + (q) + (r) + (r) + (s) + (s) + (t) + (t) + (u) + (u) +    \
80    (v) + (v) + (x) + (x) + (y) + (y) + (z) + (z))
large(int a)81 void large(int a) {
82   largeA(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a++, 0, 0, 0, 0, 0, 0);
83   // CHECK-NOTES: :[[@LINE-1]]:64: warning: side effects in the 19th macro argument 's'
84   // CHECK-NOTES: :[[@LINE-8]]:9: note: macro 'largeA' defined here
85   largeA(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a++, 0, 0, 0, 0, 0);
86   // CHECK-NOTES: :[[@LINE-1]]:67: warning: side effects in the 20th macro argument 't'
87   // CHECK-NOTES: :[[@LINE-11]]:9: note: macro 'largeA' defined here
88   largeA(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a++, 0, 0, 0, 0);
89   // CHECK-NOTES: :[[@LINE-1]]:70: warning: side effects in the 21st macro argument 'u'
90   // CHECK-NOTES: :[[@LINE-14]]:9: note: macro 'largeA' defined here
91 }
92 
93 // Passing macro argument as argument to __builtin_constant_p and macros.
94 #define builtinbad(x)      (__builtin_constant_p(x) + (x) + (x))
95 #define builtingood1(x)    (__builtin_constant_p(x) + (x))
96 #define builtingood2(x)    ((__builtin_constant_p(x) && (x)) || (x))
97 #define macrobad(x)        (builtingood1(x) + (x) + (x))
98 #define macrogood(x)       (builtingood1(x) + (x))
builtins(int ret,int a)99 void builtins(int ret, int a) {
100   ret += builtinbad(a++);
101   // CHECK-NOTES: :[[@LINE-1]]:21: warning: side effects in the 1st macro argument 'x'
102   // CHECK-NOTES: :[[@LINE-8]]:9: note: macro 'builtinbad' defined here
103 
104   ret += builtingood1(a++);
105   ret += builtingood2(a++);
106 
107   ret += macrobad(a++);
108   // CHECK-NOTES: :[[@LINE-1]]:19: warning: side effects in the 1st macro argument 'x'
109   // CHECK-NOTES: :[[@LINE-12]]:9: note: macro 'macrobad' defined here
110 
111   ret += macrogood(a++);
112 }
113 
114 // Bail out for conditionals.
115 #define condB(x,y)  if(x) {x=y;} else {x=y + 1;}
conditionals(int a,int b)116 void conditionals(int a, int b)
117 {
118   condB(a, b++);
119 }
120 
121 void log(const char *s, int v);
122 #define LOG(val) log(#val, (val))
test_log(int a)123 void test_log(int a) {
124   LOG(a++);
125 }
126