Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 18, 2025

Conversation

klausler
Copy link
Contributor

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

I broke fixed-form line continuation (without !$) for OpenMP !$
conditional compilation lines.  Fix it.
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:parser labels Apr 15, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 15, 2025

@llvm/pr-subscribers-flang-parser

Author: Peter Klausler (klausler)

Changes

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

@klausler
Copy link
Contributor Author

ping! Please review when convenient, thanks.

@klausler klausler merged commit b4ff435 into llvm:main Apr 18, 2025
14 checks passed
@klausler klausler deleted the omp-fix branch April 18, 2025 19:50
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…lvm#135852)

I broke fixed-form line continuation (without !$) for OpenMP !$
conditional compilation lines. Fix it.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…lvm#135852)

I broke fixed-form line continuation (without !$) for OpenMP !$
conditional compilation lines. Fix it.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…lvm#135852)

I broke fixed-form line continuation (without !$) for OpenMP !$
conditional compilation lines. Fix it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:parser flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants