Skip to content

Commit 58535e8

Browse files
authored
[flang] Further refinement of OpenMP !$ lines in -E mode (#138956)
Address failing Fujitsu test suite cases that were broken by the patch to defer the handling of !$ lines in -fopenmp vs. normal compilation to actual compilation rather than processing them immediately in -E mode. Tested on the samples in the bug report as well as all of the Fujitsu tests that I could find that use !$ lines. Fixes #136845.
1 parent 5b9bd88 commit 58535e8

File tree

10 files changed

+170
-118
lines changed

10 files changed

+170
-118
lines changed

flang/include/flang/Parser/token-sequence.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class TokenSequence {
137137
TokenSequence &RemoveRedundantBlanks(std::size_t firstChar = 0);
138138
TokenSequence &ClipComment(const Prescanner &, bool skipFirst = false);
139139
const TokenSequence &CheckBadFortranCharacters(
140-
Messages &, const Prescanner &, bool allowAmpersand) const;
140+
Messages &, const Prescanner &, bool preprocessingOnly) const;
141141
bool BadlyNestedParentheses() const;
142142
const TokenSequence &CheckBadParentheses(Messages &) const;
143143
void Emit(CookedSource &) const;

flang/lib/Parser/parsing.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,18 +230,19 @@ void Parsing::EmitPreprocessedSource(
230230
column = 7; // start of fixed form source field
231231
++sourceLine;
232232
inContinuation = true;
233-
} else if (!inDirective && ch != ' ' && (ch < '0' || ch > '9')) {
233+
} else if (!inDirective && !ompConditionalLine && ch != ' ' &&
234+
(ch < '0' || ch > '9')) {
234235
// Put anything other than a label or directive into the
235236
// Fortran fixed form source field (columns [7:72]).
236-
for (; column < 7; ++column) {
237+
for (int toCol{ch == '&' ? 6 : 7}; column < toCol; ++column) {
237238
out << ' ';
238239
}
239240
}
240241
if (ch != ' ') {
241242
if (ompConditionalLine) {
242243
// Only digits can stay in the label field
243244
if (!(ch >= '0' && ch <= '9')) {
244-
for (; column < 7; ++column) {
245+
for (int toCol{ch == '&' ? 6 : 7}; column < toCol; ++column) {
245246
out << ' ';
246247
}
247248
}

flang/lib/Parser/prescan.cpp

Lines changed: 97 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,7 @@ void Prescanner::Statement() {
150150
CHECK(*at_ == '!');
151151
}
152152
std::optional<int> condOffset;
153-
bool isOpenMPCondCompilation{
154-
directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0'};
155-
if (isOpenMPCondCompilation) {
156-
// OpenMP conditional compilation line.
153+
if (InOpenMPConditionalLine()) {
157154
condOffset = 2;
158155
} else if (directiveSentinel_[0] == '@' && directiveSentinel_[1] == 'c' &&
159156
directiveSentinel_[2] == 'u' && directiveSentinel_[3] == 'f' &&
@@ -167,19 +164,10 @@ void Prescanner::Statement() {
167164
FortranInclude(at_ + *payload);
168165
return;
169166
}
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-
}
167+
if (inFixedForm_) {
168+
LabelField(tokens);
182169
}
170+
SkipSpaces();
183171
} else {
184172
// Compiler directive. Emit normalized sentinel, squash following spaces.
185173
// Conditional compilation lines (!$) take this path in -E mode too
@@ -190,35 +178,47 @@ void Prescanner::Statement() {
190178
++sp, ++at_, ++column_) {
191179
EmitChar(tokens, *sp);
192180
}
193-
if (IsSpaceOrTab(at_)) {
194-
while (int n{IsSpaceOrTab(at_)}) {
195-
if (isOpenMPCondCompilation && inFixedForm_) {
181+
if (inFixedForm_) {
182+
while (column_ < 6) {
183+
if (*at_ == '\t') {
184+
tabInCurrentLine_ = true;
185+
++at_;
186+
for (; column_ < 7; ++column_) {
187+
EmitChar(tokens, ' ');
188+
}
189+
} else if (int spaceBytes{IsSpace(at_)}) {
196190
EmitChar(tokens, ' ');
197-
}
198-
tabInCurrentLine_ |= *at_ == '\t';
199-
at_ += n, ++column_;
200-
if (inFixedForm_ && column_ > fixedFormColumnLimit_) {
191+
at_ += spaceBytes;
192+
++column_;
193+
} else {
194+
if (InOpenMPConditionalLine() && column_ == 3 &&
195+
IsDecimalDigit(*at_)) {
196+
// subtle: !$ in -E mode can't be immediately followed by a digit
197+
EmitChar(tokens, ' ');
198+
}
201199
break;
202200
}
203201
}
204-
if (isOpenMPCondCompilation && inFixedForm_ && column_ == 6) {
205-
if (*at_ == '0') {
206-
EmitChar(tokens, ' ');
207-
} else {
208-
tokens.CloseToken();
209-
EmitChar(tokens, '&');
210-
}
211-
++at_, ++column_;
202+
} else if (int spaceBytes{IsSpaceOrTab(at_)}) {
203+
EmitChar(tokens, ' ');
204+
at_ += spaceBytes, ++column_;
205+
}
206+
tokens.CloseToken();
207+
SkipSpaces();
208+
if (InOpenMPConditionalLine() && inFixedForm_ && !tabInCurrentLine_ &&
209+
column_ == 6 && *at_ != '\n') {
210+
// !$ 0 - turn '0' into a space
211+
// !$ 1 - turn '1' into '&'
212+
if (int n{IsSpace(at_)}; n || *at_ == '0') {
213+
at_ += n ? n : 1;
212214
} else {
213-
EmitChar(tokens, ' ');
215+
++at_;
216+
EmitChar(tokens, '&');
217+
tokens.CloseToken();
214218
}
219+
++column_;
220+
SkipSpaces();
215221
}
216-
tokens.CloseToken();
217-
}
218-
if (*at_ == '!' || *at_ == '\n' ||
219-
(inFixedForm_ && column_ > fixedFormColumnLimit_ &&
220-
!tabInCurrentLine_)) {
221-
return; // Directive without payload
222222
}
223223
break;
224224
}
@@ -323,8 +323,8 @@ void Prescanner::Statement() {
323323
NormalizeCompilerDirectiveCommentMarker(*preprocessed);
324324
preprocessed->ToLowerCase();
325325
SourceFormChange(preprocessed->ToString());
326-
CheckAndEmitLine(preprocessed->ToLowerCase().ClipComment(
327-
*this, true /* skip first ! */),
326+
CheckAndEmitLine(
327+
preprocessed->ClipComment(*this, true /* skip first ! */),
328328
newlineProvenance);
329329
break;
330330
case LineClassification::Kind::Source:
@@ -349,6 +349,24 @@ void Prescanner::Statement() {
349349
while (CompilerDirectiveContinuation(tokens, line.sentinel)) {
350350
newlineProvenance = GetCurrentProvenance();
351351
}
352+
if (preprocessingOnly_ && inFixedForm_ && InOpenMPConditionalLine() &&
353+
nextLine_ < limit_) {
354+
// In -E mode, when the line after !$ conditional compilation is a
355+
// regular fixed form continuation line, append a '&' to the line.
356+
const char *p{nextLine_};
357+
int col{1};
358+
while (int n{IsSpace(p)}) {
359+
if (*p == '\t') {
360+
break;
361+
}
362+
p += n;
363+
++col;
364+
}
365+
if (col == 6 && *p != '0' && *p != '\t' && *p != '\n') {
366+
EmitChar(tokens, '&');
367+
tokens.CloseToken();
368+
}
369+
}
352370
tokens.ToLowerCase();
353371
SourceFormChange(tokens.ToString());
354372
} else { // Kind::Source
@@ -544,7 +562,8 @@ void Prescanner::SkipToEndOfLine() {
544562
bool Prescanner::MustSkipToEndOfLine() const {
545563
if (inFixedForm_ && column_ > fixedFormColumnLimit_ && !tabInCurrentLine_) {
546564
return true; // skip over ignored columns in right margin (73:80)
547-
} else if (*at_ == '!' && !inCharLiteral_) {
565+
} else if (*at_ == '!' && !inCharLiteral_ &&
566+
(!inFixedForm_ || tabInCurrentLine_ || column_ != 6)) {
548567
return !IsCompilerDirectiveSentinel(at_);
549568
} else {
550569
return false;
@@ -569,10 +588,11 @@ void Prescanner::NextChar() {
569588
// directives, Fortran ! comments, stuff after the right margin in
570589
// fixed form, and all forms of line continuation.
571590
bool Prescanner::SkipToNextSignificantCharacter() {
572-
auto anyContinuationLine{false};
573591
if (inPreprocessorDirective_) {
574592
SkipCComments();
593+
return false;
575594
} else {
595+
auto anyContinuationLine{false};
576596
bool mightNeedSpace{false};
577597
if (MustSkipToEndOfLine()) {
578598
SkipToEndOfLine();
@@ -589,8 +609,8 @@ bool Prescanner::SkipToNextSignificantCharacter() {
589609
if (*at_ == '\t') {
590610
tabInCurrentLine_ = true;
591611
}
612+
return anyContinuationLine;
592613
}
593-
return anyContinuationLine;
594614
}
595615

596616
void Prescanner::SkipCComments() {
@@ -1119,12 +1139,10 @@ static bool IsAtProcess(const char *p) {
11191139

11201140
bool Prescanner::IsFixedFormCommentLine(const char *start) const {
11211141
const char *p{start};
1122-
11231142
// The @process directive must start in column 1.
11241143
if (*p == '@' && IsAtProcess(p)) {
11251144
return true;
11261145
}
1127-
11281146
if (IsFixedFormCommentChar(*p) || *p == '%' || // VAX %list, %eject, &c.
11291147
((*p == 'D' || *p == 'd') &&
11301148
!features_.IsEnabled(LanguageFeature::OldDebugLines))) {
@@ -1324,24 +1342,11 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
13241342
features_.IsEnabled(LanguageFeature::OldDebugLines))) &&
13251343
nextLine_[1] == ' ' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
13261344
nextLine_[4] == ' '};
1327-
if (InCompilerDirective()) {
1328-
if (directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0') {
1329-
if (IsFixedFormCommentChar(col1)) {
1330-
if (nextLine_[1] == '$' &&
1331-
(nextLine_[2] == '&' || IsSpaceOrTab(&nextLine_[2]))) {
1332-
// Next line is also !$ conditional compilation, might be continuation
1333-
if (preprocessingOnly_) {
1334-
return nullptr;
1335-
}
1336-
} else {
1337-
return nullptr; // comment, or distinct directive
1338-
}
1339-
} else if (!canBeNonDirectiveContinuation) {
1340-
return nullptr;
1341-
}
1342-
} else if (!IsFixedFormCommentChar(col1)) {
1343-
return nullptr; // in directive other than !$, but next line is not
1344-
} else { // in directive other than !$, next line might be continuation
1345+
if (InCompilerDirective() &&
1346+
!(InOpenMPConditionalLine() && !preprocessingOnly_)) {
1347+
// !$ under -E is not continued, but deferred to later compilation
1348+
if (IsFixedFormCommentChar(col1) &&
1349+
!(InOpenMPConditionalLine() && preprocessingOnly_)) {
13451350
int j{1};
13461351
for (; j < 5; ++j) {
13471352
char ch{directiveSentinel_[j - 1]};
@@ -1356,31 +1361,27 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
13561361
return nullptr;
13571362
}
13581363
}
1359-
}
1360-
const char *col6{nextLine_ + 5};
1361-
if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
1362-
if (mightNeedSpace && !IsSpace(nextLine_ + 6)) {
1363-
insertASpace_ = true;
1364+
const char *col6{nextLine_ + 5};
1365+
if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
1366+
if (mightNeedSpace && !IsSpace(nextLine_ + 6)) {
1367+
insertASpace_ = true;
1368+
}
1369+
return nextLine_ + 6;
13641370
}
1365-
return nextLine_ + 6;
13661371
}
1367-
} else {
1368-
// Normal case: not in a compiler directive.
1369-
if (IsFixedFormCommentChar(col1)) {
1370-
if (nextLine_[1] == '$' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
1371-
nextLine_[4] == ' ' &&
1372-
IsCompilerDirectiveSentinel(&nextLine_[1], 1) &&
1373-
!preprocessingOnly_) {
1374-
// !$ conditional compilation line as a continuation
1375-
const char *col6{nextLine_ + 5};
1376-
if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
1377-
if (mightNeedSpace && !IsSpace(nextLine_ + 6)) {
1378-
insertASpace_ = true;
1379-
}
1380-
return nextLine_ + 6;
1381-
}
1372+
} else { // Normal case: not in a compiler directive.
1373+
// !$ conditional compilation lines may be continuations when not
1374+
// just preprocessing.
1375+
if (!preprocessingOnly_ && IsFixedFormCommentChar(col1) &&
1376+
nextLine_[1] == '$' && nextLine_[2] == ' ' && nextLine_[3] == ' ' &&
1377+
nextLine_[4] == ' ' && IsCompilerDirectiveSentinel(&nextLine_[1], 1)) {
1378+
if (const char *col6{nextLine_ + 5};
1379+
*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
1380+
insertASpace_ |= mightNeedSpace && !IsSpace(nextLine_ + 6);
1381+
return nextLine_ + 6;
1382+
} else {
1383+
return nullptr;
13821384
}
1383-
return nullptr;
13841385
}
13851386
if (col1 == '&' &&
13861387
features_.IsEnabled(
@@ -1422,13 +1423,13 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
14221423
}
14231424
p = SkipWhiteSpaceIncludingEmptyMacros(p);
14241425
if (InCompilerDirective()) {
1425-
if (directiveSentinel_[0] == '$' && directiveSentinel_[1] == '\0') {
1426+
if (InOpenMPConditionalLine()) {
14261427
if (preprocessingOnly_) {
14271428
// in -E mode, don't treat !$ as a continuation
14281429
return nullptr;
14291430
} else if (p[0] == '!' && p[1] == '$') {
14301431
// accept but do not require a matching sentinel
1431-
if (!(p[2] == '&' || IsSpaceOrTab(&p[2]))) {
1432+
if (p[2] != '&' && !IsSpaceOrTab(&p[2])) {
14321433
return nullptr; // not !$
14331434
}
14341435
p += 2;
@@ -1566,15 +1567,11 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
15661567
}
15671568
char sentinel[5], *sp{sentinel};
15681569
int column{2};
1569-
for (; column < 6; ++column, ++p) {
1570-
if (*p == '\n' || IsSpaceOrTab(p)) {
1571-
break;
1572-
}
1573-
if (sp == sentinel + 1 && sentinel[0] == '$' && IsDecimalDigit(*p)) {
1574-
// OpenMP conditional compilation line: leave the label alone
1570+
for (; column < 6; ++column) {
1571+
if (*p == '\n' || IsSpaceOrTab(p) || IsDecimalDigit(*p)) {
15751572
break;
15761573
}
1577-
*sp++ = ToLowerCaseLetter(*p);
1574+
*sp++ = ToLowerCaseLetter(*p++);
15781575
}
15791576
if (sp == sentinel) {
15801577
return std::nullopt;
@@ -1600,7 +1597,8 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
16001597
++p;
16011598
} else if (int n{IsSpaceOrTab(p)}) {
16021599
p += n;
1603-
} else if (isOpenMPConditional && preprocessingOnly_ && !hadDigit) {
1600+
} else if (isOpenMPConditional && preprocessingOnly_ && !hadDigit &&
1601+
*p != '\n') {
16041602
// In -E mode, "!$ &" is treated as a directive
16051603
} else {
16061604
// This is a Continuation line, not an initial directive line.
@@ -1671,14 +1669,14 @@ const char *Prescanner::IsCompilerDirectiveSentinel(CharBlock token) const {
16711669
std::optional<std::pair<const char *, const char *>>
16721670
Prescanner::IsCompilerDirectiveSentinel(const char *p) const {
16731671
char sentinel[8];
1674-
for (std::size_t j{0}; j + 1 < sizeof sentinel && *p != '\n'; ++p, ++j) {
1672+
for (std::size_t j{0}; j + 1 < sizeof sentinel; ++p, ++j) {
16751673
if (int n{IsSpaceOrTab(p)};
16761674
n || !(IsLetter(*p) || *p == '$' || *p == '@')) {
16771675
if (j > 0) {
1678-
if (j == 1 && sentinel[0] == '$' && n == 0 && *p != '&') {
1679-
// OpenMP conditional compilation line sentinels have to
1676+
if (j == 1 && sentinel[0] == '$' && n == 0 && *p != '&' && *p != '\n') {
1677+
// Free form OpenMP conditional compilation line sentinels have to
16801678
// be immediately followed by a space or &, not a digit
1681-
// or anything else.
1679+
// or anything else. A newline also works for an initial line.
16821680
break;
16831681
}
16841682
sentinel[j] = '\0';

flang/lib/Parser/prescan.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ class Prescanner {
159159
}
160160

161161
bool InCompilerDirective() const { return directiveSentinel_ != nullptr; }
162+
bool InOpenMPConditionalLine() const {
163+
return directiveSentinel_ && directiveSentinel_[0] == '$' &&
164+
!directiveSentinel_[1];
165+
;
166+
}
162167
bool InFixedFormSource() const {
163168
return inFixedForm_ && !inPreprocessorDirective_ && !InCompilerDirective();
164169
}

flang/lib/Parser/token-sequence.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ ProvenanceRange TokenSequence::GetProvenanceRange() const {
357357

358358
const TokenSequence &TokenSequence::CheckBadFortranCharacters(
359359
Messages &messages, const Prescanner &prescanner,
360-
bool allowAmpersand) const {
360+
bool preprocessingOnly) const {
361361
std::size_t tokens{SizeInTokens()};
362362
for (std::size_t j{0}; j < tokens; ++j) {
363363
CharBlock token{TokenAt(j)};
@@ -371,8 +371,10 @@ const TokenSequence &TokenSequence::CheckBadFortranCharacters(
371371
TokenAt(j + 1))) { // !dir$, &c.
372372
++j;
373373
continue;
374+
} else if (preprocessingOnly) {
375+
continue;
374376
}
375-
} else if (ch == '&' && allowAmpersand) {
377+
} else if (ch == '&' && preprocessingOnly) {
376378
continue;
377379
}
378380
if (ch < ' ' || ch >= '\x7f') {

0 commit comments

Comments
 (0)