Skip to content

Commit 5d15f60

Browse files
authored
[flang][preprocessing] Mix preprocessing directives with free form li… (#96244)
…ne continuation Allow preprocessing directives to appear between a source line and its continuation, including conditional compilation directives (#if, #ifdef, &c.). Fixes #95476.
1 parent fc066ca commit 5d15f60

File tree

11 files changed

+83
-33
lines changed

11 files changed

+83
-33
lines changed

flang/include/flang/Parser/preprocessor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class Preprocessor {
8282
bool IsNameDefined(const CharBlock &);
8383
bool IsFunctionLikeDefinition(const CharBlock &);
8484
bool AnyDefinitions() const { return !definitions_.empty(); }
85+
bool InConditional() const { return !ifStack_.empty(); }
8586

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

flang/lib/Parser/prescan.cpp

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,15 @@ void Prescanner::Statement() {
105105
NextLine();
106106
return;
107107
case LineClassification::Kind::ConditionalCompilationDirective:
108-
case LineClassification::Kind::DefinitionDirective:
109-
case LineClassification::Kind::PreprocessorDirective:
108+
case LineClassification::Kind::IncludeDirective:
110109
preprocessor_.Directive(TokenizePreprocessorDirective(), *this);
110+
afterPreprocessingDirective_ = true;
111+
skipLeadingAmpersand_ |= !inFixedForm_;
111112
return;
112-
case LineClassification::Kind::IncludeDirective:
113+
case LineClassification::Kind::PreprocessorDirective:
114+
case LineClassification::Kind::DefinitionDirective:
113115
preprocessor_.Directive(TokenizePreprocessorDirective(), *this);
114-
afterIncludeDirective_ = true;
116+
// Don't set afterPreprocessingDirective_
115117
return;
116118
case LineClassification::Kind::CompilerDirective: {
117119
directiveSentinel_ = line.sentinel;
@@ -171,15 +173,17 @@ void Prescanner::Statement() {
171173
NextChar();
172174
}
173175
LabelField(tokens);
174-
} else if (skipLeadingAmpersand_) {
175-
skipLeadingAmpersand_ = false;
176-
const char *p{SkipWhiteSpace(at_)};
177-
if (p < limit_ && *p == '&') {
178-
column_ += ++p - at_;
179-
at_ = p;
180-
}
181176
} else {
182-
SkipSpaces();
177+
if (skipLeadingAmpersand_) {
178+
skipLeadingAmpersand_ = false;
179+
const char *p{SkipWhiteSpace(at_)};
180+
if (p < limit_ && *p == '&') {
181+
column_ += ++p - at_;
182+
at_ = p;
183+
}
184+
} else {
185+
SkipSpaces();
186+
}
183187
// Check for a leading identifier that might be a keyword macro
184188
// that will expand to anything indicating a non-source line, like
185189
// a comment marker or directive sentinel. If so, disable line
@@ -289,13 +293,14 @@ void Prescanner::CheckAndEmitLine(
289293
tokens.CheckBadFortranCharacters(
290294
messages_, *this, disableSourceContinuation_);
291295
// Parenthesis nesting check does not apply while any #include is
292-
// active, nor on the lines before and after a top-level #include.
296+
// active, nor on the lines before and after a top-level #include,
297+
// nor before or after conditional source.
293298
// Applications play shenanigans with line continuation before and
294-
// after #include'd subprogram argument lists.
299+
// after #include'd subprogram argument lists and conditional source.
295300
if (!isNestedInIncludeDirective_ && !omitNewline_ &&
296-
!afterIncludeDirective_ && tokens.BadlyNestedParentheses()) {
297-
if (inFixedForm_ && nextLine_ < limit_ &&
298-
IsPreprocessorDirectiveLine(nextLine_)) {
301+
!afterPreprocessingDirective_ && tokens.BadlyNestedParentheses() &&
302+
!preprocessor_.InConditional()) {
303+
if (nextLine_ < limit_ && IsPreprocessorDirectiveLine(nextLine_)) {
299304
// don't complain
300305
} else {
301306
tokens.CheckBadParentheses(messages_);
@@ -306,7 +311,7 @@ void Prescanner::CheckAndEmitLine(
306311
omitNewline_ = false;
307312
} else {
308313
cooked_.Put('\n', newlineProvenance);
309-
afterIncludeDirective_ = false;
314+
afterPreprocessingDirective_ = false;
310315
}
311316
}
312317

@@ -353,10 +358,11 @@ void Prescanner::LabelField(TokenSequence &token) {
353358
++column_;
354359
}
355360
if (badColumn && !preprocessor_.IsNameDefined(token.CurrentOpenToken())) {
356-
if (prescannerNesting_ > 0 && *badColumn == 6 &&
357-
cooked_.BufferedBytes() == firstCookedCharacterOffset_) {
358-
// This is the first source line in #included text or conditional
359-
// code under #if.
361+
if ((prescannerNesting_ > 0 && *badColumn == 6 &&
362+
cooked_.BufferedBytes() == firstCookedCharacterOffset_) ||
363+
afterPreprocessingDirective_) {
364+
// This is the first source line in #include'd text or conditional
365+
// code under #if, or the first source line after such.
360366
// If it turns out that the preprocessed text begins with a
361367
// fixed form continuation line, the newline at the end
362368
// of the latest source line beforehand will be deleted in
@@ -599,7 +605,7 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
599605
char previous{at_ <= start_ ? ' ' : at_[-1]};
600606
NextChar();
601607
SkipSpaces();
602-
if (*at_ == '\n') {
608+
if (*at_ == '\n' && !omitNewline_) {
603609
// Discard white space at the end of a line.
604610
} else if (!inPreprocessorDirective_ &&
605611
(previous == '(' || *at_ == '(' || *at_ == ')')) {
@@ -1069,6 +1075,17 @@ bool Prescanner::SkipCommentLine(bool afterAmpersand) {
10691075
return true;
10701076
} else if (inPreprocessorDirective_) {
10711077
return false;
1078+
} else if (afterAmpersand &&
1079+
(lineClass.kind ==
1080+
LineClassification::Kind::ConditionalCompilationDirective ||
1081+
lineClass.kind == LineClassification::Kind::DefinitionDirective ||
1082+
lineClass.kind == LineClassification::Kind::PreprocessorDirective ||
1083+
lineClass.kind == LineClassification::Kind::IncludeDirective ||
1084+
lineClass.kind == LineClassification::Kind::IncludeLine)) {
1085+
SkipToEndOfLine();
1086+
omitNewline_ = true;
1087+
skipLeadingAmpersand_ = true;
1088+
return false;
10721089
} else if (lineClass.kind ==
10731090
LineClassification::Kind::ConditionalCompilationDirective ||
10741091
lineClass.kind == LineClassification::Kind::PreprocessorDirective) {
@@ -1080,13 +1097,6 @@ bool Prescanner::SkipCommentLine(bool afterAmpersand) {
10801097
// continued line).
10811098
preprocessor_.Directive(TokenizePreprocessorDirective(), *this);
10821099
return true;
1083-
} else if (afterAmpersand &&
1084-
(lineClass.kind == LineClassification::Kind::IncludeDirective ||
1085-
lineClass.kind == LineClassification::Kind::IncludeLine)) {
1086-
SkipToEndOfLine();
1087-
omitNewline_ = true;
1088-
skipLeadingAmpersand_ = true;
1089-
return false;
10901100
} else {
10911101
return false;
10921102
}

flang/lib/Parser/prescan.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ class Prescanner {
214214
int prescannerNesting_{0};
215215
int continuationLines_{0};
216216
bool isPossibleMacroCall_{false};
217-
bool afterIncludeDirective_{false};
217+
bool afterPreprocessingDirective_{false};
218218
bool disableSourceContinuation_{false};
219219

220220
Provenance startProvenance_;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s
2+
! CHECK: subroutine test(ARG1, FA, FB, ARG2)
3+
! CHECK: end
4+
5+
subroutine test( &
6+
ARG1, &
7+
! test
8+
#ifndef SWAP
9+
#define ARG1 FA
10+
#define ARG2 FB
11+
#else
12+
#define ARG1 FB
13+
#define ARG2 FA
14+
#endif
15+
ARG1, ARG2, &
16+
! test
17+
#undef ARG1
18+
#undef ARG2
19+
&ARG2)
20+
! comment
21+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s
2+
! CHECK: call t(1 ,.false.)
3+
program main
4+
#include "inc-contin-1.h"
5+
$,.false.)
6+
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
call t(1
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s
2+
! CHECK: print *, 3.14159
3+
! CHECK: print *, 3. 14159
4+
program main
5+
#include "inc-contin-2a.h"
6+
&14159
7+
#include "inc-contin-2b.h"
8+
&14159
9+
end program main
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
print *, 3.&
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
print *, 3. &

flang/test/Preprocessing/include-args.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: call foo(3.14159)
2+
! CHECK: call foo(3.14159 )
33
call foo (&
44
#include "args.h"
55
)

flang/unittests/Frontend/FrontendActionTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ TEST_F(FrontendActionTest, PrintPreprocessedInput) {
143143
EXPECT_TRUE(success);
144144
EXPECT_TRUE(!outputFileBuffer.empty());
145145
EXPECT_TRUE(
146-
llvm::StringRef(outputFileBuffer.data()).starts_with("program b\n"));
146+
llvm::StringRef(outputFileBuffer.data()).starts_with(" program b\n"));
147147
}
148148

149149
TEST_F(FrontendActionTest, ParseSyntaxOnly) {

0 commit comments

Comments
 (0)