From 55ed3bbb386a47a5977a0ba897407dd8b1059d81 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Tue, 21 Oct 2025 11:41:25 -0700 Subject: [PATCH] [flang] Line continuation for !@acc and !@cuf conditional lines 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 https://github.com/llvm/llvm-project/issues/164470. --- flang/lib/Parser/prescan.cpp | 26 +++++++++----------------- flang/lib/Parser/prescan.h | 12 +++++++++++- flang/test/Preprocessing/bug164470.cuf | 6 ++++++ 3 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 flang/test/Preprocessing/bug164470.cuf 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 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