[flang-commits] [flang] [flang][preprocessing] Mix preprocessing directives with free form li… (PR #96244)
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Sat Jun 22 13:36:10 PDT 2024
https://github.com/klausler updated https://github.com/llvm/llvm-project/pull/96244
>From 5a56db1a9072f7e483a12a06c2821354ae70052e Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Thu, 20 Jun 2024 15:28:08 -0700
Subject: [PATCH] [flang][preprocessing] Mix preprocessing directives with free
form line continuation
Allow preprocessing directives to appear between a source line and
its continuation, including conditional compilation directives
(#if, #ifdef, &c.).
Fixes https://github.com/llvm/llvm-project/issues/95476.
---
flang/include/flang/Parser/preprocessor.h | 1 +
flang/lib/Parser/prescan.cpp | 68 +++++++++++--------
flang/lib/Parser/prescan.h | 2 +-
flang/test/Preprocessing/cond-contin.F90 | 21 ++++++
.../directive-contin-with-pp.F90 | 2 +-
flang/test/Preprocessing/inc-contin-1.F | 6 ++
flang/test/Preprocessing/inc-contin-1.h | 1 +
flang/test/Preprocessing/inc-contin-2.F90 | 6 ++
flang/test/Preprocessing/inc-contin-2.h | 1 +
.../unittests/Frontend/FrontendActionTest.cpp | 2 +-
10 files changed, 78 insertions(+), 32 deletions(-)
create mode 100644 flang/test/Preprocessing/cond-contin.F90
create mode 100644 flang/test/Preprocessing/inc-contin-1.F
create mode 100644 flang/test/Preprocessing/inc-contin-1.h
create mode 100644 flang/test/Preprocessing/inc-contin-2.F90
create mode 100644 flang/test/Preprocessing/inc-contin-2.h
diff --git a/flang/include/flang/Parser/preprocessor.h b/flang/include/flang/Parser/preprocessor.h
index c3076435be5f0..57690dd226f62 100644
--- a/flang/include/flang/Parser/preprocessor.h
+++ b/flang/include/flang/Parser/preprocessor.h
@@ -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
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index 2a6ecfbb0830e..d2599b685bb77 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -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;
@@ -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
@@ -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_);
@@ -306,7 +311,7 @@ void Prescanner::CheckAndEmitLine(
omitNewline_ = false;
} else {
cooked_.Put('\n', newlineProvenance);
- afterIncludeDirective_ = false;
+ afterPreprocessingDirective_ = false;
}
}
@@ -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
@@ -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) {
@@ -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;
}
diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h
index b6f6d2ca439ee..421ba97d324c9 100644
--- a/flang/lib/Parser/prescan.h
+++ b/flang/lib/Parser/prescan.h
@@ -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_;
diff --git a/flang/test/Preprocessing/cond-contin.F90 b/flang/test/Preprocessing/cond-contin.F90
new file mode 100644
index 0000000000000..8a75d93d508d5
--- /dev/null
+++ b/flang/test/Preprocessing/cond-contin.F90
@@ -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
diff --git a/flang/test/Preprocessing/directive-contin-with-pp.F90 b/flang/test/Preprocessing/directive-contin-with-pp.F90
index be8eb4d3c1cee..64f1dc43f72b4 100644
--- a/flang/test/Preprocessing/directive-contin-with-pp.F90
+++ b/flang/test/Preprocessing/directive-contin-with-pp.F90
@@ -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$&
diff --git a/flang/test/Preprocessing/inc-contin-1.F b/flang/test/Preprocessing/inc-contin-1.F
new file mode 100644
index 0000000000000..7a4e3a0cb0b59
--- /dev/null
+++ b/flang/test/Preprocessing/inc-contin-1.F
@@ -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
diff --git a/flang/test/Preprocessing/inc-contin-1.h b/flang/test/Preprocessing/inc-contin-1.h
new file mode 100644
index 0000000000000..d4b6461e75274
--- /dev/null
+++ b/flang/test/Preprocessing/inc-contin-1.h
@@ -0,0 +1 @@
+ call t(1
diff --git a/flang/test/Preprocessing/inc-contin-2.F90 b/flang/test/Preprocessing/inc-contin-2.F90
new file mode 100644
index 0000000000000..63e9c05791589
--- /dev/null
+++ b/flang/test/Preprocessing/inc-contin-2.F90
@@ -0,0 +1,6 @@
+! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s
+! CHECK: print *, 3.14159
+ program main
+#include "inc-contin-2.h"
+ &14159
+ end program main
diff --git a/flang/test/Preprocessing/inc-contin-2.h b/flang/test/Preprocessing/inc-contin-2.h
new file mode 100644
index 0000000000000..b84a464af86e3
--- /dev/null
+++ b/flang/test/Preprocessing/inc-contin-2.h
@@ -0,0 +1 @@
+print *, 3. &
diff --git a/flang/unittests/Frontend/FrontendActionTest.cpp b/flang/unittests/Frontend/FrontendActionTest.cpp
index 123f428cc8b40..bdf5a23fdbf6a 100644
--- a/flang/unittests/Frontend/FrontendActionTest.cpp
+++ b/flang/unittests/Frontend/FrontendActionTest.cpp
@@ -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) {
More information about the flang-commits
mailing list