@@ -177,8 +177,13 @@ static TokenSequence TokenPasting(TokenSequence &&text) {
177177 return result;
178178}
179179
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) {
182187 TokenSequence result;
183188 bool skipping{false };
184189 int parenthesesNesting{0 };
@@ -223,13 +228,16 @@ TokenSequence Definition::Apply(
223228 const TokenSequence *arg{&args[index]};
224229 std::optional<TokenSequence> replaced;
225230 // 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 )))) {
228236 auto next{replacement_.SkipBlanks (j + 1 )};
229237 if (next >= tokens || !IsTokenPasting (replacement_.TokenAt (next))) {
230238 // 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 );
233241 if (replaced) {
234242 arg = &*replaced;
235243 }
@@ -301,7 +309,7 @@ void Preprocessor::Undefine(std::string macro) { definitions_.erase(macro); }
301309
302310std::optional<TokenSequence> Preprocessor::MacroReplacement (
303311 const TokenSequence &input, Prescanner &prescanner,
304- std::optional<std::size_t > *partialFunctionLikeMacro) {
312+ std::optional<std::size_t > *partialFunctionLikeMacro, bool inIfExpression ) {
305313 // Do quick scan for any use of a defined name.
306314 if (definitions_.empty ()) {
307315 return std::nullopt ;
@@ -311,7 +319,7 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
311319 for (; j < tokens; ++j) {
312320 CharBlock token{input.TokenAt (j)};
313321 if (!token.empty () && IsLegalIdentifierStart (token[0 ]) &&
314- IsNameDefined (token)) {
322+ ( IsNameDefined (token) || (inIfExpression && IsDefinedKeyword (token)) )) {
315323 break ;
316324 }
317325 }
@@ -326,17 +334,17 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
326334 // replacement text and attempt to proceed. Otherwise, return, so that
327335 // the caller may try again with remaining tokens in its input.
328336 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,
331339 std::size_t pFLMOffset) {
332340 if (after < input.SizeInTokens ()) {
333341 result.Put (replacement, 0 , pFLMOffset);
334342 TokenSequence suffix;
335343 suffix.Put (
336344 replacement, pFLMOffset, replacement.SizeInTokens () - pFLMOffset);
337345 suffix.Put (input, after, input.SizeInTokens () - after);
338- auto further{
339- ReplaceMacros ( suffix, prescanner, partialFunctionLikeMacro)};
346+ auto further{ReplaceMacros (
347+ suffix, prescanner, partialFunctionLikeMacro, inIfExpression )};
340348 if (partialFunctionLikeMacro && *partialFunctionLikeMacro) {
341349 // still not closed
342350 **partialFunctionLikeMacro += result.SizeInTokens ();
@@ -357,7 +365,28 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
357365 result.Put (input, j);
358366 continue ;
359367 }
368+ // Process identifier in replacement text.
360369 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+ }
361390 if (it == definitions_.end ()) {
362391 result.Put (input, j);
363392 continue ;
@@ -403,8 +432,8 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
403432 }
404433 std::optional<std::size_t > partialFLM;
405434 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 ))};
408437 def->set_isDisabled (false );
409438 if (partialFLM &&
410439 CompleteFunctionLikeMacro (j + 1 , replaced, *partialFLM)) {
@@ -476,11 +505,11 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
476505 (n + 1 == argStart.size () ? k : argStart[n + 1 ] - 1 ) - at};
477506 args.emplace_back (TokenSequence (input, at, count));
478507 }
479- TokenSequence applied{def->Apply (args, prescanner)};
508+ TokenSequence applied{def->Apply (args, prescanner, inIfExpression )};
480509 std::optional<std::size_t > partialFLM;
481510 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 )};
484513 def->set_isDisabled (false );
485514 if (partialFLM &&
486515 CompleteFunctionLikeMacro (k + 1 , replaced, *partialFLM)) {
@@ -501,9 +530,9 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
501530
502531TokenSequence Preprocessor::ReplaceMacros (const TokenSequence &tokens,
503532 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 )}) {
507536 return std::move (*repl);
508537 }
509538 return tokens;
@@ -1215,50 +1244,27 @@ static std::int64_t ExpressionValue(const TokenSequence &token,
12151244 return left;
12161245}
12171246
1218- bool Preprocessor::IsIfPredicateTrue (const TokenSequence &expr ,
1247+ bool Preprocessor::IsIfPredicateTrue (const TokenSequence &directive ,
12191248 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 ();
12481254 }
1249- if (expr3 .empty ()) {
1255+ if (replaced .empty ()) {
12501256 prescanner.Say (expr.GetProvenanceRange (), " empty expression" _err_en_US);
12511257 return false ;
12521258 }
12531259 std::size_t atToken{0 };
12541260 std::optional<Message> error;
1255- bool result{ExpressionValue (expr3 , 0 , &atToken, &error) != 0 };
1261+ bool result{ExpressionValue (replaced , 0 , &atToken, &error) != 0 };
12561262 if (error) {
12571263 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),
12621268 atToken == 0 ? " could not parse any expression" _err_en_US
12631269 : " excess characters after expression" _err_en_US);
12641270 }
0 commit comments