Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions flang/lib/Parser/prescan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,13 +593,13 @@ bool Prescanner::SkipToNextSignificantCharacter() {
return false;
} else {
auto anyContinuationLine{false};
bool mightNeedSpace{false};
bool atNewline{false};
if (MustSkipToEndOfLine()) {
SkipToEndOfLine();
} else {
mightNeedSpace = *at_ == '\n';
atNewline = *at_ == '\n';
}
for (; Continuation(mightNeedSpace); mightNeedSpace = false) {
for (; Continuation(atNewline); atNewline = false) {
anyContinuationLine = true;
++continuationLines_;
if (MustSkipToEndOfLine()) {
Expand Down Expand Up @@ -641,7 +641,7 @@ void Prescanner::SkipSpaces() {
while (IsSpaceOrTab(at_)) {
NextChar();
}
insertASpace_ = false;
brokenToken_ = false;
}

const char *Prescanner::SkipWhiteSpace(const char *p) {
Expand Down Expand Up @@ -745,10 +745,7 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
}
}
}
if (insertASpace_) {
tokens.PutNextTokenChar(' ', spaceProvenance_);
insertASpace_ = false;
}
brokenToken_ = false;
if (*at_ == '\n') {
return false;
}
Expand Down Expand Up @@ -808,7 +805,7 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
bool anyDefined{false};
bool hadContinuation{false};
// Subtlety: When an identifier is split across continuation lines,
// its parts are kept as distinct pp-tokens if that macro replacement
// its parts are kept as distinct pp-tokens if macro replacement
// should operate on them independently. This trick accommodates the
// historic practice of using line continuation for token pasting after
// replacement.
Expand All @@ -822,6 +819,9 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
++at_, ++column_;
hadContinuation = SkipToNextSignificantCharacter();
if (hadContinuation && IsLegalIdentifierStart(*at_)) {
if (brokenToken_) {
break;
}
// Continued identifier
tokens.CloseToken();
++parts;
Expand Down Expand Up @@ -1348,7 +1348,7 @@ bool Prescanner::SkipCommentLine(bool afterAmpersand) {
return false;
}

const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
const char *Prescanner::FixedFormContinuationLine(bool atNewline) {
if (IsAtEnd()) {
return nullptr;
}
Expand Down Expand Up @@ -1381,8 +1381,8 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
}
const char *col6{nextLine_ + 5};
if (*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
if (mightNeedSpace && !IsSpace(nextLine_ + 6)) {
insertASpace_ = true;
if (atNewline && !IsSpace(nextLine_ + 6)) {
brokenToken_ = true;
}
return nextLine_ + 6;
}
Expand All @@ -1395,7 +1395,9 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
nextLine_[4] == ' ' && IsCompilerDirectiveSentinel(&nextLine_[1], 1)) {
if (const char *col6{nextLine_ + 5};
*col6 != '\n' && *col6 != '0' && !IsSpaceOrTab(col6)) {
insertASpace_ |= mightNeedSpace && !IsSpace(nextLine_ + 6);
if (atNewline && !IsSpace(nextLine_ + 6)) {
brokenToken_ = true;
}
return nextLine_ + 6;
} else {
return nullptr;
Expand Down Expand Up @@ -1464,7 +1466,7 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
p = SkipWhiteSpace(p);
if (*p == '&') {
if (!ampersand) {
insertASpace_ = true;
brokenToken_ = true;
}
return p + 1;
} else if (ampersand) {
Expand Down Expand Up @@ -1494,22 +1496,22 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
} else if (p > lineStart && IsSpaceOrTab(p - 1)) {
--p;
} else {
insertASpace_ = true;
brokenToken_ = true;
}
return p;
} else {
return nullptr;
}
}

bool Prescanner::FixedFormContinuation(bool mightNeedSpace) {
bool Prescanner::FixedFormContinuation(bool atNewline) {
// N.B. We accept '&' as a continuation indicator in fixed form, too,
// but not in a character literal.
if (*at_ == '&' && inCharLiteral_) {
return false;
}
do {
if (const char *cont{FixedFormContinuationLine(mightNeedSpace)}) {
if (const char *cont{FixedFormContinuationLine(atNewline)}) {
BeginSourceLine(cont);
column_ = 7;
NextLine();
Expand Down
17 changes: 11 additions & 6 deletions flang/lib/Parser/prescan.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,10 @@ class Prescanner {
std::optional<std::size_t> IsIncludeLine(const char *) const;
void FortranInclude(const char *quote);
const char *IsPreprocessorDirectiveLine(const char *) const;
const char *FixedFormContinuationLine(bool mightNeedSpace);
const char *FixedFormContinuationLine(bool atNewline);
const char *FreeFormContinuationLine(bool ampersand);
bool IsImplicitContinuation() const;
bool FixedFormContinuation(bool mightNeedSpace);
bool FixedFormContinuation(bool atNewline);
bool FreeFormContinuation();
bool Continuation(bool mightNeedFixedFormSpace);
std::optional<LineClassification> IsFixedFormCompilerDirectiveLine(
Expand Down Expand Up @@ -256,10 +256,15 @@ class Prescanner {
bool continuationInCharLiteral_{false};
bool inPreprocessorDirective_{false};

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

// When a free form continuation marker (&) appears at the end of a line
// before a INCLUDE or #include, we delete it and omit the newline, so
Expand Down
7 changes: 7 additions & 0 deletions flang/test/Preprocessing/bug1077.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
!RUN: %flang -E %s 2>&1 | FileCheck %s
!CHECK: print *,((1)+(2)),4
#define foo(x,y) ((x)+(y))
print *,&
foo(1,2)&
,4
end
2 changes: 1 addition & 1 deletion flang/test/Preprocessing/pp111.F90
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
! RUN: %flang -E %s 2>&1 | FileCheck %s
! CHECK: res = IFLM (666)
! CHECK: res = IFLM(666)
! FLM call name split across continuation, no leading &, with & ! comment
integer function IFLM(x)
integer :: x
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Preprocessing/pp112.F90
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
! RUN: %flang -E %s 2>&1 | FileCheck %s
! CHECK: res = IFLM (666)
! CHECK: res = IFLM(666)
! ditto, but without & ! comment
integer function IFLM(x)
integer :: x
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Preprocessing/pp115.F90
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
! RUN: %flang -E %s 2>&1 | FileCheck %s
! CHECK: res = IFLM (666)
! CHECK: res = ((666)+111)
! ditto, with & ! comment, no leading &
integer function IFLM(x)
integer :: x
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Preprocessing/pp116.F90
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
! RUN: %flang -E %s 2>&1 | FileCheck %s
! CHECK: res = IFLM (666)
! CHECK: res = ((666)+111)
! FLM call split between name and (, no leading &
integer function IFLM(x)
integer :: x
Expand Down