[flang-commits] [flang] [flang][preprocessor] Further macro replacement of continued identifiers (PR #134302)
via flang-commits
flang-commits at lists.llvm.org
Thu Apr 3 13:17:55 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-parser
Author: Peter Klausler (klausler)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/134302.diff
3 Files Affected:
- (modified) flang/lib/Parser/prescan.cpp (+35-22)
- (added) flang/test/Preprocessing/pp047.F (+25)
- (added) flang/test/Preprocessing/pp135.F90 (+25)
``````````diff
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index 0df1e3e291923..5df82e21a45b8 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -749,35 +749,48 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
}
preventHollerith_ = false;
} else if (IsLegalInIdentifier(*at_)) {
- int parts{1};
- const char *afterLast{nullptr};
+ std::size_t parts{1};
+ bool anyDefined{false};
+ bool hadContinuation{false};
+ // Subtlety: When an identifier is split across continuation lines,
+ // its parts are kept as distinct pp-tokens if that macro replacement
+ // should operate on them independently. This trick accommodates the
+ // historic practice of using line continuation for token pasting after
+ // replacement.
+ // In free form, the macro to be replaced must have been preceded
+ // by '&' and followed by either '&' or, if last, the end of a line.
+ // call & call foo& call foo&
+ // &MACRO& OR &MACRO& OR &MACRO
+ // &foo(...) &(...)
do {
EmitChar(tokens, *at_);
++at_, ++column_;
- afterLast = at_;
- if (SkipToNextSignificantCharacter() && IsLegalIdentifierStart(*at_)) {
+ hadContinuation = SkipToNextSignificantCharacter();
+ if (hadContinuation && IsLegalIdentifierStart(*at_)) {
+ // Continued identifier
tokens.CloseToken();
++parts;
+ if (!anyDefined &&
+ (parts > 2 || inFixedForm_ ||
+ (start > start_ && start[-1] == '&')) &&
+ preprocessor_.IsNameDefined(
+ tokens.TokenAt(tokens.SizeInTokens() - 1))) {
+ anyDefined = true;
+ }
}
} while (IsLegalInIdentifier(*at_));
- if (parts >= 3) {
- // Subtlety: When an identifier is split across three or more continuation
- // lines (or two continuation lines, immediately preceded or followed
- // by '&' free form continuation line markers, its parts are kept as
- // distinct pp-tokens so that macro replacement operates on them
- // independently. This trick accommodates the historic practice of
- // using line continuation for token pasting after replacement.
- } else if (parts == 2) {
- if (afterLast && afterLast < limit_) {
- afterLast = SkipWhiteSpace(afterLast);
- }
- if ((start > start_ && start[-1] == '&') ||
- (afterLast && afterLast < limit_ &&
- (*afterLast == '&' || *afterLast == '\n'))) {
- // call & call foo& call foo&
- // &MACRO& OR &MACRO& OR &MACRO
- // &foo(...) &(...)
- } else {
+ if (!anyDefined && parts > 1) {
+ tokens.CloseToken();
+ char after{*SkipWhiteSpace(at_)};
+ anyDefined = (hadContinuation || after == '\n' || after == '&') &&
+ preprocessor_.IsNameDefined(
+ tokens.TokenAt(tokens.SizeInTokens() - 1));
+ tokens.ReopenLastToken();
+ }
+ if (!anyDefined) {
+ // If no part was a defined macro, combine the parts into one so that
+ // the combination itself can be subject to macro replacement.
+ while (parts-- > 1) {
tokens.ReopenLastToken();
}
}
diff --git a/flang/test/Preprocessing/pp047.F b/flang/test/Preprocessing/pp047.F
new file mode 100644
index 0000000000000..1d4f9f848e58a
--- /dev/null
+++ b/flang/test/Preprocessing/pp047.F
@@ -0,0 +1,25 @@
+! RUN: %flang -E %s 2>&1 | FileCheck %s
+#define FOO BAR
+#define FO BA
+#define OO AR
+! CHECK: print *,BAR, 1
+ print *,
+ +FOO
+ +, 1
+ print *,
+! CHECK: print *,FAR, 2
+ +F
+ +OO
+ +, 2
+! CHECK: print *,BAO, 3
+ print *,
+ +FO
+ +O
+ +, 3
+! CHECK: print *,BAR, 4
+ print *,
+ +F
+ +O
+ +O
+ +, 4
+ end
diff --git a/flang/test/Preprocessing/pp135.F90 b/flang/test/Preprocessing/pp135.F90
new file mode 100644
index 0000000000000..2905a8cec5d93
--- /dev/null
+++ b/flang/test/Preprocessing/pp135.F90
@@ -0,0 +1,25 @@
+! RUN: %flang -E %s 2>&1 | FileCheck %s
+#define FOO BAR
+#define FO BA
+#define OO AR
+! CHECK: print *, BAR, 1
+print *, &
+ &FOO&
+ &, 1
+! CHECK: print *, FAR, 2
+print *, &
+ &F&
+ &OO&
+ &, 2
+! CHECK: print *, BAO, 3
+print *, &
+ &FO&
+ &O&
+ &, 3
+! CHECK: print *, BAR, 4
+print *, &
+ &F&
+ &O&
+ &O&
+ &, 4
+end
``````````
</details>
https://github.com/llvm/llvm-project/pull/134302
More information about the flang-commits
mailing list