Skip to content

Commit 1bef59c

Browse files
authored
[flang][preprocessor] Further macro replacement of continued identifiers (#134302)
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 507ce46 commit 1bef59c

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)