Skip to content

Commit dd3214d

Browse files
authored
[flang] Fix handling of identifier in column 1 of free form continuat… (#146430)
…ion line An obsolete flag ("insertASpace_") is being used to signal some cases in the prescanner's implementation of continuation lines when a token should be broken when it straddles a line break. It turns out that it's sufficient to simply note these cases without ever actually inserting a space, so don't do that (fixing the motivating bug). This leaves some variables with obsolete names, so change them as well. This patch handles the third of the three bugs reported in #146362 .
1 parent 0b98b27 commit dd3214d

File tree

7 files changed

+41
-27
lines changed

7 files changed

+41
-27
lines changed

flang/lib/Parser/prescan.cpp

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -593,13 +593,13 @@ bool Prescanner::SkipToNextSignificantCharacter() {
593593
return false;
594594
} else {
595595
auto anyContinuationLine{false};
596-
bool mightNeedSpace{false};
596+
bool atNewline{false};
597597
if (MustSkipToEndOfLine()) {
598598
SkipToEndOfLine();
599599
} else {
600-
mightNeedSpace = *at_ == '\n';
600+
atNewline = *at_ == '\n';
601601
}
602-
for (; Continuation(mightNeedSpace); mightNeedSpace = false) {
602+
for (; Continuation(atNewline); atNewline = false) {
603603
anyContinuationLine = true;
604604
++continuationLines_;
605605
if (MustSkipToEndOfLine()) {
@@ -641,7 +641,7 @@ void Prescanner::SkipSpaces() {
641641
while (IsSpaceOrTab(at_)) {
642642
NextChar();
643643
}
644-
insertASpace_ = false;
644+
brokenToken_ = false;
645645
}
646646

647647
const char *Prescanner::SkipWhiteSpace(const char *p) {
@@ -745,10 +745,7 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
745745
}
746746
}
747747
}
748-
if (insertASpace_) {
749-
tokens.PutNextTokenChar(' ', spaceProvenance_);
750-
insertASpace_ = false;
751-
}
748+
brokenToken_ = false;
752749
if (*at_ == '\n') {
753750
return false;
754751
}
@@ -808,7 +805,7 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
808805
bool anyDefined{false};
809806
bool hadContinuation{false};
810807
// Subtlety: When an identifier is split across continuation lines,
811-
// its parts are kept as distinct pp-tokens if that macro replacement
808+
// its parts are kept as distinct pp-tokens if macro replacement
812809
// should operate on them independently. This trick accommodates the
813810
// historic practice of using line continuation for token pasting after
814811
// replacement.
@@ -822,6 +819,9 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
822819
++at_, ++column_;
823820
hadContinuation = SkipToNextSignificantCharacter();
824821
if (hadContinuation && IsLegalIdentifierStart(*at_)) {
822+
if (brokenToken_) {
823+
break;
824+
}
825825
// Continued identifier
826826
tokens.CloseToken();
827827
++parts;
@@ -1348,7 +1348,7 @@ bool Prescanner::SkipCommentLine(bool afterAmpersand) {
13481348
return false;
13491349
}
13501350

1351-
const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
1351+
const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
13521352
if (IsAtEnd()) {
13531353
return nullptr;
13541354
}
@@ -1381,8 +1381,8 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
13811381
}
13821382
const char *col6{nextLine_ + 5};
13831383
if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
1384-
if (mightNeedSpace && !IsSpace(nextLine_ + 6)) {
1385-
insertASpace_ = true;
1384+
if (atNewline && !IsSpace(nextLine_ + 6)) {
1385+
brokenToken_ = true;
13861386
}
13871387
return nextLine_ + 6;
13881388
}
@@ -1395,7 +1395,9 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
13951395
nextLine_[4] == ' ' && IsCompilerDirectiveSentinel(&nextLine_[1], 1)) {
13961396
if (const char *col6{nextLine_ + 5};
13971397
*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
1398-
insertASpace_ |= mightNeedSpace && !IsSpace(nextLine_ + 6);
1398+
if (atNewline && !IsSpace(nextLine_ + 6)) {
1399+
brokenToken_ = true;
1400+
}
13991401
return nextLine_ + 6;
14001402
} else {
14011403
return nullptr;
@@ -1464,7 +1466,7 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
14641466
p = SkipWhiteSpace(p);
14651467
if (*p == '&') {
14661468
if (!ampersand) {
1467-
insertASpace_ = true;
1469+
brokenToken_ = true;
14681470
}
14691471
return p + 1;
14701472
} else if (ampersand) {
@@ -1494,22 +1496,22 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
14941496
} else if (p > lineStart && IsSpaceOrTab(p - 1)) {
14951497
--p;
14961498
} else {
1497-
insertASpace_ = true;
1499+
brokenToken_ = true;
14981500
}
14991501
return p;
15001502
} else {
15011503
return nullptr;
15021504
}
15031505
}
15041506

1505-
bool Prescanner::FixedFormContinuation(bool mightNeedSpace) {
1507+
bool Prescanner::FixedFormContinuation(bool atNewline) {
15061508
// N.B. We accept '&' as a continuation indicator in fixed form, too,
15071509
// but not in a character literal.
15081510
if (*at_ == '&' && inCharLiteral_) {
15091511
return false;
15101512
}
15111513
do {
1512-
if (const char *cont{FixedFormContinuationLine(mightNeedSpace)}) {
1514+
if (const char *cont{FixedFormContinuationLine(atNewline)}) {
15131515
BeginSourceLine(cont);
15141516
column_ = 7;
15151517
NextLine();

flang/lib/Parser/prescan.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,10 @@ class Prescanner {
203203
std::optional<std::size_t> IsIncludeLine(const char *) const;
204204
void FortranInclude(const char *quote);
205205
const char *IsPreprocessorDirectiveLine(const char *) const;
206-
const char *FixedFormContinuationLine(bool mightNeedSpace);
206+
const char *FixedFormContinuationLine(bool atNewline);
207207
const char *FreeFormContinuationLine(bool ampersand);
208208
bool IsImplicitContinuation() const;
209-
bool FixedFormContinuation(bool mightNeedSpace);
209+
bool FixedFormContinuation(bool atNewline);
210210
bool FreeFormContinuation();
211211
bool Continuation(bool mightNeedFixedFormSpace);
212212
std::optional<LineClassification> IsFixedFormCompilerDirectiveLine(
@@ -256,10 +256,15 @@ class Prescanner {
256256
bool continuationInCharLiteral_{false};
257257
bool inPreprocessorDirective_{false};
258258

259-
// In some edge cases of compiler directive continuation lines, it
260-
// is necessary to treat the line break as a space character by
261-
// setting this flag, which is cleared by EmitChar().
262-
bool insertASpace_{false};
259+
// True after processing a continuation that can't be allowed
260+
// to appear in the middle of an identifier token, but is fixed form,
261+
// or is free form and doesn't have a space character handy to use as
262+
// a separator when:
263+
// a) (standard) doesn't begin with a leading '&' on the continuation
264+
// line, but has a non-blank in column 1, or
265+
// b) (extension) does have a leading '&', but didn't have one
266+
// on the continued line.
267+
bool brokenToken_{false};
263268

264269
// When a free form continuation marker (&) appears at the end of a line
265270
// before a INCLUDE or #include, we delete it and omit the newline, so

flang/test/Preprocessing/bug1077.F90

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
!RUN: %flang -E %s 2>&1 | FileCheck %s
2+
!CHECK: print *,((1)+(2)),4
3+
#define foo(x,y) ((x)+(y))
4+
print *,&
5+
foo(1,2)&
6+
,4
7+
end

flang/test/Preprocessing/pp111.F90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
! RUN: %flang -E %s 2>&1 | FileCheck %s
2-
! CHECK: res = IFLM (666)
2+
! CHECK: res = IFLM(666)
33
! FLM call name split across continuation, no leading &, with & ! comment
44
integer function IFLM(x)
55
integer :: x

flang/test/Preprocessing/pp112.F90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
! RUN: %flang -E %s 2>&1 | FileCheck %s
2-
! CHECK: res = IFLM (666)
2+
! CHECK: res = IFLM(666)
33
! ditto, but without & ! comment
44
integer function IFLM(x)
55
integer :: x

flang/test/Preprocessing/pp115.F90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
! RUN: %flang -E %s 2>&1 | FileCheck %s
2-
! CHECK: res = IFLM (666)
2+
! CHECK: res = ((666)+111)
33
! ditto, with & ! comment, no leading &
44
integer function IFLM(x)
55
integer :: x

flang/test/Preprocessing/pp116.F90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
! RUN: %flang -E %s 2>&1 | FileCheck %s
2-
! CHECK: res = IFLM (666)
2+
! CHECK: res = ((666)+111)
33
! FLM call split between name and (, no leading &
44
integer function IFLM(x)
55
integer :: x

0 commit comments

Comments
 (0)