Skip to content

Commit 0ae9bb9

Browse files
authored
[flang][OpenMP] Fix regression in !$ continuation (#134756)
A recent patch that obviated the need to use -fopenmp when using the compiler to preprocess in -E mode broke a case of Fortran line continuation when using OpenMP conditional compilation lines (!$) when *not* in -E mode. Fix.
1 parent be133ff commit 0ae9bb9

File tree

2 files changed

+90
-34
lines changed

2 files changed

+90
-34
lines changed

flang/lib/Parser/prescan.cpp

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,11 @@ void Prescanner::Statement() {
150150
CHECK(*at_ == '!');
151151
}
152152
std::optional<int> condOffset;
153-
bool isFFOpenMPCondCompilation{false};
154-
if (directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0') {
153+
bool isOpenMPCondCompilation{
154+
directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0'};
155+
if (isOpenMPCondCompilation) {
155156
// OpenMP conditional compilation line.
156157
condOffset = 2;
157-
isFFOpenMPCondCompilation = inFixedForm_;
158158
} else if (directiveSentinel_[0] == '@' && directiveSentinel_[1] == 'c' &&
159159
directiveSentinel_[2] == 'u' && directiveSentinel_[3] == 'f' &&
160160
directiveSentinel_[4] == '\0') {
@@ -166,10 +166,19 @@ void Prescanner::Statement() {
166166
if (auto payload{IsIncludeLine(at_)}) {
167167
FortranInclude(at_ + *payload);
168168
return;
169-
} else if (inFixedForm_) {
170-
LabelField(tokens);
171-
} else {
172-
SkipSpaces();
169+
}
170+
while (true) {
171+
if (auto n{IsSpace(at_)}) {
172+
at_ += n, ++column_;
173+
} else if (*at_ == '\t') {
174+
++at_, ++column_;
175+
tabInCurrentLine_ = true;
176+
} else if (inFixedForm_ && column_ == 6 && !tabInCurrentLine_ &&
177+
*at_ == '0') {
178+
++at_, ++column_;
179+
} else {
180+
break;
181+
}
173182
}
174183
} else {
175184
// Compiler directive. Emit normalized sentinel, squash following spaces.
@@ -183,12 +192,16 @@ void Prescanner::Statement() {
183192
}
184193
if (IsSpaceOrTab(at_)) {
185194
while (int n{IsSpaceOrTab(at_)}) {
186-
if (isFFOpenMPCondCompilation) {
195+
if (isOpenMPCondCompilation && inFixedForm_) {
187196
EmitChar(tokens, ' ');
188197
}
198+
tabInCurrentLine_ |= *at_ == '\t';
189199
at_ += n, ++column_;
200+
if (inFixedForm_ && column_ > fixedFormColumnLimit_) {
201+
break;
202+
}
190203
}
191-
if (isFFOpenMPCondCompilation && column_ == 6) {
204+
if (isOpenMPCondCompilation && inFixedForm_ && column_ == 6) {
192205
if (*at_ == '0') {
193206
EmitChar(tokens, ' ');
194207
} else {
@@ -202,6 +215,11 @@ void Prescanner::Statement() {
202215
}
203216
tokens.CloseToken();
204217
}
218+
if (*at_ == '!' || *at_ == '\n' ||
219+
(inFixedForm_ && column_ > fixedFormColumnLimit_ &&
220+
!tabInCurrentLine_)) {
221+
return; // Directive without payload
222+
}
205223
break;
206224
}
207225
case LineClassification::Kind::Source: {
@@ -1291,17 +1309,28 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
12911309
tabInCurrentLine_ = false;
12921310
char col1{*nextLine_};
12931311
if (InCompilerDirective()) {
1294-
if (preprocessingOnly_ && directiveSentinel_[0] == '$' &&
1295-
directiveSentinel_[1] == '\0') {
1296-
// in -E mode, don't treat "!$ &" as a continuation
1312+
if (directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0') {
1313+
// !$ OpenMP conditional compilation
1314+
if (preprocessingOnly_) {
1315+
// in -E mode, don't treat "!$ &" as a continuation
1316+
return nullptr;
1317+
} else if (IsFixedFormCommentChar(col1)) {
1318+
if (nextLine_[1] == '$') {
1319+
// accept but do not require a matching sentinel
1320+
if (!(nextLine_[2] == '&' || IsSpaceOrTab(&nextLine_[2]))) {
1321+
return nullptr;
1322+
}
1323+
} else {
1324+
return nullptr; // distinct directive
1325+
}
1326+
}
12971327
} else if (IsFixedFormCommentChar(col1)) {
12981328
int j{1};
12991329
for (; j < 5; ++j) {
13001330
char ch{directiveSentinel_[j - 1]};
13011331
if (ch == '\0') {
13021332
break;
1303-
}
1304-
if (ch != ToLowerCaseLetter(nextLine_[j])) {
1333+
} else if (ch != ToLowerCaseLetter(nextLine_[j])) {
13051334
return nullptr;
13061335
}
13071336
}
@@ -1310,13 +1339,15 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
13101339
return nullptr;
13111340
}
13121341
}
1313-
const char *col6{nextLine_ + 5};
1314-
if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
1315-
if (mightNeedSpace && !IsSpace(nextLine_ + 6)) {
1316-
insertASpace_ = true;
1317-
}
1318-
return nextLine_ + 6;
1342+
} else {
1343+
return nullptr;
1344+
}
1345+
const char *col6{nextLine_ + 5};
1346+
if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
1347+
if (mightNeedSpace && !IsSpace(nextLine_ + 6)) {
1348+
insertASpace_ = true;
13191349
}
1350+
return nextLine_ + 6;
13201351
}
13211352
} else {
13221353
// Normal case: not in a compiler directive.
@@ -1364,26 +1395,37 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
13641395
}
13651396
p = SkipWhiteSpaceIncludingEmptyMacros(p);
13661397
if (InCompilerDirective()) {
1367-
if (preprocessingOnly_ && directiveSentinel_[0] == '$' &&
1368-
directiveSentinel_[1] == '\0') {
1369-
// in -E mode, don't treat !$ as a continuation
1398+
if (directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0') {
1399+
if (preprocessingOnly_) {
1400+
// in -E mode, don't treat !$ as a continuation
1401+
return nullptr;
1402+
} else if (p[0] == '!' && p[1] == '$') {
1403+
// accept but do not require a matching sentinel
1404+
if (!(p[2] == '&' || IsSpaceOrTab(&p[2]))) {
1405+
return nullptr; // not !$
1406+
}
1407+
p += 2;
1408+
}
13701409
} else if (*p++ == '!') {
13711410
for (const char *s{directiveSentinel_}; *s != '\0'; ++p, ++s) {
13721411
if (*s != ToLowerCaseLetter(*p)) {
13731412
return nullptr; // not the same directive class
13741413
}
13751414
}
1376-
p = SkipWhiteSpace(p);
1377-
if (*p == '&') {
1378-
if (!ampersand) {
1379-
insertASpace_ = true;
1380-
}
1381-
return p + 1;
1382-
} else if (ampersand) {
1383-
return p;
1415+
} else {
1416+
return nullptr;
1417+
}
1418+
p = SkipWhiteSpace(p);
1419+
if (*p == '&') {
1420+
if (!ampersand) {
1421+
insertASpace_ = true;
13841422
}
1423+
return p + 1;
1424+
} else if (ampersand) {
1425+
return p;
1426+
} else {
1427+
return nullptr;
13851428
}
1386-
return nullptr;
13871429
}
13881430
if (p[0] == '!' && p[1] == '$' && !preprocessingOnly_ &&
13891431
features_.IsEnabled(LanguageFeature::OpenMP)) {
@@ -1606,8 +1648,13 @@ Prescanner::IsCompilerDirectiveSentinel(const char *p) const {
16061648
if (int n{IsSpaceOrTab(p)};
16071649
n || !(IsLetter(*p) || *p == '$' || *p == '@')) {
16081650
if (j > 0) {
1651+
if (j == 1 && sentinel[0] == '$' && n == 0 && *p != '&') {
1652+
// OpenMP conditional compilation line sentinels have to
1653+
// be immediately followed by a space or &, not a digit
1654+
// or anything else.
1655+
break;
1656+
}
16091657
sentinel[j] = '\0';
1610-
p = SkipWhiteSpaceIncludingEmptyMacros(p + n);
16111658
if (*p != '!') {
16121659
if (const char *sp{IsCompilerDirectiveSentinel(sentinel, j)}) {
16131660
return std::make_pair(sp, p);

flang/test/Parser/OpenMP/compiler-directive-continuation.f90

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
! CHECK-NO-OMP: i=1010011_4
1616
subroutine mixed_form1()
1717
i = 1 &
18-
!$+100&
18+
!$ +100&
1919
!$&+ 1000&
2020
&+ 10 + 1&
2121
!$& +100000&
@@ -53,3 +53,12 @@ subroutine mixed_form3()
5353
!$ +1000
5454
end subroutine
5555

56+
! CHECK-LABEL: subroutine regression
57+
! CHECK-E:{{^}}!$ real x, &
58+
! CHECK-E:{{^}} stop
59+
! CHECK-OMP: REAL x, stop
60+
! CHECK-NO-OMP-NOT: REAL x,
61+
subroutine regression
62+
!$ real x, &
63+
stop
64+
end

0 commit comments

Comments
 (0)