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..42aa829e0ed5b 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 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..9221e34e013f4 --- /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..3386ee0dfcddc --- /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 0000000000000..24a4fa4830fa3 --- /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 0000000000000..b84a464af86e3 --- /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 011e4dba13e73..7c521db666ff9 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 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) {