@@ -177,8 +177,13 @@ static TokenSequence TokenPasting(TokenSequence &&text) {
177
177
return result;
178
178
}
179
179
180
- TokenSequence Definition::Apply (
181
- const std::vector<TokenSequence> &args, Prescanner &prescanner) {
180
+ constexpr bool IsDefinedKeyword (CharBlock token) {
181
+ return token.size () == 7 && (token[0 ] == ' d' || token[0 ] == ' D' ) &&
182
+ ToLowerCaseLetters (token.ToString ()) == " defined" ;
183
+ }
184
+
185
+ TokenSequence Definition::Apply (const std::vector<TokenSequence> &args,
186
+ Prescanner &prescanner, bool inIfExpression) {
182
187
TokenSequence result;
183
188
bool skipping{false };
184
189
int parenthesesNesting{0 };
@@ -223,13 +228,16 @@ TokenSequence Definition::Apply(
223
228
const TokenSequence *arg{&args[index]};
224
229
std::optional<TokenSequence> replaced;
225
230
// Don't replace macros in the actual argument if it is preceded or
226
- // followed by the token-pasting operator ## in the replacement text.
227
- if (prev == 0 || !IsTokenPasting (replacement_.TokenAt (prev - 1 ))) {
231
+ // followed by the token-pasting operator ## in the replacement text,
232
+ // or if we have to worry about "defined(X)"/"defined X" in an
233
+ // #if/#elif expression.
234
+ if (!inIfExpression &&
235
+ (prev == 0 || !IsTokenPasting (replacement_.TokenAt (prev - 1 )))) {
228
236
auto next{replacement_.SkipBlanks (j + 1 )};
229
237
if (next >= tokens || !IsTokenPasting (replacement_.TokenAt (next))) {
230
238
// Apply macro replacement to the actual argument
231
- replaced =
232
- prescanner. preprocessor (). MacroReplacement ( *arg, prescanner);
239
+ replaced = prescanner. preprocessor (). MacroReplacement (
240
+ *arg, prescanner, nullptr , inIfExpression );
233
241
if (replaced) {
234
242
arg = &*replaced;
235
243
}
@@ -301,7 +309,7 @@ void Preprocessor::Undefine(std::string macro) { definitions_.erase(macro); }
301
309
302
310
std::optional<TokenSequence> Preprocessor::MacroReplacement (
303
311
const TokenSequence &input, Prescanner &prescanner,
304
- std::optional<std::size_t > *partialFunctionLikeMacro) {
312
+ std::optional<std::size_t > *partialFunctionLikeMacro, bool inIfExpression ) {
305
313
// Do quick scan for any use of a defined name.
306
314
if (definitions_.empty ()) {
307
315
return std::nullopt;
@@ -311,7 +319,7 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
311
319
for (; j < tokens; ++j) {
312
320
CharBlock token{input.TokenAt (j)};
313
321
if (!token.empty () && IsLegalIdentifierStart (token[0 ]) &&
314
- IsNameDefined (token)) {
322
+ ( IsNameDefined (token) || (inIfExpression && IsDefinedKeyword (token)) )) {
315
323
break ;
316
324
}
317
325
}
@@ -326,17 +334,17 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
326
334
// replacement text and attempt to proceed. Otherwise, return, so that
327
335
// the caller may try again with remaining tokens in its input.
328
336
auto CompleteFunctionLikeMacro{
329
- [this , &input, &prescanner, &result, &partialFunctionLikeMacro](
330
- std::size_t after, const TokenSequence &replacement,
337
+ [this , &input, &prescanner, &result, &partialFunctionLikeMacro,
338
+ inIfExpression]( std::size_t after, const TokenSequence &replacement,
331
339
std::size_t pFLMOffset) {
332
340
if (after < input.SizeInTokens ()) {
333
341
result.Put (replacement, 0 , pFLMOffset);
334
342
TokenSequence suffix;
335
343
suffix.Put (
336
344
replacement, pFLMOffset, replacement.SizeInTokens () - pFLMOffset);
337
345
suffix.Put (input, after, input.SizeInTokens () - after);
338
- auto further{
339
- ReplaceMacros ( suffix, prescanner, partialFunctionLikeMacro)};
346
+ auto further{ReplaceMacros (
347
+ suffix, prescanner, partialFunctionLikeMacro, inIfExpression )};
340
348
if (partialFunctionLikeMacro && *partialFunctionLikeMacro) {
341
349
// still not closed
342
350
**partialFunctionLikeMacro += result.SizeInTokens ();
@@ -357,7 +365,28 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
357
365
result.Put (input, j);
358
366
continue ;
359
367
}
368
+ // Process identifier in replacement text.
360
369
auto it{definitions_.find (token)};
370
+ // Is in the X in "defined(X)" or "defined X" in an #if/#elif expression?
371
+ if (inIfExpression) {
372
+ if (auto prev{result.SkipBlanksBackwards (result.SizeInTokens ())}) {
373
+ bool ok{true };
374
+ std::optional<std::size_t > rightParenthesis;
375
+ if (result.TokenAt (*prev).OnlyNonBlank () == ' (' ) {
376
+ prev = result.SkipBlanksBackwards (*prev);
377
+ rightParenthesis = input.SkipBlanks (j + 1 );
378
+ ok = *rightParenthesis < tokens &&
379
+ input.TokenAt (*rightParenthesis).OnlyNonBlank () == ' )' ;
380
+ }
381
+ if (ok && prev && IsDefinedKeyword (result.TokenAt (*prev))) {
382
+ result = TokenSequence{result, 0 , *prev}; // trims off "defined ("
383
+ char truth{it != definitions_.end () ? ' 1' : ' 0' };
384
+ result.Put (&truth, 1 , allSources_.CompilerInsertionProvenance (truth));
385
+ j = rightParenthesis.value_or (j);
386
+ continue ;
387
+ }
388
+ }
389
+ }
361
390
if (it == definitions_.end ()) {
362
391
result.Put (input, j);
363
392
continue ;
@@ -403,8 +432,8 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
403
432
}
404
433
std::optional<std::size_t > partialFLM;
405
434
def->set_isDisabled (true );
406
- TokenSequence replaced{TokenPasting (
407
- ReplaceMacros ( def->replacement (), prescanner, &partialFLM))};
435
+ TokenSequence replaced{TokenPasting (ReplaceMacros (
436
+ def->replacement (), prescanner, &partialFLM, inIfExpression ))};
408
437
def->set_isDisabled (false );
409
438
if (partialFLM &&
410
439
CompleteFunctionLikeMacro (j + 1 , replaced, *partialFLM)) {
@@ -476,11 +505,11 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
476
505
(n + 1 == argStart.size () ? k : argStart[n + 1 ] - 1 ) - at};
477
506
args.emplace_back (TokenSequence (input, at, count));
478
507
}
479
- TokenSequence applied{def->Apply (args, prescanner)};
508
+ TokenSequence applied{def->Apply (args, prescanner, inIfExpression )};
480
509
std::optional<std::size_t > partialFLM;
481
510
def->set_isDisabled (true );
482
- TokenSequence replaced{
483
- ReplaceMacros ( std::move (applied), prescanner, &partialFLM)};
511
+ TokenSequence replaced{ReplaceMacros (
512
+ std::move (applied), prescanner, &partialFLM, inIfExpression )};
484
513
def->set_isDisabled (false );
485
514
if (partialFLM &&
486
515
CompleteFunctionLikeMacro (k + 1 , replaced, *partialFLM)) {
@@ -501,9 +530,9 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
501
530
502
531
TokenSequence Preprocessor::ReplaceMacros (const TokenSequence &tokens,
503
532
Prescanner &prescanner,
504
- std::optional<std::size_t > *partialFunctionLikeMacro) {
505
- if (std::optional<TokenSequence> repl{
506
- MacroReplacement ( tokens, prescanner, partialFunctionLikeMacro)}) {
533
+ std::optional<std::size_t > *partialFunctionLikeMacro, bool inIfExpression ) {
534
+ if (std::optional<TokenSequence> repl{MacroReplacement (
535
+ tokens, prescanner, partialFunctionLikeMacro, inIfExpression )}) {
507
536
return std::move (*repl);
508
537
}
509
538
return tokens;
@@ -1215,50 +1244,27 @@ static std::int64_t ExpressionValue(const TokenSequence &token,
1215
1244
return left;
1216
1245
}
1217
1246
1218
- bool Preprocessor::IsIfPredicateTrue (const TokenSequence &expr ,
1247
+ bool Preprocessor::IsIfPredicateTrue (const TokenSequence &directive ,
1219
1248
std::size_t first, std::size_t exprTokens, Prescanner &prescanner) {
1220
- TokenSequence expr1{expr, first, exprTokens};
1221
- if (expr1.HasBlanks ()) {
1222
- expr1.RemoveBlanks ();
1223
- }
1224
- TokenSequence expr2;
1225
- for (std::size_t j{0 }; j < expr1.SizeInTokens (); ++j) {
1226
- if (ToLowerCaseLetters (expr1.TokenAt (j).ToString ()) == " defined" ) {
1227
- CharBlock name;
1228
- if (j + 3 < expr1.SizeInTokens () &&
1229
- expr1.TokenAt (j + 1 ).OnlyNonBlank () == ' (' &&
1230
- expr1.TokenAt (j + 3 ).OnlyNonBlank () == ' )' ) {
1231
- name = expr1.TokenAt (j + 2 );
1232
- j += 3 ;
1233
- } else if (j + 1 < expr1.SizeInTokens () &&
1234
- IsLegalIdentifierStart (expr1.TokenAt (j + 1 ))) {
1235
- name = expr1.TokenAt (++j);
1236
- }
1237
- if (!name.empty ()) {
1238
- char truth{IsNameDefined (name) ? ' 1' : ' 0' };
1239
- expr2.Put (&truth, 1 , allSources_.CompilerInsertionProvenance (truth));
1240
- continue ;
1241
- }
1242
- }
1243
- expr2.Put (expr1, j);
1244
- }
1245
- TokenSequence expr3{ReplaceMacros (expr2, prescanner)};
1246
- if (expr3.HasBlanks ()) {
1247
- expr3.RemoveBlanks ();
1249
+ TokenSequence expr{directive, first, exprTokens};
1250
+ TokenSequence replaced{
1251
+ ReplaceMacros (expr, prescanner, nullptr , /* inIfExpression=*/ true )};
1252
+ if (replaced.HasBlanks ()) {
1253
+ replaced.RemoveBlanks ();
1248
1254
}
1249
- if (expr3 .empty ()) {
1255
+ if (replaced .empty ()) {
1250
1256
prescanner.Say (expr.GetProvenanceRange (), " empty expression" _err_en_US);
1251
1257
return false ;
1252
1258
}
1253
1259
std::size_t atToken{0 };
1254
1260
std::optional<Message> error;
1255
- bool result{ExpressionValue (expr3 , 0 , &atToken, &error) != 0 };
1261
+ bool result{ExpressionValue (replaced , 0 , &atToken, &error) != 0 };
1256
1262
if (error) {
1257
1263
prescanner.Say (std::move (*error));
1258
- } else if (atToken < expr3 .SizeInTokens () &&
1259
- expr3 .TokenAt (atToken).ToString () != " !" ) {
1260
- prescanner.Say (expr3 .GetIntervalProvenanceRange (
1261
- atToken, expr3 .SizeInTokens () - atToken),
1264
+ } else if (atToken < replaced .SizeInTokens () &&
1265
+ replaced .TokenAt (atToken).ToString () != " !" ) {
1266
+ prescanner.Say (replaced .GetIntervalProvenanceRange (
1267
+ atToken, replaced .SizeInTokens () - atToken),
1262
1268
atToken == 0 ? " could not parse any expression" _err_en_US
1263
1269
: " excess characters after expression" _err_en_US);
1264
1270
}
0 commit comments