@@ -749,35 +749,48 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
749
749
}
750
750
preventHollerith_ = false ;
751
751
} else if (IsLegalInIdentifier (*at_)) {
752
- int parts{1 };
753
- const char *afterLast{nullptr };
752
+ std::size_t parts{1 };
753
+ bool anyDefined{false };
754
+ bool hadContinuation{false };
755
+ // Subtlety: When an identifier is split across continuation lines,
756
+ // its parts are kept as distinct pp-tokens if that macro replacement
757
+ // should operate on them independently. This trick accommodates the
758
+ // historic practice of using line continuation for token pasting after
759
+ // replacement.
760
+ // In free form, the macro to be replaced must have been preceded
761
+ // by '&' and followed by either '&' or, if last, the end of a line.
762
+ // call & call foo& call foo&
763
+ // &MACRO& OR &MACRO& OR &MACRO
764
+ // &foo(...) &(...)
754
765
do {
755
766
EmitChar (tokens, *at_);
756
767
++at_, ++column_;
757
- afterLast = at_;
758
- if (SkipToNextSignificantCharacter () && IsLegalIdentifierStart (*at_)) {
768
+ hadContinuation = SkipToNextSignificantCharacter ();
769
+ if (hadContinuation && IsLegalIdentifierStart (*at_)) {
770
+ // Continued identifier
759
771
tokens.CloseToken ();
760
772
++parts;
773
+ if (!anyDefined &&
774
+ (parts > 2 || inFixedForm_ ||
775
+ (start > start_ && start[-1 ] == ' &' )) &&
776
+ preprocessor_.IsNameDefined (
777
+ tokens.TokenAt (tokens.SizeInTokens () - 1 ))) {
778
+ anyDefined = true ;
779
+ }
761
780
}
762
781
} while (IsLegalInIdentifier (*at_));
763
- if (parts >= 3 ) {
764
- // Subtlety: When an identifier is split across three or more continuation
765
- // lines (or two continuation lines, immediately preceded or followed
766
- // by '&' free form continuation line markers, its parts are kept as
767
- // distinct pp-tokens so that macro replacement operates on them
768
- // independently. This trick accommodates the historic practice of
769
- // using line continuation for token pasting after replacement.
770
- } else if (parts == 2 ) {
771
- if (afterLast && afterLast < limit_) {
772
- afterLast = SkipWhiteSpace (afterLast);
773
- }
774
- if ((start > start_ && start[-1 ] == ' &' ) ||
775
- (afterLast && afterLast < limit_ &&
776
- (*afterLast == ' &' || *afterLast == ' \n ' ))) {
777
- // call & call foo& call foo&
778
- // &MACRO& OR &MACRO& OR &MACRO
779
- // &foo(...) &(...)
780
- } else {
782
+ if (!anyDefined && parts > 1 ) {
783
+ tokens.CloseToken ();
784
+ char after{*SkipWhiteSpace (at_)};
785
+ anyDefined = (hadContinuation || after == ' \n ' || after == ' &' ) &&
786
+ preprocessor_.IsNameDefined (
787
+ tokens.TokenAt (tokens.SizeInTokens () - 1 ));
788
+ tokens.ReopenLastToken ();
789
+ }
790
+ if (!anyDefined) {
791
+ // If no part was a defined macro, combine the parts into one so that
792
+ // the combination itself can be subject to macro replacement.
793
+ while (parts-- > 1 ) {
781
794
tokens.ReopenLastToken ();
782
795
}
783
796
}
0 commit comments