@@ -259,14 +259,15 @@ void Preprocessor::Define(std::string macro, std::string value) {
259
259
void Preprocessor::Undefine (std::string macro) { definitions_.erase (macro); }
260
260
261
261
std::optional<TokenSequence> Preprocessor::MacroReplacement (
262
- const TokenSequence &input, Prescanner &prescanner) {
262
+ const TokenSequence &input, Prescanner &prescanner,
263
+ std::optional<std::size_t > *partialFunctionLikeMacro) {
263
264
// Do quick scan for any use of a defined name.
264
265
if (definitions_.empty ()) {
265
266
return std::nullopt;
266
267
}
267
268
std::size_t tokens{input.SizeInTokens ()};
268
- std::size_t j;
269
- for (j = 0 ; j < tokens; ++j) {
269
+ std::size_t j{ 0 } ;
270
+ for (; j < tokens; ++j) {
270
271
CharBlock token{input.TokenAt (j)};
271
272
if (!token.empty () && IsLegalIdentifierStart (token[0 ]) &&
272
273
IsNameDefined (token)) {
@@ -277,6 +278,38 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
277
278
return std::nullopt; // input contains nothing that would be replaced
278
279
}
279
280
TokenSequence result{input, 0 , j};
281
+
282
+ // After rescanning after macro replacement has failed due to an unclosed
283
+ // function-like macro call (no left parenthesis yet, or no closing
284
+ // parenthesis), if tokens remain in the input, append them to the
285
+ // replacement text and attempt to proceed. Otherwise, return, so that
286
+ // the caller may try again with remaining tokens in its input.
287
+ auto CompleteFunctionLikeMacro{
288
+ [this , &input, &prescanner, &result, &partialFunctionLikeMacro](
289
+ std::size_t after, const TokenSequence &replacement,
290
+ std::size_t pFLMOffset) {
291
+ if (after < input.SizeInTokens ()) {
292
+ result.Put (replacement, 0 , pFLMOffset);
293
+ TokenSequence suffix;
294
+ suffix.Put (
295
+ replacement, pFLMOffset, replacement.SizeInTokens () - pFLMOffset);
296
+ suffix.Put (input, after, input.SizeInTokens () - after);
297
+ auto further{
298
+ ReplaceMacros (suffix, prescanner, partialFunctionLikeMacro)};
299
+ if (partialFunctionLikeMacro && *partialFunctionLikeMacro) {
300
+ // still not closed
301
+ **partialFunctionLikeMacro += result.SizeInTokens ();
302
+ }
303
+ result.Put (further);
304
+ return true ;
305
+ } else {
306
+ if (partialFunctionLikeMacro) {
307
+ *partialFunctionLikeMacro = pFLMOffset + result.SizeInTokens ();
308
+ }
309
+ return false ;
310
+ }
311
+ }};
312
+
280
313
for (; j < tokens; ++j) {
281
314
CharBlock token{input.TokenAt (j)};
282
315
if (token.IsBlank () || !IsLegalIdentifierStart (token[0 ])) {
@@ -294,20 +327,17 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
294
327
continue ;
295
328
}
296
329
if (!def->isFunctionLike ()) {
297
- bool isRenaming{false };
298
- if (def->isPredefined ()) {
330
+ if (def->isPredefined () && !def->replacement ().empty ()) {
299
331
std::string repl;
300
- if (!def->replacement ().empty ()) {
301
- std::string name{def->replacement ().TokenAt (0 ).ToString ()};
302
- if (name == " __FILE__" ) {
303
- repl = " \" " s +
304
- allSources_.GetPath (prescanner.GetCurrentProvenance ()) + ' "' ;
305
- } else if (name == " __LINE__" ) {
306
- std::string buf;
307
- llvm::raw_string_ostream ss{buf};
308
- ss << allSources_.GetLineNumber (prescanner.GetCurrentProvenance ());
309
- repl = ss.str ();
310
- }
332
+ std::string name{def->replacement ().TokenAt (0 ).ToString ()};
333
+ if (name == " __FILE__" ) {
334
+ repl = " \" " s +
335
+ allSources_.GetPath (prescanner.GetCurrentProvenance ()) + ' "' ;
336
+ } else if (name == " __LINE__" ) {
337
+ std::string buf;
338
+ llvm::raw_string_ostream ss{buf};
339
+ ss << allSources_.GetLineNumber (prescanner.GetCurrentProvenance ());
340
+ repl = ss.str ();
311
341
}
312
342
if (!repl.empty ()) {
313
343
ProvenanceRange insert{allSources_.AddCompilerInsertion (repl)};
@@ -317,105 +347,109 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
317
347
continue ;
318
348
}
319
349
}
350
+ std::optional<std::size_t > partialFLM;
320
351
def->set_isDisabled (true );
321
- TokenSequence replaced{
322
- TokenPasting ( ReplaceMacros (def->replacement (), prescanner))};
352
+ TokenSequence replaced{TokenPasting (
353
+ ReplaceMacros (def->replacement (), prescanner, &partialFLM ))};
323
354
def->set_isDisabled (false );
324
- // Allow a keyword-like macro replacement to be the name of
325
- // a function-like macro, possibly surrounded by blanks.
326
- std::size_t k{0 }, repTokens{replaced.SizeInTokens ()};
327
- for (; k < repTokens && replaced.TokenAt (k).IsBlank (); ++k) {
355
+ if (partialFLM &&
356
+ CompleteFunctionLikeMacro (j + 1 , replaced, *partialFLM)) {
357
+ return result;
358
+ }
359
+ if (!replaced.empty ()) {
360
+ ProvenanceRange from{def->replacement ().GetProvenanceRange ()};
361
+ ProvenanceRange use{input.GetTokenProvenanceRange (j)};
362
+ ProvenanceRange newRange{
363
+ allSources_.AddMacroCall (from, use, replaced.ToString ())};
364
+ result.Put (replaced, newRange);
365
+ }
366
+ } else {
367
+ // Possible function-like macro call. Skip spaces and newlines to see
368
+ // whether '(' is next.
369
+ std::size_t k{j};
370
+ bool leftParen{false };
371
+ while (++k < tokens) {
372
+ const CharBlock &lookAhead{input.TokenAt (k)};
373
+ if (!lookAhead.IsBlank () && lookAhead[0 ] != ' \n ' ) {
374
+ leftParen = lookAhead[0 ] == ' (' && lookAhead.size () == 1 ;
375
+ break ;
376
+ }
328
377
}
329
- if (k < repTokens) {
330
- token = replaced.TokenAt (k);
331
- for (++k; k < repTokens && replaced.TokenAt (k).IsBlank (); ++k) {
378
+ if (!leftParen) {
379
+ if (partialFunctionLikeMacro) {
380
+ *partialFunctionLikeMacro = result.SizeInTokens ();
381
+ result.Put (input, j, tokens - j);
382
+ return result;
383
+ } else {
384
+ result.Put (input, j);
385
+ continue ;
332
386
}
333
- if (k == repTokens && IsLegalIdentifierStart (token[0 ])) {
334
- auto it{definitions_.find (token)};
335
- if (it != definitions_.end () && !it->second .isDisabled () &&
336
- it->second .isFunctionLike ()) {
337
- def = &it->second ;
338
- isRenaming = true ;
387
+ }
388
+ std::vector<std::size_t > argStart{++k};
389
+ for (int nesting{0 }; k < tokens; ++k) {
390
+ CharBlock token{input.TokenAt (k)};
391
+ char ch{token.OnlyNonBlank ()};
392
+ if (ch == ' (' ) {
393
+ ++nesting;
394
+ } else if (ch == ' )' ) {
395
+ if (nesting == 0 ) {
396
+ break ;
339
397
}
398
+ --nesting;
399
+ } else if (ch == ' ,' && nesting == 0 ) {
400
+ argStart.push_back (k + 1 );
340
401
}
341
402
}
342
- if (!isRenaming) {
343
- if (!replaced.empty ()) {
344
- ProvenanceRange from{def->replacement ().GetProvenanceRange ()};
345
- ProvenanceRange use{input.GetTokenProvenanceRange (j)};
346
- ProvenanceRange newRange{
347
- allSources_.AddMacroCall (from, use, replaced.ToString ())};
348
- result.Put (replaced, newRange);
349
- }
403
+ if (argStart.size () == 1 && k == argStart[0 ] &&
404
+ def->argumentCount () == 0 ) {
405
+ // Subtle: () is zero arguments, not one empty argument,
406
+ // unless one argument was expected.
407
+ argStart.clear ();
408
+ }
409
+ if (k >= tokens && partialFunctionLikeMacro) {
410
+ *partialFunctionLikeMacro = result.SizeInTokens ();
411
+ result.Put (input, j, tokens - j);
412
+ return result;
413
+ } else if (k >= tokens || argStart.size () < def->argumentCount () ||
414
+ (argStart.size () > def->argumentCount () && !def->isVariadic ())) {
415
+ result.Put (input, j);
350
416
continue ;
351
417
}
352
- }
353
- // Possible function-like macro call. Skip spaces and newlines to see
354
- // whether '(' is next.
355
- std::size_t k{j};
356
- bool leftParen{false };
357
- while (++k < tokens) {
358
- const CharBlock &lookAhead{input.TokenAt (k)};
359
- if (!lookAhead.IsBlank () && lookAhead[0 ] != ' \n ' ) {
360
- leftParen = lookAhead[0 ] == ' (' && lookAhead.size () == 1 ;
361
- break ;
418
+ std::vector<TokenSequence> args;
419
+ for (std::size_t n{0 }; n < argStart.size (); ++n) {
420
+ std::size_t at{argStart[n]};
421
+ std::size_t count{
422
+ (n + 1 == argStart.size () ? k : argStart[n + 1 ] - 1 ) - at};
423
+ args.emplace_back (TokenSequence (input, at, count));
362
424
}
363
- }
364
- if (!leftParen) {
365
- result.Put (input, j);
366
- continue ;
367
- }
368
- std::vector<std::size_t > argStart{++k};
369
- for (int nesting{0 }; k < tokens; ++k) {
370
- CharBlock token{input.TokenAt (k)};
371
- char ch{token.OnlyNonBlank ()};
372
- if (ch == ' (' ) {
373
- ++nesting;
374
- } else if (ch == ' )' ) {
375
- if (nesting == 0 ) {
376
- break ;
377
- }
378
- --nesting;
379
- } else if (ch == ' ,' && nesting == 0 ) {
380
- argStart.push_back (k + 1 );
425
+ TokenSequence applied{def->Apply (args, prescanner)};
426
+ std::optional<std::size_t > partialFLM;
427
+ def->set_isDisabled (true );
428
+ TokenSequence replaced{
429
+ ReplaceMacros (std::move (applied), prescanner, &partialFLM)};
430
+ def->set_isDisabled (false );
431
+ if (partialFLM &&
432
+ CompleteFunctionLikeMacro (k + 1 , replaced, *partialFLM)) {
433
+ return result;
381
434
}
435
+ if (!replaced.empty ()) {
436
+ ProvenanceRange from{def->replacement ().GetProvenanceRange ()};
437
+ ProvenanceRange use{input.GetIntervalProvenanceRange (j, k - j)};
438
+ ProvenanceRange newRange{
439
+ allSources_.AddMacroCall (from, use, replaced.ToString ())};
440
+ result.Put (replaced, newRange);
441
+ }
442
+ j = k; // advance to the terminal ')'
382
443
}
383
- if (argStart.size () == 1 && k == argStart[0 ] && def->argumentCount () == 0 ) {
384
- // Subtle: () is zero arguments, not one empty argument,
385
- // unless one argument was expected.
386
- argStart.clear ();
387
- }
388
- if (k >= tokens || argStart.size () < def->argumentCount () ||
389
- (argStart.size () > def->argumentCount () && !def->isVariadic ())) {
390
- result.Put (input, j);
391
- continue ;
392
- }
393
- std::vector<TokenSequence> args;
394
- for (std::size_t n{0 }; n < argStart.size (); ++n) {
395
- std::size_t at{argStart[n]};
396
- std::size_t count{
397
- (n + 1 == argStart.size () ? k : argStart[n + 1 ] - 1 ) - at};
398
- args.emplace_back (TokenSequence (input, at, count));
399
- }
400
- TokenSequence applied{def->Apply (args, prescanner)};
401
- def->set_isDisabled (true );
402
- TokenSequence replaced{ReplaceMacros (std::move (applied), prescanner)};
403
- def->set_isDisabled (false );
404
- if (!replaced.empty ()) {
405
- ProvenanceRange from{def->replacement ().GetProvenanceRange ()};
406
- ProvenanceRange use{input.GetIntervalProvenanceRange (j, k - j)};
407
- ProvenanceRange newRange{
408
- allSources_.AddMacroCall (from, use, replaced.ToString ())};
409
- result.Put (replaced, newRange);
410
- }
411
- j = k; // advance to the terminal ')'
412
444
}
413
445
return result;
414
446
}
415
447
416
- TokenSequence Preprocessor::ReplaceMacros (
417
- const TokenSequence &tokens, Prescanner &prescanner) {
418
- if (std::optional<TokenSequence> repl{MacroReplacement (tokens, prescanner)}) {
448
+ TokenSequence Preprocessor::ReplaceMacros (const TokenSequence &tokens,
449
+ Prescanner &prescanner,
450
+ std::optional<std::size_t > *partialFunctionLikeMacro) {
451
+ if (std::optional<TokenSequence> repl{
452
+ MacroReplacement (tokens, prescanner, partialFunctionLikeMacro)}) {
419
453
return std::move (*repl);
420
454
}
421
455
return tokens;
0 commit comments