[flang-commits] [flang] [flang] Further refinement of OpenMP !$ lines in -E mode (PR #138956)
via flang-commits
flang-commits at lists.llvm.org
Wed May 7 13:41:27 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-openmp
Author: Peter Klausler (klausler)
<details>
<summary>Changes</summary>
Address failing Fujitsu test suite cases that were broken by the patch to defer the handling of !$ lines in -fopenmp vs. normal compilation to actual compilation rather than processing them immediately in -E mode.
Tested on the samples in the bug report as well as all of the Fujitsu tests that I could find that use !$ lines.
Fixes https://github.com/llvm/llvm-project/issues/136845.
---
Patch is 20.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138956.diff
10 Files Affected:
- (modified) flang/include/flang/Parser/token-sequence.h (+1-1)
- (modified) flang/lib/Parser/parsing.cpp (+4-3)
- (modified) flang/lib/Parser/prescan.cpp (+95-98)
- (modified) flang/lib/Parser/prescan.h (+5)
- (modified) flang/lib/Parser/token-sequence.cpp (+4-2)
- (modified) flang/test/Parser/OpenMP/bug518.f (+2-2)
- (modified) flang/test/Parser/OpenMP/compiler-directive-continuation.f90 (+6-6)
- (modified) flang/test/Parser/OpenMP/sentinels.f (+2-2)
- (modified) flang/test/Parser/continuation-in-conditional-compilation.f (+4-3)
- (added) flang/test/Preprocessing/bug136845.F (+45)
``````````diff
diff --git a/flang/include/flang/Parser/token-sequence.h b/flang/include/flang/Parser/token-sequence.h
index 69291e69526e2..05aeacccde097 100644
--- a/flang/include/flang/Parser/token-sequence.h
+++ b/flang/include/flang/Parser/token-sequence.h
@@ -137,7 +137,7 @@ class TokenSequence {
TokenSequence &RemoveRedundantBlanks(std::size_t firstChar = 0);
TokenSequence &ClipComment(const Prescanner &, bool skipFirst = false);
const TokenSequence &CheckBadFortranCharacters(
- Messages &, const Prescanner &, bool allowAmpersand) const;
+ Messages &, const Prescanner &, bool preprocessingOnly) const;
bool BadlyNestedParentheses() const;
const TokenSequence &CheckBadParentheses(Messages &) const;
void Emit(CookedSource &) const;
diff --git a/flang/lib/Parser/parsing.cpp b/flang/lib/Parser/parsing.cpp
index 17f544194de02..93737d99567dd 100644
--- a/flang/lib/Parser/parsing.cpp
+++ b/flang/lib/Parser/parsing.cpp
@@ -230,10 +230,11 @@ void Parsing::EmitPreprocessedSource(
column = 7; // start of fixed form source field
++sourceLine;
inContinuation = true;
- } else if (!inDirective && ch != ' ' && (ch < '0' || ch > '9')) {
+ } else if (!inDirective && !ompConditionalLine && ch != ' ' &&
+ (ch < '0' || ch > '9')) {
// Put anything other than a label or directive into the
// Fortran fixed form source field (columns [7:72]).
- for (; column < 7; ++column) {
+ for (int toCol{ch == '&' ? 6 : 7}; column < toCol; ++column) {
out << ' ';
}
}
@@ -241,7 +242,7 @@ void Parsing::EmitPreprocessedSource(
if (ompConditionalLine) {
// Only digits can stay in the label field
if (!(ch >= '0' && ch <= '9')) {
- for (; column < 7; ++column) {
+ for (int toCol{ch == '&' ? 6 : 7}; column < toCol; ++column) {
out << ' ';
}
}
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index 46e04c15ade01..ee180d986e39d 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -150,10 +150,7 @@ void Prescanner::Statement() {
CHECK(*at_ == '!');
}
std::optional<int> condOffset;
- bool isOpenMPCondCompilation{
- directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0'};
- if (isOpenMPCondCompilation) {
- // OpenMP conditional compilation line.
+ if (InOpenMPConditionalLine()) {
condOffset = 2;
} else if (directiveSentinel_[0] == '@' && directiveSentinel_[1] == 'c' &&
directiveSentinel_[2] == 'u' && directiveSentinel_[3] == 'f' &&
@@ -167,19 +164,10 @@ void Prescanner::Statement() {
FortranInclude(at_ + *payload);
return;
}
- while (true) {
- if (auto n{IsSpace(at_)}) {
- at_ += n, ++column_;
- } else if (*at_ == '\t') {
- ++at_, ++column_;
- tabInCurrentLine_ = true;
- } else if (inFixedForm_ && column_ == 6 && !tabInCurrentLine_ &&
- *at_ == '0') {
- ++at_, ++column_;
- } else {
- break;
- }
+ if (inFixedForm_) {
+ LabelField(tokens);
}
+ SkipSpaces();
} else {
// Compiler directive. Emit normalized sentinel, squash following spaces.
// Conditional compilation lines (!$) take this path in -E mode too
@@ -190,35 +178,47 @@ void Prescanner::Statement() {
++sp, ++at_, ++column_) {
EmitChar(tokens, *sp);
}
- if (IsSpaceOrTab(at_)) {
- while (int n{IsSpaceOrTab(at_)}) {
- if (isOpenMPCondCompilation && inFixedForm_) {
+ if (inFixedForm_) {
+ while (column_ < 6) {
+ if (*at_ == '\t') {
+ tabInCurrentLine_ = true;
+ ++at_;
+ for (; column_ < 7; ++column_) {
+ EmitChar(tokens, ' ');
+ }
+ } else if (int spaceBytes{IsSpace(at_)}) {
EmitChar(tokens, ' ');
- }
- tabInCurrentLine_ |= *at_ == '\t';
- at_ += n, ++column_;
- if (inFixedForm_ && column_ > fixedFormColumnLimit_) {
+ at_ += spaceBytes;
+ ++column_;
+ } else {
+ if (InOpenMPConditionalLine() && column_ == 3 &&
+ IsDecimalDigit(*at_)) {
+ // subtle: !$ in -E mode can't be immediately followed by a digit
+ EmitChar(tokens, ' ');
+ }
break;
}
}
- if (isOpenMPCondCompilation && inFixedForm_ && column_ == 6) {
- if (*at_ == '0') {
- EmitChar(tokens, ' ');
- } else {
- tokens.CloseToken();
- EmitChar(tokens, '&');
- }
- ++at_, ++column_;
+ } else if (int spaceBytes{IsSpaceOrTab(at_)}) {
+ EmitChar(tokens, ' ');
+ at_ += spaceBytes, ++column_;
+ }
+ tokens.CloseToken();
+ SkipSpaces();
+ if (InOpenMPConditionalLine() && inFixedForm_ && !tabInCurrentLine_ &&
+ column_ == 6 && *at_ != '\n') {
+ // !$ 0 - turn '0' into a space
+ // !$ 1 - turn '1' into '&'
+ if (int n{IsSpace(at_)}; n || *at_ == '0') {
+ at_ += n ? n : 1;
} else {
- EmitChar(tokens, ' ');
+ ++at_;
+ EmitChar(tokens, '&');
+ tokens.CloseToken();
}
+ ++column_;
+ SkipSpaces();
}
- tokens.CloseToken();
- }
- if (*at_ == '!' || *at_ == '\n' ||
- (inFixedForm_ && column_ > fixedFormColumnLimit_ &&
- !tabInCurrentLine_)) {
- return; // Directive without payload
}
break;
}
@@ -323,8 +323,8 @@ void Prescanner::Statement() {
NormalizeCompilerDirectiveCommentMarker(*preprocessed);
preprocessed->ToLowerCase();
SourceFormChange(preprocessed->ToString());
- CheckAndEmitLine(preprocessed->ToLowerCase().ClipComment(
- *this, true /* skip first ! */),
+ CheckAndEmitLine(
+ preprocessed->ClipComment(*this, true /* skip first ! */),
newlineProvenance);
break;
case LineClassification::Kind::Source:
@@ -349,6 +349,24 @@ void Prescanner::Statement() {
while (CompilerDirectiveContinuation(tokens, line.sentinel)) {
newlineProvenance = GetCurrentProvenance();
}
+ if (preprocessingOnly_ && inFixedForm_ && InOpenMPConditionalLine() &&
+ nextLine_ < limit_) {
+ // In -E mode, when the line after !$ conditional compilation is a
+ // regular fixed form continuation line, append a '&' to the line.
+ const char *p{nextLine_};
+ int col{1};
+ while (int n{IsSpace(p)}) {
+ if (*p == '\t') {
+ break;
+ }
+ p += n;
+ ++col;
+ }
+ if (col == 6 && *p != '0' && *p != '\t' && *p != '\n') {
+ EmitChar(tokens, '&');
+ tokens.CloseToken();
+ }
+ }
tokens.ToLowerCase();
SourceFormChange(tokens.ToString());
} else { // Kind::Source
@@ -544,7 +562,8 @@ void Prescanner::SkipToEndOfLine() {
bool Prescanner::MustSkipToEndOfLine() const {
if (inFixedForm_ && column_ > fixedFormColumnLimit_ && !tabInCurrentLine_) {
return true; // skip over ignored columns in right margin (73:80)
- } else if (*at_ == '!' && !inCharLiteral_) {
+ } else if (*at_ == '!' && !inCharLiteral_ &&
+ (!inFixedForm_ || tabInCurrentLine_ || column_ != 6)) {
return !IsCompilerDirectiveSentinel(at_);
} else {
return false;
@@ -569,10 +588,11 @@ void Prescanner::NextChar() {
// directives, Fortran ! comments, stuff after the right margin in
// fixed form, and all forms of line continuation.
bool Prescanner::SkipToNextSignificantCharacter() {
- auto anyContinuationLine{false};
if (inPreprocessorDirective_) {
SkipCComments();
+ return false;
} else {
+ auto anyContinuationLine{false};
bool mightNeedSpace{false};
if (MustSkipToEndOfLine()) {
SkipToEndOfLine();
@@ -589,8 +609,8 @@ bool Prescanner::SkipToNextSignificantCharacter() {
if (*at_ == '\t') {
tabInCurrentLine_ = true;
}
+ return anyContinuationLine;
}
- return anyContinuationLine;
}
void Prescanner::SkipCComments() {
@@ -1119,12 +1139,10 @@ static bool IsAtProcess(const char *p) {
bool Prescanner::IsFixedFormCommentLine(const char *start) const {
const char *p{start};
-
// The @process directive must start in column 1.
if (*p == '@' && IsAtProcess(p)) {
return true;
}
-
if (IsFixedFormCommentChar(*p) || *p == '%' || // VAX %list, %eject, &c.
((*p == 'D' || *p == 'd') &&
!features_.IsEnabled(LanguageFeature::OldDebugLines))) {
@@ -1325,23 +1343,9 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
nextLine_[1] == ' ' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
nextLine_[4] == ' '};
if (InCompilerDirective()) {
- if (directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0') {
- if (IsFixedFormCommentChar(col1)) {
- if (nextLine_[1] == '$' &&
- (nextLine_[2] == '&' || IsSpaceOrTab(&nextLine_[2]))) {
- // Next line is also !$ conditional compilation, might be continuation
- if (preprocessingOnly_) {
- return nullptr;
- }
- } else {
- return nullptr; // comment, or distinct directive
- }
- } else if (!canBeNonDirectiveContinuation) {
- return nullptr;
- }
- } else if (!IsFixedFormCommentChar(col1)) {
- return nullptr; // in directive other than !$, but next line is not
- } else { // in directive other than !$, next line might be continuation
+ // !$ under -E is not continued, but deferred to later compilation
+ if (IsFixedFormCommentChar(col1) &&
+ !(InOpenMPConditionalLine() && preprocessingOnly_)) {
int j{1};
for (; j < 5; ++j) {
char ch{directiveSentinel_[j - 1]};
@@ -1356,31 +1360,27 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
return nullptr;
}
}
- }
- const char *col6{nextLine_ + 5};
- if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
- if (mightNeedSpace && !IsSpace(nextLine_ + 6)) {
- insertASpace_ = true;
+ const char *col6{nextLine_ + 5};
+ if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
+ if (mightNeedSpace && !IsSpace(nextLine_ + 6)) {
+ insertASpace_ = true;
+ }
+ return nextLine_ + 6;
}
- return nextLine_ + 6;
}
- } else {
- // Normal case: not in a compiler directive.
- if (IsFixedFormCommentChar(col1)) {
- if (nextLine_[1] == '$' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
- nextLine_[4] == ' ' &&
- IsCompilerDirectiveSentinel(&nextLine_[1], 1) &&
- !preprocessingOnly_) {
- // !$ conditional compilation line as a continuation
- const char *col6{nextLine_ + 5};
- if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
- if (mightNeedSpace && !IsSpace(nextLine_ + 6)) {
- insertASpace_ = true;
- }
- return nextLine_ + 6;
- }
+ } else { // Normal case: not in a compiler directive.
+ // !$ conditional compilation lines may be continuations when not
+ // just preprocessing.
+ if (!preprocessingOnly_ && IsFixedFormCommentChar(col1) &&
+ nextLine_[1] == '$' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
+ nextLine_[4] == ' ' && IsCompilerDirectiveSentinel(&nextLine_[1], 1)) {
+ if (const char *col6{nextLine_ + 5};
+ *col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
+ insertASpace_ |= mightNeedSpace && !IsSpace(nextLine_ + 6);
+ return nextLine_ + 6;
+ } else {
+ return nullptr;
}
- return nullptr;
}
if (col1 == '&' &&
features_.IsEnabled(
@@ -1422,13 +1422,13 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
}
p = SkipWhiteSpaceIncludingEmptyMacros(p);
if (InCompilerDirective()) {
- if (directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0') {
+ if (InOpenMPConditionalLine()) {
if (preprocessingOnly_) {
// in -E mode, don't treat !$ as a continuation
return nullptr;
} else if (p[0] == '!' && p[1] == '$') {
// accept but do not require a matching sentinel
- if (!(p[2] == '&' || IsSpaceOrTab(&p[2]))) {
+ if (p[2] != '&' && !IsSpaceOrTab(&p[2])) {
return nullptr; // not !$
}
p += 2;
@@ -1566,15 +1566,11 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
}
char sentinel[5], *sp{sentinel};
int column{2};
- for (; column < 6; ++column, ++p) {
- if (*p == '\n' || IsSpaceOrTab(p)) {
- break;
- }
- if (sp == sentinel + 1 && sentinel[0] == '$' && IsDecimalDigit(*p)) {
- // OpenMP conditional compilation line: leave the label alone
+ for (; column < 6; ++column) {
+ if (*p == '\n' || IsSpaceOrTab(p) || IsDecimalDigit(*p)) {
break;
}
- *sp++ = ToLowerCaseLetter(*p);
+ *sp++ = ToLowerCaseLetter(*p++);
}
if (sp == sentinel) {
return std::nullopt;
@@ -1600,7 +1596,8 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
++p;
} else if (int n{IsSpaceOrTab(p)}) {
p += n;
- } else if (isOpenMPConditional && preprocessingOnly_ && !hadDigit) {
+ } else if (isOpenMPConditional && preprocessingOnly_ && !hadDigit &&
+ *p != '\n') {
// In -E mode, "!$ &" is treated as a directive
} else {
// This is a Continuation line, not an initial directive line.
@@ -1671,14 +1668,14 @@ const char *Prescanner::IsCompilerDirectiveSentinel(CharBlock token) const {
std::optional<std::pair<const char *, const char *>>
Prescanner::IsCompilerDirectiveSentinel(const char *p) const {
char sentinel[8];
- for (std::size_t j{0}; j + 1 < sizeof sentinel && *p != '\n'; ++p, ++j) {
+ for (std::size_t j{0}; j + 1 < sizeof sentinel; ++p, ++j) {
if (int n{IsSpaceOrTab(p)};
n || !(IsLetter(*p) || *p == '$' || *p == '@')) {
if (j > 0) {
- if (j == 1 && sentinel[0] == '$' && n == 0 && *p != '&') {
- // OpenMP conditional compilation line sentinels have to
+ if (j == 1 && sentinel[0] == '$' && n == 0 && *p != '&' && *p != '\n') {
+ // Free form OpenMP conditional compilation line sentinels have to
// be immediately followed by a space or &, not a digit
- // or anything else.
+ // or anything else. A newline also works for an initial line.
break;
}
sentinel[j] = '\0';
diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h
index 53361ba14f378..ec4c53cf3e0f2 100644
--- a/flang/lib/Parser/prescan.h
+++ b/flang/lib/Parser/prescan.h
@@ -159,6 +159,11 @@ class Prescanner {
}
bool InCompilerDirective() const { return directiveSentinel_ != nullptr; }
+ bool InOpenMPConditionalLine() const {
+ return directiveSentinel_ && directiveSentinel_[0] == '$' &&
+ !directiveSentinel_[1];
+ ;
+ }
bool InFixedFormSource() const {
return inFixedForm_ && !inPreprocessorDirective_ && !InCompilerDirective();
}
diff --git a/flang/lib/Parser/token-sequence.cpp b/flang/lib/Parser/token-sequence.cpp
index aee76938550f5..40a074eaf0a47 100644
--- a/flang/lib/Parser/token-sequence.cpp
+++ b/flang/lib/Parser/token-sequence.cpp
@@ -357,7 +357,7 @@ ProvenanceRange TokenSequence::GetProvenanceRange() const {
const TokenSequence &TokenSequence::CheckBadFortranCharacters(
Messages &messages, const Prescanner &prescanner,
- bool allowAmpersand) const {
+ bool preprocessingOnly) const {
std::size_t tokens{SizeInTokens()};
for (std::size_t j{0}; j < tokens; ++j) {
CharBlock token{TokenAt(j)};
@@ -371,8 +371,10 @@ const TokenSequence &TokenSequence::CheckBadFortranCharacters(
TokenAt(j + 1))) { // !dir$, &c.
++j;
continue;
+ } else if (preprocessingOnly) {
+ continue;
}
- } else if (ch == '&' && allowAmpersand) {
+ } else if (ch == '&' && preprocessingOnly) {
continue;
}
if (ch < ' ' || ch >= '\x7f') {
diff --git a/flang/test/Parser/OpenMP/bug518.f b/flang/test/Parser/OpenMP/bug518.f
index 2dbacef59fa8a..2739de63f8b25 100644
--- a/flang/test/Parser/OpenMP/bug518.f
+++ b/flang/test/Parser/OpenMP/bug518.f
@@ -9,9 +9,9 @@
!$omp end parallel
end
-!CHECK-E:{{^}}!$ thread = OMP_GET_MAX_THREADS()
+!CHECK-E:{{^}}!$ thread = OMP_GET_MAX_THREADS()
!CHECK-E:{{^}}!$omp parallel private(ia)
-!CHECK-E:{{^}}!$ continue
+!CHECK-E:{{^}}!$ continue
!CHECK-E:{{^}}!$omp end parallel
!CHECK-OMP:thread=omp_get_max_threads()
diff --git a/flang/test/Parser/OpenMP/compiler-directive-continuation.f90 b/flang/test/Parser/OpenMP/compiler-directive-continuation.f90
index 169976d74c0bf..644ab3f723aba 100644
--- a/flang/test/Parser/OpenMP/compiler-directive-continuation.f90
+++ b/flang/test/Parser/OpenMP/compiler-directive-continuation.f90
@@ -7,10 +7,10 @@
! CHECK-LABEL: subroutine mixed_form1()
! CHECK-E:{{^}} i = 1 &
! CHECK-E:{{^}}!$ +100&
-! CHECK-E:{{^}}!$ &+ 1000&
-! CHECK-E:{{^}} &+ 10 + 1&
-! CHECK-E:{{^}}!$ & +100000&
-! CHECK-E:{{^}} &0000 + 1000000
+! CHECK-E:{{^}}!$ &+ 1000&
+! CHECK-E:{{^}} &+ 10 + 1&
+! CHECK-E:{{^}}!$ & +100000&
+! CHECK-E:{{^}} &0000 + 1000000
! CHECK-OMP: i=1001001112_4
! CHECK-NO-OMP: i=1010011_4
subroutine mixed_form1()
@@ -39,8 +39,8 @@ subroutine mixed_form2()
! CHECK-LABEL: subroutine mixed_form3()
! CHECK-E:{{^}}!$ i=0
! CHECK-E:{{^}}!$ i = 1 &
-! CHECK-E:{{^}}!$ & +10 &
-! CHECK-E:{{^}}!$ &+100&
+! CHECK-E:{{^}}!$ & +10 &
+! CHECK-E:{{^}}!$ &+100&
! CHECK-E:{{^}}!$ +1000
! CHECK-OMP: i=0_4
! CHECK-OMP: i=1111_4
diff --git a/flang/test/Parser/OpenMP/sentinels.f b/flang/test/Parser/OpenMP/sentinels.f
index 299b83e2abba8..f5a2fd4f7f931 100644
--- a/flang/test/Parser/OpenMP/sentinels.f
+++ b/flang/test/Parser/OpenMP/sentinels.f
@@ -61,12 +61,12 @@ subroutine sub(a, b)
! Test valid chars in initial and continuation lines.
! CHECK: !$ 20 PRINT *, "msg2"
-! CHECK: !$ & , "msg3"
+! CHECK: !$ &, "msg3"
c$ 20 PRINT *, "msg2"
c$ & , "msg3"
! CHECK: !$ PRINT *, "msg4",
-! CHECK: !$ & "msg5"
+! CHECK: !$ &"msg5"
c$ 0PRINT *, "msg4",
c$ + "msg5"
end
diff --git a/flang/test/Parser/continuation-in-conditional-compilation.f b/flang/test/Parser/continuation-in-conditional-compilation.f
index 57b69de657348..ebc6a3f875b9a 100644
--- a/flang/test/Parser/continuation-in-conditional-compilation.f
+++ b/flang/test/Parser/continuation-in-conditional-compilation.f
@@ -1,11 +1,12 @@
! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s
program main
! CHECK: k01=1+
-! CHECK: !$ & 1
+! CHECK: !$ &1
k01=1+
-!$ & 1
+!$ &1
-! CHECK: !$ k02=23
+! CHECK: !$ k02=2
+! CHECK: 3
! CHECK: !$ &4
!$ k02=2
+3
diff --git a/flang/test/Preprocessing/bug136845.F b/flang/test/Preprocessing/bug136845.F
new file mode 100644
index 0000000000000..ce52c2953bb57
--- /dev/null
+++ b/flang/test/Preprocessing/bug136845.F
@@ -0,0 +1,45 @@
+!RUN: %flang_fc1 -E %s | FileCheck --check-prefix=PREPRO %s
+!RUN: %flang_fc1 -fdebug-unparse %s | FileCheck --check-prefix=NORMAL %s
+!RUN: %flang_fc1 -fopenmp -fdebug-unparse %s | FileCheck --check-prefix=OMP %s
+
+c$ !
+
+C$
+ continue
+
+ k=0 w
+ k=0
+c$ 0 x
+c$ 1 y
+c$ 2 k= z
+c$ ! A
+c$ !1 B
+ print *,k
+*$1 continue
+ end
+
+!PREPRO:!$ &
+!PREPRO: continue
+!PREPRO: k=0
+!PREPRO: k=0
+!PREPRO:!$
+!PREPRO:!$ &
+!PREPRO:!$ &k=
+!PREPRO:!$ &
+!PREPRO:!$ &1
+!PREPRO: print *,k
+!PREPRO:!$ 1 continue
+!...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/138956
More information about the flang-commits
mailing list