Skip to content

Commit 8b512e5

Browse files
authored
[flang][preprocessor] Support \ as line continuation (#89970)
When prescanning a Fortran source file with preprocessing enabled in free source form, interpret a line-ending backslash as a source line continuation marker as a C preprocessor would. This usage isn't completely portable, but it is supported by GNU Fortran and appears in the source for FPM package manager.
1 parent fa465b4 commit 8b512e5

File tree

5 files changed

+26
-5
lines changed

5 files changed

+26
-5
lines changed

flang/docs/Preprocessing.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ local:
9393
* If a `#define` or `#undef` directive appears among continuation
9494
lines, it may or may not affect text in the continued statement that
9595
appeared before the directive.
96+
* A backslash at the end of a free form source line is a continuation
97+
marker, with no space skipping or special handling of a leading `&`
98+
on the next line.
9699

97100
## Behavior that few compilers properly support (or none), but should:
98101

flang/include/flang/Parser/preprocessor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class Preprocessor {
8181
void Undefine(std::string macro);
8282
bool IsNameDefined(const CharBlock &);
8383
bool IsFunctionLikeDefinition(const CharBlock &);
84+
bool AnyDefinitions() const { return !definitions_.empty(); }
8485

8586
// When called with partialFunctionLikeMacro not null, MacroReplacement()
8687
// and ReplaceMacros() handle an unclosed function-like macro reference

flang/lib/Parser/prescan.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,18 @@ Prescanner::Prescanner(Messages &messages, CookedSource &cooked,
2929
Preprocessor &preprocessor, common::LanguageFeatureControl lfc)
3030
: messages_{messages}, cooked_{cooked}, preprocessor_{preprocessor},
3131
allSources_{preprocessor_.allSources()}, features_{lfc},
32+
backslashFreeFormContinuation_{preprocessor.AnyDefinitions()},
3233
encoding_{allSources_.encoding()} {}
3334

3435
Prescanner::Prescanner(const Prescanner &that)
3536
: messages_{that.messages_}, cooked_{that.cooked_},
3637
preprocessor_{that.preprocessor_}, allSources_{that.allSources_},
37-
features_{that.features_}, inFixedForm_{that.inFixedForm_},
38+
features_{that.features_},
39+
backslashFreeFormContinuation_{that.backslashFreeFormContinuation_},
40+
inFixedForm_{that.inFixedForm_},
3841
fixedFormColumnLimit_{that.fixedFormColumnLimit_},
39-
encoding_{that.encoding_}, prescannerNesting_{that.prescannerNesting_ +
40-
1},
42+
encoding_{that.encoding_},
43+
prescannerNesting_{that.prescannerNesting_ + 1},
4144
skipLeadingAmpersand_{that.skipLeadingAmpersand_},
4245
compilerDirectiveBloomFilter_{that.compilerDirectiveBloomFilter_},
4346
compilerDirectiveSentinels_{that.compilerDirectiveSentinels_} {}
@@ -1226,9 +1229,14 @@ bool Prescanner::Continuation(bool mightNeedFixedFormSpace) {
12261229
} else {
12271230
return FreeFormContinuation();
12281231
}
1229-
} else {
1230-
return false;
1232+
} else if (*at_ == '\\' && at_ + 2 == nextLine_ &&
1233+
backslashFreeFormContinuation_ && !inFixedForm_ && nextLine_ < limit_) {
1234+
// cpp-like handling of \ at end of a free form source line
1235+
BeginSourceLine(nextLine_);
1236+
NextLine();
1237+
return true;
12311238
}
1239+
return false;
12321240
}
12331241

12341242
std::optional<Prescanner::LineClassification>

flang/lib/Parser/prescan.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ class Prescanner {
197197
Preprocessor &preprocessor_;
198198
AllSources &allSources_;
199199
common::LanguageFeatureControl features_;
200+
bool backslashFreeFormContinuation_{false};
200201
bool inFixedForm_{false};
201202
int fixedFormColumnLimit_{72};
202203
Encoding encoding_{Encoding::UTF_8};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
! RUN: %flang -E %s | FileCheck %s
2+
print *, \
3+
"hello, \
4+
world"
5+
end
6+
!CHECK: print *, "hello, world"
7+
!CHECK: end
8+

0 commit comments

Comments
 (0)