1*89a1d03eSRichard // RUN: %check_clang_tidy -std=c++14-or-later %s modernize-macro-to-enum %t -- -- -I%S/Inputs/macro-to-enum -fno-delayed-template-parsing
2*89a1d03eSRichard // C++14 or later required for binary literals.
3*89a1d03eSRichard
4*89a1d03eSRichard #if 1
5*89a1d03eSRichard #include "modernize-macro-to-enum.h"
6*89a1d03eSRichard
7*89a1d03eSRichard // These macros are skipped due to being inside a conditional compilation block.
8*89a1d03eSRichard #define GOO_RED 1
9*89a1d03eSRichard #define GOO_GREEN 2
10*89a1d03eSRichard #define GOO_BLUE 3
11*89a1d03eSRichard
12*89a1d03eSRichard #endif
13*89a1d03eSRichard
14*89a1d03eSRichard // Macros expanding to expressions involving only literals are converted.
15*89a1d03eSRichard #define EXPR1 1 - 1
16*89a1d03eSRichard #define EXPR2 1 + 1
17*89a1d03eSRichard #define EXPR3 1 * 1
18*89a1d03eSRichard #define EXPR4 1 / 1
19*89a1d03eSRichard #define EXPR5 1 | 1
20*89a1d03eSRichard #define EXPR6 1 & 1
21*89a1d03eSRichard #define EXPR7 1 << 1
22*89a1d03eSRichard #define EXPR8 1 >> 1
23*89a1d03eSRichard #define EXPR9 1 % 2
24*89a1d03eSRichard #define EXPR10 1 ^ 1
25*89a1d03eSRichard #define EXPR11 (1 + (2))
26*89a1d03eSRichard #define EXPR12 ((1) + (2 + 0) + (1 * 1) + (1 / 1) + (1 | 1 ) + (1 & 1) + (1 << 1) + (1 >> 1) + (1 % 2) + (1 ^ 1))
27*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-12]]:1: warning: replace macro with enum [modernize-macro-to-enum]
28*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR1' defines an integral constant; prefer an enum instead
29*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR2' defines an integral constant; prefer an enum instead
30*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR3' defines an integral constant; prefer an enum instead
31*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR4' defines an integral constant; prefer an enum instead
32*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR5' defines an integral constant; prefer an enum instead
33*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR6' defines an integral constant; prefer an enum instead
34*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR7' defines an integral constant; prefer an enum instead
35*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR8' defines an integral constant; prefer an enum instead
36*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR9' defines an integral constant; prefer an enum instead
37*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR10' defines an integral constant; prefer an enum instead
38*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR11' defines an integral constant; prefer an enum instead
39*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR12' defines an integral constant; prefer an enum instead
40*89a1d03eSRichard // CHECK-FIXES: enum {
41*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR1 = 1 - 1,
42*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR2 = 1 + 1,
43*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR3 = 1 * 1,
44*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR4 = 1 / 1,
45*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR5 = 1 | 1,
46*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR6 = 1 & 1,
47*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR7 = 1 << 1,
48*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR8 = 1 >> 1,
49*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR9 = 1 % 2,
50*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR10 = 1 ^ 1,
51*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR11 = (1 + (2)),
52*89a1d03eSRichard // CHECK-FIXES-NEXT: EXPR12 = ((1) + (2 + 0) + (1 * 1) + (1 / 1) + (1 | 1 ) + (1 & 1) + (1 << 1) + (1 >> 1) + (1 % 2) + (1 ^ 1))
53*89a1d03eSRichard // CHECK-FIXES-NEXT: };
54*89a1d03eSRichard
55*89a1d03eSRichard #define RED 0xFF0000
56*89a1d03eSRichard #define GREEN 0x00FF00
57*89a1d03eSRichard #define BLUE 0x0000FF
58*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:1: warning: replace macro with enum [modernize-macro-to-enum]
59*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: macro 'RED' defines an integral constant; prefer an enum instead
60*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: macro 'GREEN' defines an integral constant; prefer an enum instead
61*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: macro 'BLUE' defines an integral constant; prefer an enum instead
62*89a1d03eSRichard // CHECK-FIXES: enum {
63*89a1d03eSRichard // CHECK-FIXES-NEXT: RED = 0xFF0000,
64*89a1d03eSRichard // CHECK-FIXES-NEXT: GREEN = 0x00FF00,
65*89a1d03eSRichard // CHECK-FIXES-NEXT: BLUE = 0x0000FF
66*89a1d03eSRichard // CHECK-FIXES-NEXT: };
67*89a1d03eSRichard
68*89a1d03eSRichard // Verify that comments are preserved.
69*89a1d03eSRichard #define CoordModeOrigin 0 /* relative to the origin */
70*89a1d03eSRichard #define CoordModePrevious 1 /* relative to previous point */
71*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: replace macro with enum
72*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'CoordModeOrigin' defines an integral constant; prefer an enum instead
73*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'CoordModePrevious' defines an integral constant; prefer an enum instead
74*89a1d03eSRichard // CHECK-FIXES: enum {
75*89a1d03eSRichard // CHECK-FIXES-NEXT: CoordModeOrigin = 0, /* relative to the origin */
76*89a1d03eSRichard // CHECK-FIXES-NEXT: CoordModePrevious = 1 /* relative to previous point */
77*89a1d03eSRichard // CHECK-FIXES-NEXT: };
78*89a1d03eSRichard
79*89a1d03eSRichard // Verify that multiline comments are preserved.
80*89a1d03eSRichard #define BadDrawable 9 /* parameter not a Pixmap or Window */
81*89a1d03eSRichard #define BadAccess 10 /* depending on context:
82*89a1d03eSRichard - key/button already grabbed
83*89a1d03eSRichard - attempt to free an illegal
84*89a1d03eSRichard cmap entry
85*89a1d03eSRichard - attempt to store into a read-only
86*89a1d03eSRichard color map entry. */
87*89a1d03eSRichard // - attempt to modify the access control
88*89a1d03eSRichard // list from other than the local host.
89*89a1d03eSRichard //
90*89a1d03eSRichard #define BadAlloc 11 /* insufficient resources */
91*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-11]]:1: warning: replace macro with enum
92*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-12]]:9: warning: macro 'BadDrawable' defines an integral constant; prefer an enum instead
93*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-12]]:9: warning: macro 'BadAccess' defines an integral constant; prefer an enum instead
94*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: macro 'BadAlloc' defines an integral constant; prefer an enum instead
95*89a1d03eSRichard // CHECK-FIXES: enum {
96*89a1d03eSRichard // CHECK-FIXES-NEXT: BadDrawable = 9, /* parameter not a Pixmap or Window */
97*89a1d03eSRichard // CHECK-FIXES-NEXT: BadAccess = 10, /* depending on context:
98*89a1d03eSRichard // CHECK-FIXES-NEXT: - key/button already grabbed
99*89a1d03eSRichard // CHECK-FIXES-NEXT: - attempt to free an illegal
100*89a1d03eSRichard // CHECK-FIXES-NEXT: cmap entry
101*89a1d03eSRichard // CHECK-FIXES-NEXT: - attempt to store into a read-only
102*89a1d03eSRichard // CHECK-FIXES-NEXT: color map entry. */
103*89a1d03eSRichard // CHECK-FIXES-NEXT: // - attempt to modify the access control
104*89a1d03eSRichard // CHECK-FIXES-NEXT: // list from other than the local host.
105*89a1d03eSRichard // CHECK-FIXES-NEXT: //
106*89a1d03eSRichard // CHECK-FIXES-NEXT: BadAlloc = 11 /* insufficient resources */
107*89a1d03eSRichard // CHECK-FIXES-NEXT: };
108*89a1d03eSRichard
109*89a1d03eSRichard // Undefining a macro invalidates adjacent macros
110*89a1d03eSRichard // from being considered as an enum.
111*89a1d03eSRichard #define REMOVED1 1
112*89a1d03eSRichard #define REMOVED2 2
113*89a1d03eSRichard #define REMOVED3 3
114*89a1d03eSRichard #undef REMOVED2
115*89a1d03eSRichard #define VALID1 1
116*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: replace macro with enum
117*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: macro 'VALID1' defines an integral constant; prefer an enum instead
118*89a1d03eSRichard // CHECK-FIXES: enum {
119*89a1d03eSRichard // CHECK-FIXES-NEXT: VALID1 = 1
120*89a1d03eSRichard // CHECK-FIXES-NEXT: };
121*89a1d03eSRichard
122*89a1d03eSRichard #define UNDEF1 1
123*89a1d03eSRichard #define UNDEF2 2
124*89a1d03eSRichard #define UNDEF3 3
125*89a1d03eSRichard
126*89a1d03eSRichard // Undefining a macro later invalidates the set of possible adjacent macros
127*89a1d03eSRichard // from being considered as an enum.
128*89a1d03eSRichard #undef UNDEF2
129*89a1d03eSRichard
130*89a1d03eSRichard // Integral constants can have an optional sign
131*89a1d03eSRichard #define SIGNED1 +1
132*89a1d03eSRichard #define SIGNED2 -1
133*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: replace macro with enum
134*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'SIGNED1' defines an integral constant; prefer an enum instead
135*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'SIGNED2' defines an integral constant; prefer an enum instead
136*89a1d03eSRichard // CHECK-FIXES: enum {
137*89a1d03eSRichard // CHECK-FIXES-NEXT: SIGNED1 = +1,
138*89a1d03eSRichard // CHECK-FIXES-NEXT: SIGNED2 = -1
139*89a1d03eSRichard // CHECK-FIXES-NEXT: };
140*89a1d03eSRichard
141*89a1d03eSRichard // Integral constants with bitwise negated values
142*89a1d03eSRichard #define UNOP1 ~0U
143*89a1d03eSRichard #define UNOP2 ~1U
144*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: replace macro with enum
145*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'UNOP1' defines an integral constant; prefer an enum instead
146*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'UNOP2' defines an integral constant; prefer an enum instead
147*89a1d03eSRichard // CHECK-FIXES: enum {
148*89a1d03eSRichard // CHECK-FIXES-NEXT: UNOP1 = ~0U,
149*89a1d03eSRichard // CHECK-FIXES-NEXT: UNOP2 = ~1U
150*89a1d03eSRichard // CHECK-FIXES-NEXT: };
151*89a1d03eSRichard
152*89a1d03eSRichard // Integral constants in other bases and with suffixes are OK
153*89a1d03eSRichard #define BASE1 0777 // octal
154*89a1d03eSRichard #define BASE2 0xDEAD // hexadecimal
155*89a1d03eSRichard #define BASE3 0b0011 // binary
156*89a1d03eSRichard #define SUFFIX1 +1U
157*89a1d03eSRichard #define SUFFIX2 -1L
158*89a1d03eSRichard #define SUFFIX3 +1UL
159*89a1d03eSRichard #define SUFFIX4 -1LL
160*89a1d03eSRichard #define SUFFIX5 +1ULL
161*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-8]]:1: warning: replace macro with enum
162*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'BASE1' defines an integral constant; prefer an enum instead
163*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'BASE2' defines an integral constant; prefer an enum instead
164*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'BASE3' defines an integral constant; prefer an enum instead
165*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'SUFFIX1' defines an integral constant; prefer an enum instead
166*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'SUFFIX2' defines an integral constant; prefer an enum instead
167*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'SUFFIX3' defines an integral constant; prefer an enum instead
168*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'SUFFIX4' defines an integral constant; prefer an enum instead
169*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'SUFFIX5' defines an integral constant; prefer an enum instead
170*89a1d03eSRichard // CHECK-FIXES: enum {
171*89a1d03eSRichard // CHECK-FIXES-NEXT: BASE1 = 0777, // octal
172*89a1d03eSRichard // CHECK-FIXES-NEXT: BASE2 = 0xDEAD, // hexadecimal
173*89a1d03eSRichard // CHECK-FIXES-NEXT: BASE3 = 0b0011, // binary
174*89a1d03eSRichard // CHECK-FIXES-NEXT: SUFFIX1 = +1U,
175*89a1d03eSRichard // CHECK-FIXES-NEXT: SUFFIX2 = -1L,
176*89a1d03eSRichard // CHECK-FIXES-NEXT: SUFFIX3 = +1UL,
177*89a1d03eSRichard // CHECK-FIXES-NEXT: SUFFIX4 = -1LL,
178*89a1d03eSRichard // CHECK-FIXES-NEXT: SUFFIX5 = +1ULL
179*89a1d03eSRichard // CHECK-FIXES-NEXT: };
180*89a1d03eSRichard
181*89a1d03eSRichard // A limited form of constant expression is recognized: a parenthesized
182*89a1d03eSRichard // literal or a parenthesized literal with the unary operators +, - or ~.
183*89a1d03eSRichard #define PAREN1 (-1)
184*89a1d03eSRichard #define PAREN2 (1)
185*89a1d03eSRichard #define PAREN3 (+1)
186*89a1d03eSRichard #define PAREN4 (~1)
187*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:1: warning: replace macro with enum
188*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: macro 'PAREN1' defines an integral constant; prefer an enum instead
189*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: macro 'PAREN2' defines an integral constant; prefer an enum instead
190*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: macro 'PAREN3' defines an integral constant; prefer an enum instead
191*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: macro 'PAREN4' defines an integral constant; prefer an enum instead
192*89a1d03eSRichard // CHECK-FIXES: enum {
193*89a1d03eSRichard // CHECK-FIXES-NEXT: PAREN1 = (-1),
194*89a1d03eSRichard // CHECK-FIXES-NEXT: PAREN2 = (1),
195*89a1d03eSRichard // CHECK-FIXES-NEXT: PAREN3 = (+1),
196*89a1d03eSRichard // CHECK-FIXES-NEXT: PAREN4 = (~1)
197*89a1d03eSRichard // CHECK-FIXES-NEXT: };
198*89a1d03eSRichard
199*89a1d03eSRichard // More complicated parenthesized expressions are excluded.
200*89a1d03eSRichard // Expansions that are not surrounded by parentheses are excluded.
201*89a1d03eSRichard // Nested matching parentheses are stripped.
202*89a1d03eSRichard #define COMPLEX_PAREN1 (x+1)
203*89a1d03eSRichard #define COMPLEX_PAREN2 (x+1
204*89a1d03eSRichard #define COMPLEX_PAREN3 (())
205*89a1d03eSRichard #define COMPLEX_PAREN4 ()
206*89a1d03eSRichard #define COMPLEX_PAREN5 (+1)
207*89a1d03eSRichard #define COMPLEX_PAREN6 ((+1))
208*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:1: warning: replace macro with enum
209*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'COMPLEX_PAREN5' defines an integral constant; prefer an enum instead
210*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'COMPLEX_PAREN6' defines an integral constant; prefer an enum instead
211*89a1d03eSRichard // CHECK-FIXES: enum {
212*89a1d03eSRichard // CHECK-FIXES-NEXT: COMPLEX_PAREN5 = (+1),
213*89a1d03eSRichard // CHECK-FIXES-NEXT: COMPLEX_PAREN6 = ((+1))
214*89a1d03eSRichard // CHECK-FIXES-NEXT: };
215*89a1d03eSRichard
216*89a1d03eSRichard #define GOOD_COMMA (1, 2)
217*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: replace macro with enum
218*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: macro 'GOOD_COMMA' defines an integral constant; prefer an enum instead
219*89a1d03eSRichard // CHECK-FIXES: enum {
220*89a1d03eSRichard // CHECK-FIXES-NEXT: GOOD_COMMA = (1, 2)
221*89a1d03eSRichard // CHECK-FIXES-NEXT: };
222*89a1d03eSRichard
223*89a1d03eSRichard // Macros appearing in conditional expressions can't be replaced
224*89a1d03eSRichard // by enums.
225*89a1d03eSRichard #define USE_FOO 1
226*89a1d03eSRichard #define USE_BAR 0
227*89a1d03eSRichard #define USE_IF 1
228*89a1d03eSRichard #define USE_ELIF 1
229*89a1d03eSRichard #define USE_IFDEF 1
230*89a1d03eSRichard #define USE_IFNDEF 1
231*89a1d03eSRichard
232*89a1d03eSRichard // Undef'ing first and then defining later should still exclude this macro
233*89a1d03eSRichard #undef USE_UINT64
234*89a1d03eSRichard #define USE_UINT64 0
235*89a1d03eSRichard #undef USE_INT64
236*89a1d03eSRichard #define USE_INT64 0
237*89a1d03eSRichard
238*89a1d03eSRichard #if defined(USE_FOO) && USE_FOO
239*89a1d03eSRichard extern void foo();
240*89a1d03eSRichard #else
foo()241*89a1d03eSRichard inline void foo() {}
242*89a1d03eSRichard #endif
243*89a1d03eSRichard
244*89a1d03eSRichard #if USE_BAR
245*89a1d03eSRichard extern void bar();
246*89a1d03eSRichard #else
bar()247*89a1d03eSRichard inline void bar() {}
248*89a1d03eSRichard #endif
249*89a1d03eSRichard
250*89a1d03eSRichard #if USE_IF
used_if()251*89a1d03eSRichard inline void used_if() {}
252*89a1d03eSRichard #endif
253*89a1d03eSRichard
254*89a1d03eSRichard #if 0
255*89a1d03eSRichard #elif USE_ELIF
used_elif()256*89a1d03eSRichard inline void used_elif() {}
257*89a1d03eSRichard #endif
258*89a1d03eSRichard
259*89a1d03eSRichard #ifdef USE_IFDEF
used_ifdef()260*89a1d03eSRichard inline void used_ifdef() {}
261*89a1d03eSRichard #endif
262*89a1d03eSRichard
263*89a1d03eSRichard #ifndef USE_IFNDEF
264*89a1d03eSRichard #else
used_ifndef()265*89a1d03eSRichard inline void used_ifndef() {}
266*89a1d03eSRichard #endif
267*89a1d03eSRichard
268*89a1d03eSRichard // Regular conditional compilation blocks should leave previous
269*89a1d03eSRichard // macro enums alone.
270*89a1d03eSRichard #if 0
271*89a1d03eSRichard #include <non-existent.h>
272*89a1d03eSRichard #endif
273*89a1d03eSRichard
274*89a1d03eSRichard // Conditional compilation blocks invalidate adjacent macros
275*89a1d03eSRichard // from being considered as an enum. Conditionally compiled
276*89a1d03eSRichard // blocks could contain macros that should rightly be included
277*89a1d03eSRichard // in the enum, but we can't explore multiple branches of a
278*89a1d03eSRichard // conditionally compiled section in clang-tidy, only the active
279*89a1d03eSRichard // branch based on compilation options.
280*89a1d03eSRichard #define CONDITION1 1
281*89a1d03eSRichard #define CONDITION2 2
282*89a1d03eSRichard #if 0
283*89a1d03eSRichard #define CONDITION3 3
284*89a1d03eSRichard #else
285*89a1d03eSRichard #define CONDITION3 -3
286*89a1d03eSRichard #endif
287*89a1d03eSRichard
288*89a1d03eSRichard #define IFDEF1 1
289*89a1d03eSRichard #define IFDEF2 2
290*89a1d03eSRichard #ifdef FROB
291*89a1d03eSRichard #define IFDEF3 3
292*89a1d03eSRichard #endif
293*89a1d03eSRichard
294*89a1d03eSRichard #define IFNDEF1 1
295*89a1d03eSRichard #define IFNDEF2 2
296*89a1d03eSRichard #ifndef GOINK
297*89a1d03eSRichard #define IFNDEF3 3
298*89a1d03eSRichard #endif
299*89a1d03eSRichard
300*89a1d03eSRichard // Macros used in conditions are invalidated, even if they look
301*89a1d03eSRichard // like enums after they are used in conditions.
302*89a1d03eSRichard #if DEFINED_LATER1
303*89a1d03eSRichard #endif
304*89a1d03eSRichard #ifdef DEFINED_LATER2
305*89a1d03eSRichard #endif
306*89a1d03eSRichard #ifndef DEFINED_LATER3
307*89a1d03eSRichard #endif
308*89a1d03eSRichard #undef DEFINED_LATER4
309*89a1d03eSRichard #if ((defined(DEFINED_LATER5) || DEFINED_LATER6) && DEFINED_LATER7) || (DEFINED_LATER8 > 10)
310*89a1d03eSRichard #endif
311*89a1d03eSRichard
312*89a1d03eSRichard #define DEFINED_LATER1 1
313*89a1d03eSRichard #define DEFINED_LATER2 2
314*89a1d03eSRichard #define DEFINED_LATER3 3
315*89a1d03eSRichard #define DEFINED_LATER4 4
316*89a1d03eSRichard #define DEFINED_LATER5 5
317*89a1d03eSRichard #define DEFINED_LATER6 6
318*89a1d03eSRichard #define DEFINED_LATER7 7
319*89a1d03eSRichard #define DEFINED_LATER8 8
320*89a1d03eSRichard
321*89a1d03eSRichard // Sometimes an argument to ifdef can be classified as a keyword token.
322*89a1d03eSRichard #ifdef __restrict
323*89a1d03eSRichard #endif
324*89a1d03eSRichard
325*89a1d03eSRichard // These macros do not expand to integral constants.
326*89a1d03eSRichard #define HELLO "Hello, "
327*89a1d03eSRichard #define WORLD "World"
328*89a1d03eSRichard #define EPS1 1.0F
329*89a1d03eSRichard #define EPS2 1e5
330*89a1d03eSRichard #define EPS3 1.
331*89a1d03eSRichard
332*89a1d03eSRichard // Ignore macros invoking comma operator unless they are inside parens.
333*89a1d03eSRichard #define BAD_COMMA 1, 2
334*89a1d03eSRichard
335*89a1d03eSRichard extern void draw(unsigned int Color);
336*89a1d03eSRichard
f()337*89a1d03eSRichard void f()
338*89a1d03eSRichard {
339*89a1d03eSRichard // Usage of macros converted to enums should still compile.
340*89a1d03eSRichard draw(RED);
341*89a1d03eSRichard draw(GREEN | RED);
342*89a1d03eSRichard draw(BLUE + RED);
343*89a1d03eSRichard }
344*89a1d03eSRichard
345*89a1d03eSRichard // Ignore macros defined inside a top-level function definition.
g(int x)346*89a1d03eSRichard void g(int x)
347*89a1d03eSRichard {
348*89a1d03eSRichard if (x != 0) {
349*89a1d03eSRichard #define INSIDE1 1
350*89a1d03eSRichard #define INSIDE2 2
351*89a1d03eSRichard if (INSIDE1 > 1) {
352*89a1d03eSRichard f();
353*89a1d03eSRichard }
354*89a1d03eSRichard } else {
355*89a1d03eSRichard if (INSIDE2 == 1) {
356*89a1d03eSRichard f();
357*89a1d03eSRichard }
358*89a1d03eSRichard }
359*89a1d03eSRichard }
360*89a1d03eSRichard
361*89a1d03eSRichard // Ignore macros defined inside a top-level function declaration.
362*89a1d03eSRichard extern void g2(
363*89a1d03eSRichard #define INSIDE3 3
364*89a1d03eSRichard #define INSIDE4 4
365*89a1d03eSRichard );
366*89a1d03eSRichard
367*89a1d03eSRichard // Ignore macros defined inside a record (structure) declaration.
368*89a1d03eSRichard struct S {
369*89a1d03eSRichard #define INSIDE5 5
370*89a1d03eSRichard #define INSIDE6 6
371*89a1d03eSRichard char storage[INSIDE5];
372*89a1d03eSRichard };
373*89a1d03eSRichard class C {
374*89a1d03eSRichard #define INSIDE7 7
375*89a1d03eSRichard #define INSIDE8 8
376*89a1d03eSRichard };
377*89a1d03eSRichard
378*89a1d03eSRichard // Ignore macros defined inside a template function definition.
379*89a1d03eSRichard template <int N>
380*89a1d03eSRichard #define INSIDE9 9
fn()381*89a1d03eSRichard bool fn()
382*89a1d03eSRichard {
383*89a1d03eSRichard #define INSIDE10 10
384*89a1d03eSRichard return INSIDE9 > 1 || INSIDE10 < N;
385*89a1d03eSRichard }
386*89a1d03eSRichard
387*89a1d03eSRichard // Ignore macros defined inside a variable declaration.
388*89a1d03eSRichard extern int
389*89a1d03eSRichard #define INSIDE11 11
390*89a1d03eSRichard v;
391*89a1d03eSRichard
392*89a1d03eSRichard // Ignore macros defined inside a template class definition.
393*89a1d03eSRichard template <int N>
394*89a1d03eSRichard class C2 {
395*89a1d03eSRichard public:
396*89a1d03eSRichard #define INSIDE12 12
397*89a1d03eSRichard char storage[N];
f()398*89a1d03eSRichard bool f() {
399*89a1d03eSRichard return N > INSIDE12;
400*89a1d03eSRichard }
401*89a1d03eSRichard bool g();
402*89a1d03eSRichard };
403*89a1d03eSRichard
404*89a1d03eSRichard // Ignore macros defined inside a template member function definition.
405*89a1d03eSRichard template <int N>
406*89a1d03eSRichard #define INSIDE13 13
g()407*89a1d03eSRichard bool C2<N>::g() {
408*89a1d03eSRichard #define INSIDE14 14
409*89a1d03eSRichard return N < INSIDE12 || N > INSIDE13 || INSIDE14 > N;
410*89a1d03eSRichard };
411*89a1d03eSRichard
412*89a1d03eSRichard // Ignore macros defined inside a template type alias.
413*89a1d03eSRichard template <typename T>
414*89a1d03eSRichard class C3 {
415*89a1d03eSRichard T data;
416*89a1d03eSRichard };
417*89a1d03eSRichard template <typename T>
418*89a1d03eSRichard #define INSIDE15 15
419*89a1d03eSRichard using Data = C3<T[INSIDE15]>;
420*89a1d03eSRichard
421*89a1d03eSRichard // Ignore macros defined inside a type alias.
422*89a1d03eSRichard using Data2 =
423*89a1d03eSRichard #define INSIDE16 16
424*89a1d03eSRichard char[INSIDE16];
425*89a1d03eSRichard
426*89a1d03eSRichard // Ignore macros defined inside a (constexpr) variable definition.
427*89a1d03eSRichard constexpr int
428*89a1d03eSRichard #define INSIDE17 17
429*89a1d03eSRichard value = INSIDE17;
430*89a1d03eSRichard
431*89a1d03eSRichard // Ignore macros used in the expansion of other macros
432*89a1d03eSRichard #define INSIDE18 18
433*89a1d03eSRichard #define INSIDE19 19
434*89a1d03eSRichard
435*89a1d03eSRichard #define CONCAT(n_, s_) n_##s_
436*89a1d03eSRichard #define FN_NAME(n_, s_) CONCAT(n_, s_)
437*89a1d03eSRichard
438*89a1d03eSRichard extern void FN_NAME(g, INSIDE18)();
439*89a1d03eSRichard
gg()440*89a1d03eSRichard void gg()
441*89a1d03eSRichard {
442*89a1d03eSRichard g18();
443*89a1d03eSRichard }
444