@@ -749,35 +749,48 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
749749 }
750750 preventHollerith_ = false ;
751751 } 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(...) &(...)
754765 do {
755766 EmitChar (tokens, *at_);
756767 ++at_, ++column_;
757- afterLast = at_;
758- if (SkipToNextSignificantCharacter () && IsLegalIdentifierStart (*at_)) {
768+ hadContinuation = SkipToNextSignificantCharacter ();
769+ if (hadContinuation && IsLegalIdentifierStart (*at_)) {
770+ // Continued identifier
759771 tokens.CloseToken ();
760772 ++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+ }
761780 }
762781 } 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 ) {
781794 tokens.ReopenLastToken ();
782795 }
783796 }
0 commit comments