Skip to content

[flang][preprocessing] Mix preprocessing directives with free form li… #96244

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 24, 2024
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
1 change: 1 addition & 0 deletions flang/include/flang/Parser/preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class Preprocessor {
bool IsNameDefined(const CharBlock &);
bool IsFunctionLikeDefinition(const CharBlock &);
bool AnyDefinitions() const { return !definitions_.empty(); }
bool InConditional() const { return !ifStack_.empty(); }

// When called with partialFunctionLikeMacro not null, MacroReplacement()
// and ReplaceMacros() handle an unclosed function-like macro reference
Expand Down
70 changes: 40 additions & 30 deletions flang/lib/Parser/prescan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,15 @@ void Prescanner::Statement() {
NextLine();
return;
case LineClassification::Kind::ConditionalCompilationDirective:
case LineClassification::Kind::DefinitionDirective:
case LineClassification::Kind::PreprocessorDirective:
case LineClassification::Kind::IncludeDirective:
preprocessor_.Directive(TokenizePreprocessorDirective(), *this);
afterPreprocessingDirective_ = true;
skipLeadingAmpersand_ |= !inFixedForm_;
return;
case LineClassification::Kind::IncludeDirective:
case LineClassification::Kind::PreprocessorDirective:
case LineClassification::Kind::DefinitionDirective:
preprocessor_.Directive(TokenizePreprocessorDirective(), *this);
afterIncludeDirective_ = true;
// Don't set afterPreprocessingDirective_
return;
case LineClassification::Kind::CompilerDirective: {
directiveSentinel_ = line.sentinel;
Expand Down Expand Up @@ -171,15 +173,17 @@ void Prescanner::Statement() {
NextChar();
}
LabelField(tokens);
} else if (skipLeadingAmpersand_) {
skipLeadingAmpersand_ = false;
const char *p{SkipWhiteSpace(at_)};
if (p < limit_ && *p == '&') {
column_ += ++p - at_;
at_ = p;
}
} else {
SkipSpaces();
if (skipLeadingAmpersand_) {
skipLeadingAmpersand_ = false;
const char *p{SkipWhiteSpace(at_)};
if (p < limit_ && *p == '&') {
column_ += ++p - at_;
at_ = p;
}
} else {
SkipSpaces();
}
// Check for a leading identifier that might be a keyword macro
// that will expand to anything indicating a non-source line, like
// a comment marker or directive sentinel. If so, disable line
Expand Down Expand Up @@ -289,13 +293,14 @@ void Prescanner::CheckAndEmitLine(
tokens.CheckBadFortranCharacters(
messages_, *this, disableSourceContinuation_);
// Parenthesis nesting check does not apply while any #include is
// active, nor on the lines before and after a top-level #include.
// active, nor on the lines before and after a top-level #include,
// nor before or after conditional source.
// Applications play shenanigans with line continuation before and
// after #include'd subprogram argument lists.
// after #include'd subprogram argument lists and conditional source.
if (!isNestedInIncludeDirective_ && !omitNewline_ &&
!afterIncludeDirective_ && tokens.BadlyNestedParentheses()) {
if (inFixedForm_ && nextLine_ < limit_ &&
IsPreprocessorDirectiveLine(nextLine_)) {
!afterPreprocessingDirective_ && tokens.BadlyNestedParentheses() &&
!preprocessor_.InConditional()) {
if (nextLine_ < limit_ && IsPreprocessorDirectiveLine(nextLine_)) {
// don't complain
} else {
tokens.CheckBadParentheses(messages_);
Expand All @@ -306,7 +311,7 @@ void Prescanner::CheckAndEmitLine(
omitNewline_ = false;
} else {
cooked_.Put('\n', newlineProvenance);
afterIncludeDirective_ = false;
afterPreprocessingDirective_ = false;
}
}

Expand Down Expand Up @@ -353,10 +358,11 @@ void Prescanner::LabelField(TokenSequence &token) {
++column_;
}
if (badColumn && !preprocessor_.IsNameDefined(token.CurrentOpenToken())) {
if (prescannerNesting_ > 0 && *badColumn == 6 &&
cooked_.BufferedBytes() == firstCookedCharacterOffset_) {
// This is the first source line in #included text or conditional
// code under #if.
if ((prescannerNesting_ > 0 && *badColumn == 6 &&
cooked_.BufferedBytes() == firstCookedCharacterOffset_) ||
afterPreprocessingDirective_) {
// This is the first source line in #include'd text or conditional
// code under #if, or the first source line after such.
// If it turns out that the preprocessed text begins with a
// fixed form continuation line, the newline at the end
// of the latest source line beforehand will be deleted in
Expand Down Expand Up @@ -599,7 +605,7 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
char previous{at_ <= start_ ? ' ' : at_[-1]};
NextChar();
SkipSpaces();
if (*at_ == '\n') {
if (*at_ == '\n' && !omitNewline_) {
// Discard white space at the end of a line.
} else if (!inPreprocessorDirective_ &&
(previous == '(' || *at_ == '(' || *at_ == ')')) {
Expand Down Expand Up @@ -1069,6 +1075,17 @@ bool Prescanner::SkipCommentLine(bool afterAmpersand) {
return true;
} else if (inPreprocessorDirective_) {
return false;
} else if (afterAmpersand &&
(lineClass.kind ==
LineClassification::Kind::ConditionalCompilationDirective ||
lineClass.kind == LineClassification::Kind::DefinitionDirective ||
lineClass.kind == LineClassification::Kind::PreprocessorDirective ||
lineClass.kind == LineClassification::Kind::IncludeDirective ||
lineClass.kind == LineClassification::Kind::IncludeLine)) {
SkipToEndOfLine();
omitNewline_ = true;
skipLeadingAmpersand_ = true;
return false;
} else if (lineClass.kind ==
LineClassification::Kind::ConditionalCompilationDirective ||
lineClass.kind == LineClassification::Kind::PreprocessorDirective) {
Expand All @@ -1080,13 +1097,6 @@ bool Prescanner::SkipCommentLine(bool afterAmpersand) {
// continued line).
preprocessor_.Directive(TokenizePreprocessorDirective(), *this);
return true;
} else if (afterAmpersand &&
(lineClass.kind == LineClassification::Kind::IncludeDirective ||
lineClass.kind == LineClassification::Kind::IncludeLine)) {
SkipToEndOfLine();
omitNewline_ = true;
skipLeadingAmpersand_ = true;
return false;
} else {
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Parser/prescan.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class Prescanner {
int prescannerNesting_{0};
int continuationLines_{0};
bool isPossibleMacroCall_{false};
bool afterIncludeDirective_{false};
bool afterPreprocessingDirective_{false};
bool disableSourceContinuation_{false};

Provenance startProvenance_;
Expand Down
21 changes: 21 additions & 0 deletions flang/test/Preprocessing/cond-contin.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s
! CHECK: subroutine test(ARG1, FA, FB, ARG2)
! CHECK: end

subroutine test( &
ARG1, &
! test
#ifndef SWAP
#define ARG1 FA
#define ARG2 FB
#else
#define ARG1 FB
#define ARG2 FA
#endif
ARG1, ARG2, &
! test
#undef ARG1
#undef ARG2
&ARG2)
! comment
end
2 changes: 1 addition & 1 deletion flang/test/Preprocessing/directive-contin-with-pp.F90
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
! RUN: %flang -fc1 -fdebug-unparse -fopenmp %s 2>&1 | FileCheck %s
! RUN: %flang_fc1 -fdebug-unparse -fopenmp %s 2>&1 | FileCheck %s

#define DIR_START !dir$
#define DIR_CONT !dir$&
Expand Down
6 changes: 6 additions & 0 deletions flang/test/Preprocessing/inc-contin-1.F
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s
! CHECK: call t(1 ,.false.)
program main
#include "inc-contin-1.h"
$,.false.)
end
1 change: 1 addition & 0 deletions flang/test/Preprocessing/inc-contin-1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
call t(1
9 changes: 9 additions & 0 deletions flang/test/Preprocessing/inc-contin-2.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s
! CHECK: print *, 3.14159
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is improper result, since test has whitespace between . and & in flang/test/Preprocessing/inc-contin-2.h.
It should be:

! CHECK: print *, 3. 14159

And then, it must fail since whitespaces are not allowed in constants as it was in Fortran-77.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an example:
https://godbolt.org/z/Gx1brb7h6

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks; patch has been updated to test cases with and without the space.

! CHECK: print *, 3. 14159
program main
#include "inc-contin-2a.h"
&14159
#include "inc-contin-2b.h"
&14159
end program main
1 change: 1 addition & 0 deletions flang/test/Preprocessing/inc-contin-2a.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print *, 3.&
1 change: 1 addition & 0 deletions flang/test/Preprocessing/inc-contin-2b.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print *, 3. &
2 changes: 1 addition & 1 deletion flang/test/Preprocessing/include-args.F90
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
! RUN: %flang -E %s 2>&1 | FileCheck %s
! CHECK: call foo(3.14159)
! CHECK: call foo(3.14159 )
call foo (&
#include "args.h"
)
Expand Down
2 changes: 1 addition & 1 deletion flang/unittests/Frontend/FrontendActionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ TEST_F(FrontendActionTest, PrintPreprocessedInput) {
EXPECT_TRUE(success);
EXPECT_TRUE(!outputFileBuffer.empty());
EXPECT_TRUE(
llvm::StringRef(outputFileBuffer.data()).starts_with("program b\n"));
llvm::StringRef(outputFileBuffer.data()).starts_with(" program b\n"));
}

TEST_F(FrontendActionTest, ParseSyntaxOnly) {
Expand Down
Loading