@@ -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);
0 commit comments