@@ -150,11 +150,11 @@ void Prescanner::Statement() {
150
150
CHECK (*at_ == ' !' );
151
151
}
152
152
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) {
155
156
// OpenMP conditional compilation line.
156
157
condOffset = 2 ;
157
- isFFOpenMPCondCompilation = inFixedForm_;
158
158
} else if (directiveSentinel_[0 ] == ' @' && directiveSentinel_[1 ] == ' c' &&
159
159
directiveSentinel_[2 ] == ' u' && directiveSentinel_[3 ] == ' f' &&
160
160
directiveSentinel_[4 ] == ' \0 ' ) {
@@ -166,10 +166,19 @@ void Prescanner::Statement() {
166
166
if (auto payload{IsIncludeLine (at_)}) {
167
167
FortranInclude (at_ + *payload);
168
168
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
+ }
173
182
}
174
183
} else {
175
184
// Compiler directive. Emit normalized sentinel, squash following spaces.
@@ -183,12 +192,16 @@ void Prescanner::Statement() {
183
192
}
184
193
if (IsSpaceOrTab (at_)) {
185
194
while (int n{IsSpaceOrTab (at_)}) {
186
- if (isFFOpenMPCondCompilation ) {
195
+ if (isOpenMPCondCompilation && inFixedForm_ ) {
187
196
EmitChar (tokens, ' ' );
188
197
}
198
+ tabInCurrentLine_ |= *at_ == ' \t ' ;
189
199
at_ += n, ++column_;
200
+ if (inFixedForm_ && column_ > fixedFormColumnLimit_) {
201
+ break ;
202
+ }
190
203
}
191
- if (isFFOpenMPCondCompilation && column_ == 6 ) {
204
+ if (isOpenMPCondCompilation && inFixedForm_ && column_ == 6 ) {
192
205
if (*at_ == ' 0' ) {
193
206
EmitChar (tokens, ' ' );
194
207
} else {
@@ -202,6 +215,11 @@ void Prescanner::Statement() {
202
215
}
203
216
tokens.CloseToken ();
204
217
}
218
+ if (*at_ == ' !' || *at_ == ' \n ' ||
219
+ (inFixedForm_ && column_ > fixedFormColumnLimit_ &&
220
+ !tabInCurrentLine_)) {
221
+ return ; // Directive without payload
222
+ }
205
223
break ;
206
224
}
207
225
case LineClassification::Kind::Source: {
@@ -1291,17 +1309,28 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
1291
1309
tabInCurrentLine_ = false ;
1292
1310
char col1{*nextLine_};
1293
1311
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
+ }
1297
1327
} else if (IsFixedFormCommentChar (col1)) {
1298
1328
int j{1 };
1299
1329
for (; j < 5 ; ++j) {
1300
1330
char ch{directiveSentinel_[j - 1 ]};
1301
1331
if (ch == ' \0 ' ) {
1302
1332
break ;
1303
- }
1304
- if (ch != ToLowerCaseLetter (nextLine_[j])) {
1333
+ } else if (ch != ToLowerCaseLetter (nextLine_[j])) {
1305
1334
return nullptr ;
1306
1335
}
1307
1336
}
@@ -1310,13 +1339,15 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
1310
1339
return nullptr ;
1311
1340
}
1312
1341
}
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 ;
1319
1349
}
1350
+ return nextLine_ + 6 ;
1320
1351
}
1321
1352
} else {
1322
1353
// Normal case: not in a compiler directive.
@@ -1364,26 +1395,37 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
1364
1395
}
1365
1396
p = SkipWhiteSpaceIncludingEmptyMacros (p);
1366
1397
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
+ }
1370
1409
} else if (*p++ == ' !' ) {
1371
1410
for (const char *s{directiveSentinel_}; *s != ' \0 ' ; ++p, ++s) {
1372
1411
if (*s != ToLowerCaseLetter (*p)) {
1373
1412
return nullptr ; // not the same directive class
1374
1413
}
1375
1414
}
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 ;
1384
1422
}
1423
+ return p + 1 ;
1424
+ } else if (ampersand) {
1425
+ return p;
1426
+ } else {
1427
+ return nullptr ;
1385
1428
}
1386
- return nullptr ;
1387
1429
}
1388
1430
if (p[0 ] == ' !' && p[1 ] == ' $' && !preprocessingOnly_ &&
1389
1431
features_.IsEnabled (LanguageFeature::OpenMP)) {
@@ -1606,8 +1648,13 @@ Prescanner::IsCompilerDirectiveSentinel(const char *p) const {
1606
1648
if (int n{IsSpaceOrTab (p)};
1607
1649
n || !(IsLetter (*p) || *p == ' $' || *p == ' @' )) {
1608
1650
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
+ }
1609
1657
sentinel[j] = ' \0 ' ;
1610
- p = SkipWhiteSpaceIncludingEmptyMacros (p + n);
1611
1658
if (*p != ' !' ) {
1612
1659
if (const char *sp{IsCompilerDirectiveSentinel (sentinel, j)}) {
1613
1660
return std::make_pair (sp, p);
0 commit comments