1 // RUN: %check_clang_tidy %s android-comparison-in-temp-failure-retry %t
2 
3 #define TEMP_FAILURE_RETRY(x)                                                  \
4   ({                                                                           \
5     typeof(x) __z;                                                             \
6     do                                                                         \
7       __z = (x);                                                               \
8     while (__z == -1);                                                         \
9     __z;                                                                       \
10   })
11 
12 int foo();
13 int bar(int a);
14 
test()15 void test() {
16   int i;
17   TEMP_FAILURE_RETRY((i = foo()));
18   TEMP_FAILURE_RETRY(foo());
19   TEMP_FAILURE_RETRY((foo()));
20 
21   TEMP_FAILURE_RETRY(foo() == 1);
22   // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: top-level comparison in TEMP_FAILURE_RETRY [android-comparison-in-temp-failure-retry]
23   TEMP_FAILURE_RETRY((foo() == 1));
24   // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: top-level comparison in TEMP_FAILURE_RETRY
25   TEMP_FAILURE_RETRY((int)(foo() == 1));
26   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: top-level comparison in TEMP_FAILURE_RETRY
27 
28   TEMP_FAILURE_RETRY(bar(foo() == 1));
29   TEMP_FAILURE_RETRY((bar(foo() == 1)));
30   TEMP_FAILURE_RETRY((bar(foo() == 1)) == 1);
31   // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: top-level comparison in TEMP_FAILURE_RETRY
32   TEMP_FAILURE_RETRY(((bar(foo() == 1)) == 1));
33   // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: top-level comparison in TEMP_FAILURE_RETRY
34   TEMP_FAILURE_RETRY((int)((bar(foo() == 1)) == 1));
35   // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: top-level comparison in TEMP_FAILURE_RETRY
36 
37 #define INDIRECT TEMP_FAILURE_RETRY
38   INDIRECT(foo());
39   INDIRECT((foo() == 1));
40   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: top-level comparison in TEMP_FAILURE_RETRY
41   INDIRECT(bar(foo() == 1));
42   INDIRECT((int)((bar(foo() == 1)) == 1));
43   // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: top-level comparison in TEMP_FAILURE_RETRY
44 
45 #define TFR(x) TEMP_FAILURE_RETRY(x)
46   TFR(foo());
47   TFR((foo() == 1));
48   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: top-level comparison in TEMP_FAILURE_RETRY
49   TFR(bar(foo() == 1));
50   TFR((int)((bar(foo() == 1)) == 1));
51   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: top-level comparison in TEMP_FAILURE_RETRY
52 
53 #define ADD_TFR(x) (1 + TEMP_FAILURE_RETRY(x) + 1)
54   ADD_TFR(foo());
55   ADD_TFR(foo() == 1);
56   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: top-level comparison in TEMP_FAILURE_RETRY
57 
58   ADD_TFR(bar(foo() == 1));
59   ADD_TFR((int)((bar(foo() == 1)) == 1));
60   // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: top-level comparison in TEMP_FAILURE_RETRY
61 
62 #define ADDP_TFR(x) (1 + TEMP_FAILURE_RETRY((x)) + 1)
63   ADDP_TFR(foo());
64   ADDP_TFR((foo() == 1));
65   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: top-level comparison in TEMP_FAILURE_RETRY
66 
67   ADDP_TFR(bar(foo() == 1));
68   ADDP_TFR((int)((bar(foo() == 1)) == 1));
69   // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: top-level comparison in TEMP_FAILURE_RETRY
70 
71 #define MACRO TEMP_FAILURE_RETRY(foo() == 1)
72   MACRO;
73   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: top-level comparison in TEMP_FAILURE_RETRY
74 
75   // Be sure that being a macro arg doesn't mess with this.
76 #define ID(x) (x)
77   ID(ADDP_TFR(bar(foo() == 1)));
78   ID(ADDP_TFR(bar(foo() == 1) == 1));
79   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: top-level comparison in TEMP_FAILURE_RETRY
80   ID(MACRO);
81   // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: top-level comparison in TEMP_FAILURE_RETRY
82 
83 #define CMP(x) x == 1
84   TEMP_FAILURE_RETRY(CMP(foo()));
85   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: top-level comparison in TEMP_FAILURE_RETRY
86 }
87 
88 // Be sure that it works inside of things like loops, if statements, etc.
control_flow()89 void control_flow() {
90   do {
91     if (TEMP_FAILURE_RETRY(foo())) {
92     }
93 
94     if (TEMP_FAILURE_RETRY(foo() == 1)) {
95       // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: top-level comparison in TEMP_FAILURE_RETRY
96     }
97 
98     if (TEMP_FAILURE_RETRY(bar(foo() == 1))) {
99     }
100 
101     if (TEMP_FAILURE_RETRY(bar(foo() == 1) == 1)) {
102       // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: top-level comparison in TEMP_FAILURE_RETRY
103     }
104   } while (TEMP_FAILURE_RETRY(foo() == 1));
105   // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: top-level comparison in TEMP_FAILURE_RETRY
106 }
107 
with_nondependent_variable_type()108 void with_nondependent_variable_type() {
109 #undef TEMP_FAILURE_RETRY
110 #define TEMP_FAILURE_RETRY(x)                                                  \
111   ({                                                                           \
112     long int __z;                                                              \
113     do                                                                         \
114       __z = (x);                                                               \
115     while (__z == -1);                                                         \
116     __z;                                                                       \
117   })
118 
119   TEMP_FAILURE_RETRY((foo()));
120   TEMP_FAILURE_RETRY((int)(foo() == 1));
121   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: top-level comparison in TEMP_FAILURE_RETRY
122   TEMP_FAILURE_RETRY((bar(foo() == 1)));
123   TEMP_FAILURE_RETRY((int)((bar(foo() == 1)) == 1));
124   // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: top-level comparison in TEMP_FAILURE_RETRY
125 }
126 
127 // I can't find a case where TEMP_FAILURE_RETRY is implemented like this, but if
128 // we can cheaply support it, I don't see why not.
obscured_temp_failure_retry()129 void obscured_temp_failure_retry() {
130 #undef TEMP_FAILURE_RETRY
131 #define IMPL(x)                                                                \
132   ({                                                                           \
133     typeof(x) __z;                                                             \
134     do                                                                         \
135       __z = (x);                                                               \
136     while (__z == -1);                                                         \
137     __z;                                                                       \
138   })
139 
140 #define IMPL2(x) IMPL(x)
141 #define TEMP_FAILURE_RETRY(x) IMPL2(x)
142   TEMP_FAILURE_RETRY((foo()));
143   TEMP_FAILURE_RETRY((int)(foo() == 1));
144   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: top-level comparison in TEMP_FAILURE_RETRY
145   TEMP_FAILURE_RETRY((bar(foo() == 1)));
146   TEMP_FAILURE_RETRY((int)((bar(foo() == 1)) == 1));
147   // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: top-level comparison in TEMP_FAILURE_RETRY
148 }
149