[flang-commits] [flang] y (PR #232040)
via flang-commits
flang-commits at lists.llvm.org
Wed Oct 14 11:55:10 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-parser
Author: Leandro Lupori (luporl)
<details>
<summary>Changes</summary>
In OpenMP conditional compilation sentinels, it is not mandatory to
have a space or ampersand following the sentinel in free form
continuation lines (OMP 6.0 - 5.3.1).
To avoid conflicts, all other possible sentinels are examined before
considering it to be an OpenMP conditional compilation sentinel.
Fixes #<!-- -->198771
---
Full diff: https://github.com/llvm/llvm-project/pull/232040.diff
3 Files Affected:
- (modified) flang/lib/Parser/prescan.cpp (+39-19)
- (modified) flang/lib/Parser/prescan.h (+5-2)
- (modified) flang/test/Parser/OpenMP/compiler-directive-continuation.f90 (+47)
``````````diff
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index e481661f8af8ba..95fdba3450eb98 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -1620,7 +1620,8 @@ const char *Prescanner::GetFreeFormContinuationLine(
// in -E mode, don't treat !$/!@acc/!@cuf as a continuation
return nullptr;
} else if (*p == '!') {
- if (auto lClass{IsCompilerDirectiveSentinelAfterKeywordMacro(p + 1)}) {
+ if (auto lClass{IsCompilerDirectiveSentinelAfterKeywordMacro(
+ p + 1, LineKind::Continuation)}) {
if (lClass->sentinel &&
((IsOpenMPConditionalLine(lClass->sentinel) &&
InOpenMPConditionalLine()) ||
@@ -1631,12 +1632,16 @@ const char *Prescanner::GetFreeFormContinuationLine(
p += 1 + lClass->payloadOffset;
}
}
- if (*p != '&' && !IsSpaceOrTab(p)) {
+ // In OpenMP conditional continuation lines, space or ampersand are
+ // optional.
+ if (*p == '!' ||
+ (*p != '&' && !IsSpaceOrTab(p) && !InOpenMPConditionalLine())) {
return nullptr;
}
}
} else if (*p == '!') {
- if (auto lClass{IsCompilerDirectiveSentinelAfterKeywordMacro(p + 1)}) {
+ if (auto lClass{IsCompilerDirectiveSentinelAfterKeywordMacro(
+ p + 1, LineKind::Continuation)}) {
if (lClass->sentinel &&
std::strcmp(directiveSentinel_, lClass->sentinel) == 0) {
p += 1 + lClass->payloadOffset;
@@ -1663,7 +1668,8 @@ const char *Prescanner::GetFreeFormContinuationLine(
}
if (p[0] == '!' && !preprocessingOnly_) {
// Conditional lines can be continuations
- if (auto lClass{IsCompilerDirectiveSentinelAfterKeywordMacro(p + 1)}) {
+ if (auto lClass{IsCompilerDirectiveSentinelAfterKeywordMacro(
+ p + 1, LineKind::Continuation)}) {
if (lClass->sentinel &&
((IsOpenMPConditionalLine(lClass->sentinel) &&
features_.IsEnabled(LanguageFeature::OpenMP)) ||
@@ -1977,44 +1983,58 @@ const char *Prescanner::IsCompilerDirectiveSentinel(CharBlock token) const {
}
std::optional<std::pair<const char *, const char *>>
-Prescanner::IsCompilerDirectiveSentinel(const char *p) const {
+Prescanner::IsCompilerDirectiveSentinel(
+ const char *p, LineKind lineKind) const {
char sentinel[8];
- for (std::size_t j{0}; j + 1 < sizeof sentinel; ++p, ++j) {
+ const char *originalP{p};
+ std::size_t j{0};
+ for (; j + 1 < sizeof sentinel; ++p, ++j) {
if (int n{IsSpaceOrTab(p)};
n || !(IsLetter(*p) || *p == '$' || *p == '@')) {
- 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. A newline also works for an initial line.
+ if (lineKind != LineKind::Continuation && j == 1 && sentinel[0] == '$' &&
+ n == 0 && *p != '\n' && *p != '&') {
+ // OpenMP conditional compilation line sentinels have to be
+ // immediately followed by a space or new line on initial lines.
+ // In free form continuation lines, the space is optional, and the
+ // sentinel may or may not be followed by &.
break;
}
- if (*p != '!') {
- sentinel[j] = '\0';
- if (const char *sp{IsCompilerDirectiveSentinel(sentinel, j)}) {
- return std::make_pair(sp, p);
- }
+ if (*p == '!') {
+ return std::nullopt;
+ }
+ sentinel[j] = '\0';
+ if (const char *sp{IsCompilerDirectiveSentinel(sentinel, j)}) {
+ return std::make_pair(sp, p);
}
break;
} else {
sentinel[j] = ToLowerCaseLetter(*p);
}
}
+ if (!inFixedForm_ && lineKind == LineKind::Continuation && j >= 1 &&
+ sentinel[0] == '$') {
+ if (const char *sp{IsCompilerDirectiveSentinel("$", 1)}) {
+ // This is a free form OpenMP conditional compilation sentinel with the
+ // space omitted.
+ return std::make_pair(sp, originalP + 1);
+ }
+ }
return std::nullopt;
}
-auto Prescanner::IsCompilerDirectiveSentinelAfterKeywordMacro(
- const char *p) const -> std::optional<LineClassification> {
+auto Prescanner::IsCompilerDirectiveSentinelAfterKeywordMacro(const char *p,
+ LineKind lineKind) const -> std::optional<LineClassification> {
if (auto name{GetKeywordMacroName(p)}) {
Provenance provenance{GetProvenance(p)};
TokenSequence expansion{ExpandKeywordMacro(*name, provenance)};
expansion.Put("\n", 1, provenance); // termination
CharBlock block{expansion.ToLowerCase().ToCharBlock()};
- if (auto maybePair{IsCompilerDirectiveSentinel(block.begin())}) {
+ if (auto maybePair{IsCompilerDirectiveSentinel(block.begin(), lineKind)}) {
return LineClassification{
LineClassification::Kind::CompilerDirectiveAfterMacroExpansion,
name->size(), maybePair->first};
}
- } else if (auto maybePair{IsCompilerDirectiveSentinel(p)}) {
+ } else if (auto maybePair{IsCompilerDirectiveSentinel(p, lineKind)}) {
return LineClassification{LineClassification::Kind::CompilerDirective,
static_cast<std::size_t>(maybePair->second - p), maybePair->first};
}
diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h
index 900d8b6cb52ad4..c4bec27a51beea 100644
--- a/flang/lib/Parser/prescan.h
+++ b/flang/lib/Parser/prescan.h
@@ -88,11 +88,13 @@ class Prescanner {
std::optional<CharBlock> GetKeywordMacroName(const char *) const;
TokenSequence ExpandKeywordMacro(CharBlock, Provenance) const;
+ enum class LineKind { Unknown, Initial, Continuation };
const char *IsCompilerDirectiveSentinel(const char *, std::size_t) const;
const char *IsCompilerDirectiveSentinel(CharBlock) const;
// 'first' is the sentinel, 'second' is beginning of payload
std::optional<std::pair<const char *, const char *>>
- IsCompilerDirectiveSentinel(const char *p) const;
+ IsCompilerDirectiveSentinel(
+ const char *p, LineKind lineKind = LineKind::Unknown) const;
template <typename... A> Message &Say(A &&...a) {
return messages_.Say(std::forward<A>(a)...);
@@ -276,7 +278,8 @@ class Prescanner {
bool CompilerDirectiveContinuation(TokenSequence &, const char *sentinel);
bool SourceLineContinuation(TokenSequence &);
std::optional<LineClassification>
- IsCompilerDirectiveSentinelAfterKeywordMacro(const char *p) const;
+ IsCompilerDirectiveSentinelAfterKeywordMacro(
+ const char *p, LineKind lineKind = LineKind::Unknown) const;
Messages &messages_;
CookedSource &cooked_;
diff --git a/flang/test/Parser/OpenMP/compiler-directive-continuation.f90 b/flang/test/Parser/OpenMP/compiler-directive-continuation.f90
index 644ab3f723aba0..9cf77ca76d3786 100644
--- a/flang/test/Parser/OpenMP/compiler-directive-continuation.f90
+++ b/flang/test/Parser/OpenMP/compiler-directive-continuation.f90
@@ -62,3 +62,50 @@ subroutine regression
!$ real x, &
stop
end
+
+! Free source form conditional compilation sentinel on a continuation line
+! that is immediately followed by the continued text, with no white space or
+! ampersand in between (https://github.com/llvm/llvm-project/issues/198771).
+! CHECK-LABEL: subroutine mixed_form4()
+! CHECK-OMP: i=1111111_4
+! CHECK-NO-OMP: i=1010001_4
+subroutine mixed_form4()
+!$ i = 0
+ i = 1&
+ !$ +10 &
+!$+100&
+!$&+ 1000&
+ &+ 10000&
+!$& +100000&
+ & +1000000
+end subroutine
+
+! Same, but continuing a conditional compilation line.
+! CHECK-LABEL: subroutine mixed_form5()
+! CHECK-OMP: i=21_4
+! CHECK-NO-OMP-NOT: i=21_4
+subroutine mixed_form5()
+!$ i = 1&
+!$+10&
+!$*2
+end subroutine
+
+! An initial line still needs white space after the sentinel, so these
+! are comments.
+! CHECK-LABEL: subroutine initial_line()
+! CHECK-OMP-NOT: i=5_4
+! CHECK-OMP-NOT: j=6_4
+subroutine initial_line()
+!$i = 5
+!$+j = 6
+end subroutine
+
+! Comment lines between continued conditional compilation lines.
+! CHECK-LABEL: subroutine cond_comment()
+! CHECK-OMP: i=5_4
+subroutine cond_comment()
+!$ i = 1 &
+! comment
+!$!comment
+!$ + 4
+end subroutine
``````````
</details>
https://github.com/llvm/llvm-project/pull/232040
More information about the flang-commits
mailing list