Skip to content

Commit acc910c

Browse files
committed
[flang][preprocessor] Further macro replacement of continued identifiers
The preprocessor can perform macro replacement within identifiers when they are split up with Fortran line continuation, but is failing to do macro replacement on a continued identifier when none of its parts are replaced.
1 parent 1407f5b commit acc910c

File tree

3 files changed

+85
-22
lines changed

3 files changed

+85
-22
lines changed

flang/lib/Parser/prescan.cpp

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

flang/test/Preprocessing/pp047.F

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
! RUN: %flang -E %s 2>&1 | FileCheck %s
2+
#define FOO BAR
3+
#define FO BA
4+
#define OO AR
5+
! CHECK: print *,BAR, 1
6+
print *,
7+
+FOO
8+
+, 1
9+
print *,
10+
! CHECK: print *,FAR, 2
11+
+F
12+
+OO
13+
+, 2
14+
! CHECK: print *,BAO, 3
15+
print *,
16+
+FO
17+
+O
18+
+, 3
19+
! CHECK: print *,BAR, 4
20+
print *,
21+
+F
22+
+O
23+
+O
24+
+, 4
25+
end

flang/test/Preprocessing/pp135.F90

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
! RUN: %flang -E %s 2>&1 | FileCheck %s
2+
#define FOO BAR
3+
#define FO BA
4+
#define OO AR
5+
! CHECK: print *, BAR, 1
6+
print *, &
7+
&FOO&
8+
&, 1
9+
! CHECK: print *, FAR, 2
10+
print *, &
11+
&F&
12+
&OO&
13+
&, 2
14+
! CHECK: print *, BAO, 3
15+
print *, &
16+
&FO&
17+
&O&
18+
&, 3
19+
! CHECK: print *, BAR, 4
20+
print *, &
21+
&F&
22+
&O&
23+
&O&
24+
&, 4
25+
end

0 commit comments

Comments
 (0)