@@ -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: {
@@ -1278,17 +1296,28 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
12781296 tabInCurrentLine_ = false ;
12791297 char col1{*nextLine_};
12801298 if (InCompilerDirective ()) {
1281- if (preprocessingOnly_ && directiveSentinel_[0 ] == ' $' &&
1282- directiveSentinel_[1 ] == ' \0 ' ) {
1283- // in -E mode, don't treat "!$ &" as a continuation
1299+ if (directiveSentinel_[0 ] == ' $' && directiveSentinel_[1 ] == ' \0 ' ) {
1300+ // !$ OpenMP conditional compilation
1301+ if (preprocessingOnly_) {
1302+ // in -E mode, don't treat "!$ &" as a continuation
1303+ return nullptr ;
1304+ } else if (IsFixedFormCommentChar (col1)) {
1305+ if (nextLine_[1 ] == ' $' ) {
1306+ // accept but do not require a matching sentinel
1307+ if (!(nextLine_[2 ] == ' &' || IsSpaceOrTab (&nextLine_[2 ]))) {
1308+ return nullptr ;
1309+ }
1310+ } else {
1311+ return nullptr ; // distinct directive
1312+ }
1313+ }
12841314 } else if (IsFixedFormCommentChar (col1)) {
12851315 int j{1 };
12861316 for (; j < 5 ; ++j) {
12871317 char ch{directiveSentinel_[j - 1 ]};
12881318 if (ch == ' \0 ' ) {
12891319 break ;
1290- }
1291- if (ch != ToLowerCaseLetter (nextLine_[j])) {
1320+ } else if (ch != ToLowerCaseLetter (nextLine_[j])) {
12921321 return nullptr ;
12931322 }
12941323 }
@@ -1297,13 +1326,15 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
12971326 return nullptr ;
12981327 }
12991328 }
1300- const char *col6{nextLine_ + 5 };
1301- if (*col6 != ' \n ' && *col6 != ' 0' && !IsSpaceOrTab (col6)) {
1302- if (mightNeedSpace && !IsSpace (nextLine_ + 6 )) {
1303- insertASpace_ = true ;
1304- }
1305- return nextLine_ + 6 ;
1329+ } else {
1330+ return nullptr ;
1331+ }
1332+ const char *col6{nextLine_ + 5 };
1333+ if (*col6 != ' \n ' && *col6 != ' 0' && !IsSpaceOrTab (col6)) {
1334+ if (mightNeedSpace && !IsSpace (nextLine_ + 6 )) {
1335+ insertASpace_ = true ;
13061336 }
1337+ return nextLine_ + 6 ;
13071338 }
13081339 } else {
13091340 // Normal case: not in a compiler directive.
@@ -1351,26 +1382,37 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
13511382 }
13521383 p = SkipWhiteSpaceIncludingEmptyMacros (p);
13531384 if (InCompilerDirective ()) {
1354- if (preprocessingOnly_ && directiveSentinel_[0 ] == ' $' &&
1355- directiveSentinel_[1 ] == ' \0 ' ) {
1356- // in -E mode, don't treat !$ as a continuation
1385+ if (directiveSentinel_[0 ] == ' $' && directiveSentinel_[1 ] == ' \0 ' ) {
1386+ if (preprocessingOnly_) {
1387+ // in -E mode, don't treat !$ as a continuation
1388+ return nullptr ;
1389+ } else if (p[0 ] == ' !' && p[1 ] == ' $' ) {
1390+ // accept but do not require a matching sentinel
1391+ if (!(p[2 ] == ' &' || IsSpaceOrTab (&p[2 ]))) {
1392+ return nullptr ; // not !$
1393+ }
1394+ p += 2 ;
1395+ }
13571396 } else if (*p++ == ' !' ) {
13581397 for (const char *s{directiveSentinel_}; *s != ' \0 ' ; ++p, ++s) {
13591398 if (*s != ToLowerCaseLetter (*p)) {
13601399 return nullptr ; // not the same directive class
13611400 }
13621401 }
1363- p = SkipWhiteSpace (p);
1364- if (*p == ' &' ) {
1365- if (!ampersand) {
1366- insertASpace_ = true ;
1367- }
1368- return p + 1 ;
1369- } else if (ampersand) {
1370- return p;
1402+ } else {
1403+ return nullptr ;
1404+ }
1405+ p = SkipWhiteSpace (p);
1406+ if (*p == ' &' ) {
1407+ if (!ampersand) {
1408+ insertASpace_ = true ;
13711409 }
1410+ return p + 1 ;
1411+ } else if (ampersand) {
1412+ return p;
1413+ } else {
1414+ return nullptr ;
13721415 }
1373- return nullptr ;
13741416 }
13751417 if (p[0 ] == ' !' && p[1 ] == ' $' && !preprocessingOnly_ &&
13761418 features_.IsEnabled (LanguageFeature::OpenMP)) {
@@ -1593,8 +1635,13 @@ Prescanner::IsCompilerDirectiveSentinel(const char *p) const {
15931635 if (int n{IsSpaceOrTab (p)};
15941636 n || !(IsLetter (*p) || *p == ' $' || *p == ' @' )) {
15951637 if (j > 0 ) {
1638+ if (j == 1 && sentinel[0 ] == ' $' && n == 0 && *p != ' &' ) {
1639+ // OpenMP conditional compilation line sentinels have to
1640+ // be immediately followed by a space or &, not a digit
1641+ // or anything else.
1642+ break ;
1643+ }
15961644 sentinel[j] = ' \0 ' ;
1597- p = SkipWhiteSpaceIncludingEmptyMacros (p + n);
15981645 if (*p != ' !' ) {
15991646 if (const char *sp{IsCompilerDirectiveSentinel (sentinel, j)}) {
16001647 return std::make_pair (sp, p);
0 commit comments