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