diff options
author | Peter Klausler <35819229+klausler@users.noreply.github.com> | 2024-06-24 10:18:50 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-24 10:18:50 -0700 |
commit | 5d15f606da4cb4346465956d935a2842f8e86200 (patch) | |
tree | 6b2eb0edaad38b971632dd4e56fc0fdc42665086 | |
parent | fc066ca1c32b4aef549f3e371dc70589804aba0f (diff) | |
download | llvm-5d15f606da4cb4346465956d935a2842f8e86200.zip llvm-5d15f606da4cb4346465956d935a2842f8e86200.tar.gz llvm-5d15f606da4cb4346465956d935a2842f8e86200.tar.bz2 |
[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 https://github.com/llvm/llvm-project/issues/95476.
-rw-r--r-- | flang/include/flang/Parser/preprocessor.h | 1 | ||||
-rw-r--r-- | flang/lib/Parser/prescan.cpp | 70 | ||||
-rw-r--r-- | flang/lib/Parser/prescan.h | 2 | ||||
-rw-r--r-- | flang/test/Preprocessing/cond-contin.F90 | 21 | ||||
-rw-r--r-- | flang/test/Preprocessing/inc-contin-1.F | 6 | ||||
-rw-r--r-- | flang/test/Preprocessing/inc-contin-1.h | 1 | ||||
-rw-r--r-- | flang/test/Preprocessing/inc-contin-2.F90 | 9 | ||||
-rw-r--r-- | flang/test/Preprocessing/inc-contin-2a.h | 1 | ||||
-rw-r--r-- | flang/test/Preprocessing/inc-contin-2b.h | 1 | ||||
-rw-r--r-- | flang/test/Preprocessing/include-args.F90 | 2 | ||||
-rw-r--r-- | flang/unittests/Frontend/FrontendActionTest.cpp | 2 |
11 files changed, 83 insertions, 33 deletions
diff --git a/flang/include/flang/Parser/preprocessor.h b/flang/include/flang/Parser/preprocessor.h index c307643..57690dd 100644 --- a/flang/include/flang/Parser/preprocessor.h +++ b/flang/include/flang/Parser/preprocessor.h @@ -82,6 +82,7 @@ public: 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 2a6ecfb..42aa829 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 @@ -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_ == ')')) { @@ -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 b6f6d2c..421ba97 100644 --- a/flang/lib/Parser/prescan.h +++ b/flang/lib/Parser/prescan.h @@ -214,7 +214,7 @@ private: 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 0000000..9221e34 --- /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/inc-contin-1.F b/flang/test/Preprocessing/inc-contin-1.F new file mode 100644 index 0000000..7a4e3a0 --- /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 0000000..d4b6461 --- /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 0000000..3386ee0 --- /dev/null +++ b/flang/test/Preprocessing/inc-contin-2.F90 @@ -0,0 +1,9 @@ +! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s +! CHECK: print *, 3.14159 +! CHECK: print *, 3. 14159 + program main +#include "inc-contin-2a.h" + &14159 +#include "inc-contin-2b.h" + &14159 + end program main diff --git a/flang/test/Preprocessing/inc-contin-2a.h b/flang/test/Preprocessing/inc-contin-2a.h new file mode 100644 index 0000000..24a4fa4 --- /dev/null +++ b/flang/test/Preprocessing/inc-contin-2a.h @@ -0,0 +1 @@ +print *, 3.& diff --git a/flang/test/Preprocessing/inc-contin-2b.h b/flang/test/Preprocessing/inc-contin-2b.h new file mode 100644 index 0000000..b84a464 --- /dev/null +++ b/flang/test/Preprocessing/inc-contin-2b.h @@ -0,0 +1 @@ +print *, 3. & diff --git a/flang/test/Preprocessing/include-args.F90 b/flang/test/Preprocessing/include-args.F90 index 011e4db..7c521db 100644 --- a/flang/test/Preprocessing/include-args.F90 +++ b/flang/test/Preprocessing/include-args.F90 @@ -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" ) diff --git a/flang/unittests/Frontend/FrontendActionTest.cpp b/flang/unittests/Frontend/FrontendActionTest.cpp index 123f428..bdf5a23 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) { |