[flang-commits] [flang] [flang] Fix fixed-form continuations of !$ OpenMP conditional lines (PR #135852)

via flang-commits flang-commits at lists.llvm.org
Tue Apr 15 13:48:22 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-parser

Author: Peter Klausler (klausler)

<details>
<summary>Changes</summary>

I broke fixed-form line continuation (without !$) for OpenMP !$ conditional compilation lines.  Fix it.

---
Full diff: https://github.com/llvm/llvm-project/pull/135852.diff


4 Files Affected:

- (modified) flang/lib/Parser/prescan.cpp (+50-26) 
- (modified) flang/test/Parser/continuation-in-conditional-compilation.f (+6) 
- (modified) flang/test/Parser/unmatched-parens.f90 (+1-1) 
- (modified) flang/test/Preprocessing/implicit-contin3.F90 (+1-1) 


``````````diff
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index b2b3d7fcfe786..2db9fa0a937f3 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -371,7 +371,7 @@ void Prescanner::CheckAndEmitLine(
   // nor before or after conditional source.
   // Applications play shenanigans with line continuation before and
   // after #include'd subprogram argument lists and conditional source.
-  if (!isNestedInIncludeDirective_ && !omitNewline_ &&
+  if (!preprocessingOnly_ && !isNestedInIncludeDirective_ && !omitNewline_ &&
       !afterPreprocessingDirective_ && tokens.BadlyNestedParentheses() &&
       !preprocessor_.InConditional()) {
     if (nextLine_ < limit_ && IsPreprocessorDirectiveLine(nextLine_)) {
@@ -975,17 +975,22 @@ void Prescanner::QuotedCharacterLiteral(
     } else {
       isEscaped = false;
     }
-    EmitQuotedChar(static_cast<unsigned char>(*at_), emit, insert, false,
-        Encoding::LATIN_1);
-    while (PadOutCharacterLiteral(tokens)) {
-    }
     if (*at_ == '\n') {
-      if (!inPreprocessorDirective_) {
+      if (inPreprocessorDirective_) {
+        EmitQuotedChar(static_cast<unsigned char>(*at_), emit, insert, false,
+            Encoding::LATIN_1);
+      } else if (InCompilerDirective() && preprocessingOnly_) {
+        // don't complain about -E output of !$, do it in later compilation
+      } else {
         Say(GetProvenanceRange(start, end),
             "Incomplete character literal"_err_en_US);
       }
       break;
     }
+    EmitQuotedChar(static_cast<unsigned char>(*at_), emit, insert, false,
+        Encoding::LATIN_1);
+    while (PadOutCharacterLiteral(tokens)) {
+    }
     // Here's a weird edge case.  When there's a two or more following
     // continuation lines at this point, and the entire significant part of
     // the next continuation line is the name of a keyword macro, replace
@@ -1314,23 +1319,30 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
   }
   tabInCurrentLine_ = false;
   char col1{*nextLine_};
+  bool canBeNonDirectiveContinuation{
+      (col1 == ' ' ||
+          ((col1 == 'D' || col1 == 'd') &&
+              features_.IsEnabled(LanguageFeature::OldDebugLines))) &&
+      nextLine_[1] == ' ' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
+      nextLine_[4] == ' '};
   if (InCompilerDirective()) {
-    if (!IsFixedFormCommentChar(col1)) {
-      return nullptr;
-    } else if (directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0') {
-      // !$ OpenMP conditional compilation
-      if (preprocessingOnly_) {
-        // in -E mode, don't treat "!$   &" as a continuation
-        return nullptr;
-      } else if (nextLine_[1] == '$') {
-        // accept but do not require a matching sentinel
-        if (!(nextLine_[2] == '&' || IsSpaceOrTab(&nextLine_[2]))) {
-          return nullptr;
+    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 {
-        return nullptr; // distinct directive
+      } else if (!canBeNonDirectiveContinuation) {
+        return nullptr;
       }
-    } else { // all other directives
+    } 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
       int j{1};
       for (; j < 5; ++j) {
         char ch{directiveSentinel_[j - 1]};
@@ -1355,6 +1367,22 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
     }
   } 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;
+        }
+      }
+      return nullptr;
+    }
     if (col1 == '&' &&
         features_.IsEnabled(
             LanguageFeature::FixedFormContinuationWithColumn1Ampersand)) {
@@ -1370,15 +1398,11 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
       tabInCurrentLine_ = true;
       return nextLine_ + 2; // VAX extension
     }
-    if ((col1 == ' ' ||
-            ((col1 == 'D' || col1 == 'd') &&
-                features_.IsEnabled(LanguageFeature::OldDebugLines))) &&
-        nextLine_[1] == ' ' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
-        nextLine_[4] == ' ') {
+    if (canBeNonDirectiveContinuation) {
       const char *col6{nextLine_ + 5};
       if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
         if ((*col6 == 'i' || *col6 == 'I') && IsIncludeLine(nextLine_)) {
-          // It's An INCLUDE line, not a continuation
+          // It's an INCLUDE line, not a continuation
         } else {
           return nextLine_ + 6;
         }
diff --git a/flang/test/Parser/continuation-in-conditional-compilation.f b/flang/test/Parser/continuation-in-conditional-compilation.f
index 35525b4fda582..57b69de657348 100644
--- a/flang/test/Parser/continuation-in-conditional-compilation.f
+++ b/flang/test/Parser/continuation-in-conditional-compilation.f
@@ -5,6 +5,12 @@ program main
       k01=1+
 !$   &  1
 
+! CHECK: !$    k02=23
+! CHECK: !$   &4
+!$    k02=2
+     +3
+!$   +4
+
 ! CHECK: !$omp parallel private(k01)
 !$omp parallel
 !$omp+ private(k01)
diff --git a/flang/test/Parser/unmatched-parens.f90 b/flang/test/Parser/unmatched-parens.f90
index c0a3e843f4f72..ad8c37cf60af4 100644
--- a/flang/test/Parser/unmatched-parens.f90
+++ b/flang/test/Parser/unmatched-parens.f90
@@ -1,4 +1,4 @@
-! RUN: not %flang_fc1 -E %s 2>&1 | FileCheck %s
+! RUN: not %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
 do i = 1,10
   ! CHECK: Unmatched '('
   if (i != 0) then
diff --git a/flang/test/Preprocessing/implicit-contin3.F90 b/flang/test/Preprocessing/implicit-contin3.F90
index 8c1829d55eee7..4c31d076aa681 100644
--- a/flang/test/Preprocessing/implicit-contin3.F90
+++ b/flang/test/Preprocessing/implicit-contin3.F90
@@ -1,4 +1,4 @@
-! RUN: not %flang -E %s 2>&1 | FileCheck %s
+! RUN: not %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
 ! Test implicit continuation for possible function-like macro calls only
 #define flm(x) x
 call notamacro(3

``````````

</details>


https://github.com/llvm/llvm-project/pull/135852


More information about the flang-commits mailing list