[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-openmp

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