Skip to content

Conversation

@klausler
Copy link
Contributor

Some Fortran source-level features that work for OpenMP !$ conditional lines, such as free form line continuation, don't work for OpenACC !@acc or CUDA !@Cuf conditional lines. Make them less particular.

Fixes #164470.

Some Fortran source-level features that work for OpenMP !$ conditional
lines, such as free form line continuation, don't work for OpenACC
!@acc or CUDA !@Cuf conditional lines.  Make them less particular.

Fixes llvm#164470.
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:parser labels Oct 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 21, 2025

@llvm/pr-subscribers-flang-parser

Author: Peter Klausler (klausler)

Changes

Some Fortran source-level features that work for OpenMP !$ conditional lines, such as free form line continuation, don't work for OpenACC !@acc or CUDA !@cuf conditional lines. Make them less particular.

Fixes #164470.


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

3 Files Affected:

  • (modified) flang/lib/Parser/prescan.cpp (+9-17)
  • (modified) flang/lib/Parser/prescan.h (+11-1)
  • (added) flang/test/Preprocessing/bug164470.cuf (+6)
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index 66e5b2cbd5c7f..df0372bbe554a 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -140,17 +140,9 @@ void Prescanner::Statement() {
       CHECK(*at_ == '!');
     }
     std::optional<int> condOffset;
-    if (InOpenMPConditionalLine()) {
+    if (InOpenMPConditionalLine()) { // !$
       condOffset = 2;
-    } else if (directiveSentinel_[0] == '@' && directiveSentinel_[1] == 'c' &&
-        directiveSentinel_[2] == 'u' && directiveSentinel_[3] == 'f' &&
-        directiveSentinel_[4] == '\0') {
-      // CUDA conditional compilation line.
-      condOffset = 5;
-    } else if (directiveSentinel_[0] == '@' && directiveSentinel_[1] == 'a' &&
-        directiveSentinel_[2] == 'c' && directiveSentinel_[3] == 'c' &&
-        directiveSentinel_[4] == '\0') {
-      // OpenACC conditional compilation line.
+    } else if (InOpenACCOrCUDAConditionalLine()) { // !@acc or !@cuf
       condOffset = 5;
     }
     if (condOffset && !preprocessingOnly_) {
@@ -166,7 +158,8 @@ void Prescanner::Statement() {
     } else {
       // Compiler directive.  Emit normalized sentinel, squash following spaces.
       // Conditional compilation lines (!$) take this path in -E mode too
-      // so that -fopenmp only has to appear on the later compilation.
+      // so that -fopenmp only has to appear on the later compilation
+      // (ditto for !@cuf and !@acc).
       EmitChar(tokens, '!');
       ++at_, ++column_;
       for (const char *sp{directiveSentinel_}; *sp != '\0';
@@ -202,7 +195,7 @@ void Prescanner::Statement() {
       }
       tokens.CloseToken();
       SkipSpaces();
-      if (InOpenMPConditionalLine() && inFixedForm_ && !tabInCurrentLine_ &&
+      if (InConditionalLine() && inFixedForm_ && !tabInCurrentLine_ &&
           column_ == 6 && *at_ != '\n') {
         // !$   0   - turn '0' into a space
         // !$   1   - turn '1' into '&'
@@ -347,7 +340,7 @@ void Prescanner::Statement() {
       while (CompilerDirectiveContinuation(tokens, line.sentinel)) {
         newlineProvenance = GetCurrentProvenance();
       }
-      if (preprocessingOnly_ && inFixedForm_ && InOpenMPConditionalLine() &&
+      if (preprocessingOnly_ && inFixedForm_ && InConditionalLine() &&
           nextLine_ < limit_) {
         // In -E mode, when the line after !$ conditional compilation is a
         // regular fixed form continuation line, append a '&' to the line.
@@ -1360,11 +1353,10 @@ const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
               features_.IsEnabled(LanguageFeature::OldDebugLines))) &&
       nextLine_[1] == ' ' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
       nextLine_[4] == ' '};
-  if (InCompilerDirective() &&
-      !(InOpenMPConditionalLine() && !preprocessingOnly_)) {
+  if (InCompilerDirective() && !(InConditionalLine() && !preprocessingOnly_)) {
     // !$ under -E is not continued, but deferred to later compilation
     if (IsFixedFormCommentChar(col1) &&
-        !(InOpenMPConditionalLine() && preprocessingOnly_)) {
+        !(InConditionalLine() && preprocessingOnly_)) {
       int j{1};
       for (; j < 5; ++j) {
         char ch{directiveSentinel_[j - 1]};
@@ -1443,7 +1435,7 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
   }
   p = SkipWhiteSpaceIncludingEmptyMacros(p);
   if (InCompilerDirective()) {
-    if (InOpenMPConditionalLine()) {
+    if (InConditionalLine()) {
       if (preprocessingOnly_) {
         // in -E mode, don't treat !$ as a continuation
         return nullptr;
diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h
index fc38adb926530..5e7481781d944 100644
--- a/flang/lib/Parser/prescan.h
+++ b/flang/lib/Parser/prescan.h
@@ -171,7 +171,17 @@ class Prescanner {
   bool InOpenMPConditionalLine() const {
     return directiveSentinel_ && directiveSentinel_[0] == '$' &&
         !directiveSentinel_[1];
-    ;
+  }
+  bool InOpenACCOrCUDAConditionalLine() const {
+    return directiveSentinel_ && directiveSentinel_[0] == '@' &&
+        ((directiveSentinel_[1] == 'a' && directiveSentinel_[2] == 'c' &&
+             directiveSentinel_[3] == 'c') ||
+            (directiveSentinel_[1] == 'c' && directiveSentinel_[2] == 'u' &&
+                directiveSentinel_[3] == 'f')) &&
+        directiveSentinel_[4] == '\0';
+  }
+  bool InConditionalLine() const {
+    return InOpenMPConditionalLine() || InOpenACCOrCUDAConditionalLine();
   }
   bool InFixedFormSource() const {
     return inFixedForm_ && !inPreprocessorDirective_ && !InCompilerDirective();
diff --git a/flang/test/Preprocessing/bug164470.cuf b/flang/test/Preprocessing/bug164470.cuf
new file mode 100644
index 0000000000000..3e959f40d2e3f
--- /dev/null
+++ b/flang/test/Preprocessing/bug164470.cuf
@@ -0,0 +1,6 @@
+!RUN: %flang_fc1 -x cuda -fdebug-unparse %s 2>&1 | FileCheck %s
+!CHECK: ATTRIBUTES(DEVICE) FUNCTION foo()
+!@cuf attributes(device) &
+function foo()
+  foo = 1.
+end

Copy link
Contributor

@clementval clementval left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks

@klausler klausler merged commit d5103c1 into llvm:main Oct 21, 2025
13 checks passed
@klausler klausler deleted the bug164470 branch October 21, 2025 20:38
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
…#164475)

Some Fortran source-level features that work for OpenMP !$ conditional
lines, such as free form line continuation, don't work for OpenACC !@acc
or CUDA !@Cuf conditional lines. Make them less particular.

Fixes llvm#164470.
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
…#164475)

Some Fortran source-level features that work for OpenMP !$ conditional
lines, such as free form line continuation, don't work for OpenACC !@acc
or CUDA !@Cuf conditional lines. Make them less particular.

Fixes llvm#164470.
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.

Continuation line not supported with cuf or OpenACC conditional compilation line

4 participants