Alexander Kornienko | a1a2933 | 2018-02-28 14:47:20 +0000 | [diff] [blame] | 1 | // RUN: %check_clang_tidy %s bugprone-macro-repeated-side-effects %t |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 2 | |
| 3 | #define badA(x,y) ((x)+((x)+(y))+(y)) |
| 4 | void bad(int ret, int a, int b) { |
| 5 | ret = badA(a++, b); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 8 | ret = badA(++a, b); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 11 | ret = badA(a--, b); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 14 | ret = badA(--a, b); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 17 | ret = badA(a, b++); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 20 | ret = badA(a, ++b); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 23 | ret = badA(a, b--); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 26 | ret = badA(a, --b); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 29 | } |
| 30 | |
| 31 | |
Daniel Marjamaki | e0384e5 | 2015-07-02 07:49:55 +0000 | [diff] [blame] | 32 | #define MIN(A,B) ((A) < (B) ? (A) : (B)) // single ?: |
| 33 | #define LIMIT(X,A,B) ((X) < (A) ? (A) : ((X) > (B) ? (B) : (X))) // two ?: |
| 34 | void question(int x) { |
| 35 | MIN(x++, 12); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | e0384e5 | 2015-07-02 07:49:55 +0000 | [diff] [blame] | 38 | MIN(34, x++); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | e0384e5 | 2015-07-02 07:49:55 +0000 | [diff] [blame] | 41 | LIMIT(x++, 0, 100); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | e0384e5 | 2015-07-02 07:49:55 +0000 | [diff] [blame] | 44 | LIMIT(20, x++, 100); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | e0384e5 | 2015-07-02 07:49:55 +0000 | [diff] [blame] | 47 | LIMIT(20, 0, x++); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | e0384e5 | 2015-07-02 07:49:55 +0000 | [diff] [blame] | 50 | } |
| 51 | |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 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} |
| 55 | void fp1(int i) { |
| 56 | UNROLL({ i++; }); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 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))) |
| 68 | char* __rawmemchr(char* a, char b) { |
| 69 | return a; |
| 70 | } |
| 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)) |
| 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); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 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); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 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); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 91 | } |
| 92 | |
Daniel Marjamaki | e0384e5 | 2015-07-02 07:49:55 +0000 | [diff] [blame] | 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)) |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 99 | void builtins(int ret, int a) { |
Daniel Marjamaki | e0384e5 | 2015-07-02 07:49:55 +0000 | [diff] [blame] | 100 | ret += builtinbad(a++); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | e0384e5 | 2015-07-02 07:49:55 +0000 | [diff] [blame] | 103 | |
| 104 | ret += builtingood1(a++); |
| 105 | ret += builtingood2(a++); |
| 106 | |
| 107 | ret += macrobad(a++); |
Jonas Toth | 0ec3185 | 2018-09-25 18:15:52 +0000 | [diff] [blame] | 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 |
Daniel Marjamaki | e0384e5 | 2015-07-02 07:49:55 +0000 | [diff] [blame] | 110 | |
| 111 | ret += macrogood(a++); |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 112 | } |
| 113 | |
| 114 | // Bail out for conditionals. |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 115 | #define condB(x,y) if(x) {x=y;} else {x=y + 1;} |
Daniel Marjamaki | e0384e5 | 2015-07-02 07:49:55 +0000 | [diff] [blame] | 116 | void conditionals(int a, int b) |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 117 | { |
Daniel Marjamaki | 71c9257 | 2015-06-17 14:19:35 +0000 | [diff] [blame] | 118 | condB(a, b++); |
| 119 | } |
| 120 | |
Alexander Kornienko | 5142c0d | 2016-04-23 00:00:08 +0000 | [diff] [blame] | 121 | void log(const char *s, int v); |
| 122 | #define LOG(val) log(#val, (val)) |
| 123 | void test_log(int a) { |
| 124 | LOG(a++); |
| 125 | } |