[flang] Let !@acc and !@cuf conditional lines be continuations (#164892)
OpenMP conditional compilation lines (!$) work as continuation lines,
but OpenACC and CUDA conditional lines do not.
Fixes https://github.com/llvm/llvm-project/issues/164727 and
https://github.com/llvm/llvm-project/issues/164708.
GitOrigin-RevId: af34890ef8f501cf758525f04b3e6f0e18a96b44
diff --git a/lib/Parser/prescan.cpp b/lib/Parser/prescan.cpp
index df0372b..4739da0 100644
--- a/lib/Parser/prescan.cpp
+++ b/lib/Parser/prescan.cpp
@@ -1380,19 +1380,23 @@
}
}
} else { // Normal case: not in a compiler directive.
- // !$ conditional compilation lines may be continuations when not
+ // Conditional compilation lines may be continuations when not
// just preprocessing.
- if (!preprocessingOnly_ && IsFixedFormCommentChar(col1) &&
- nextLine_[1] == '$' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
- nextLine_[4] == ' ' && IsCompilerDirectiveSentinel(&nextLine_[1], 1)) {
- if (const char *col6{nextLine_ + 5};
- *col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
- if (atNewline && !IsSpace(nextLine_ + 6)) {
- brokenToken_ = true;
+ if (!preprocessingOnly_ && IsFixedFormCommentChar(col1)) {
+ if ((nextLine_[1] == '$' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
+ nextLine_[4] == ' ' &&
+ IsCompilerDirectiveSentinel(&nextLine_[1], 1)) ||
+ (nextLine_[1] == '@' &&
+ IsCompilerDirectiveSentinel(&nextLine_[1], 4))) {
+ if (const char *col6{nextLine_ + 5};
+ *col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
+ if (atNewline && !IsSpace(nextLine_ + 6)) {
+ brokenToken_ = true;
+ }
+ return nextLine_ + 6;
+ } else {
+ return nullptr;
}
- return nextLine_ + 6;
- } else {
- return nullptr;
}
}
if (col1 == '&' &&
@@ -1427,6 +1431,15 @@
return nullptr; // not a continuation line
}
+constexpr bool IsDirective(const char *match, const char *dir) {
+ for (; *match; ++match) {
+ if (*match != ToLowerCaseLetter(*dir++)) {
+ return false;
+ }
+ }
+ return true;
+}
+
const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
const char *lineStart{nextLine_};
const char *p{lineStart};
@@ -1439,12 +1452,18 @@
if (preprocessingOnly_) {
// in -E mode, don't treat !$ as a continuation
return nullptr;
- } else if (p[0] == '!' && p[1] == '$') {
- // accept but do not require a matching sentinel
- if (p[2] != '&' && !IsSpaceOrTab(&p[2])) {
- return nullptr; // not !$
- }
+ } else if (p[0] == '!' && (p[1] == '$' || p[1] == '@')) {
p += 2;
+ if (InOpenACCOrCUDAConditionalLine()) {
+ if (IsDirective("acc", p) || IsDirective("cuf", p)) {
+ p += 3;
+ } else {
+ return nullptr;
+ }
+ }
+ if (*p != '&' && !IsSpaceOrTab(p)) {
+ return nullptr;
+ }
}
} else if (*p++ == '!') {
for (const char *s{directiveSentinel_}; *s != '\0'; ++p, ++s) {
@@ -1467,10 +1486,17 @@
return nullptr;
}
}
- if (p[0] == '!' && p[1] == '$' && !preprocessingOnly_ &&
- features_.IsEnabled(LanguageFeature::OpenMP)) {
- // !$ conditional line can be a continuation
- p = lineStart = SkipWhiteSpace(p + 2);
+ if (p[0] == '!' && !preprocessingOnly_) {
+ // Conditional lines can be continuations
+ if (p[1] == '$' && features_.IsEnabled(LanguageFeature::OpenMP)) {
+ p = lineStart = SkipWhiteSpace(p + 2);
+ } else if (IsDirective("@acc", p + 1) &&
+ features_.IsEnabled(LanguageFeature::OpenACC)) {
+ p = lineStart = SkipWhiteSpace(p + 5);
+ } else if (IsDirective("@cuf", p + 1) &&
+ features_.IsEnabled(LanguageFeature::CUDA)) {
+ p = lineStart = SkipWhiteSpace(p + 5);
+ }
}
if (*p == '&') {
return p + 1;
@@ -1706,15 +1732,6 @@
return std::nullopt;
}
-constexpr bool IsDirective(const char *match, const char *dir) {
- for (; *match; ++match) {
- if (*match != ToLowerCaseLetter(*dir++)) {
- return false;
- }
- }
- return true;
-}
-
Prescanner::LineClassification Prescanner::ClassifyLine(
const char *start) const {
if (inFixedForm_) {
diff --git a/test/Preprocessing/bug164727.cuf b/test/Preprocessing/bug164727.cuf
new file mode 100644
index 0000000..89c846d
--- /dev/null
+++ b/test/Preprocessing/bug164727.cuf
@@ -0,0 +1,6 @@
+!RUN: %flang_fc1 -fdebug-unparse -x cuda %s 2>&1 | FileCheck %s
+!CHECK: REAL, MANAGED, ALLOCATABLE :: x
+real, &
+ !@cuf managed, &
+ allocatable :: x
+end