diff --git a/flang/lib/Parser/parsing.cpp b/flang/lib/Parser/parsing.cpp --- a/flang/lib/Parser/parsing.cpp +++ b/flang/lib/Parser/parsing.cpp @@ -103,7 +103,13 @@ int column{1}; bool inDirective{false}; bool inContinuation{false}; + bool lineWasBlankBefore{true}; const AllSources &allSources{allCooked().allSources()}; + // All directives that flang support are known to have a length of 3 chars + constexpr int directiveNameLength{3}; + // We need to know the current directive in order to provide correct + // continuation for the directive + std::string directive; for (const char &atChar : cooked().AsCharBlock()) { char ch{atChar}; if (ch == '\n') { @@ -111,15 +117,36 @@ column = 1; inDirective = false; inContinuation = false; + lineWasBlankBefore = true; ++sourceLine; + directive.clear(); } else { - if (ch == '!') { + auto provenance{cooked().GetProvenanceRange(CharBlock{&atChar, 1})}; + + // Preserves original case of the character + const auto getOriginalChar{[&](char ch) { + if (IsLetter(ch) && provenance && provenance->size() == 1) { + if (const char *orig{allSources.GetSource(*provenance)}) { + const char upper{ToUpperCaseLetter(ch)}; + if (*orig == upper) { + return upper; + } + } + } + return ch; + }}; + + if (ch == '!' && lineWasBlankBefore) { // Other comment markers (C, *, D) in original fixed form source // input card column 1 will have been deleted or normalized to !, // which signifies a comment (directive) in both source forms. inDirective = true; } - auto provenance{cooked().GetProvenanceRange(CharBlock{&atChar, 1})}; + if (inDirective && directive.size() < directiveNameLength && + IsLetter(ch)) { + directive += getOriginalChar(ch); + } + std::optional position{provenance ? allSources.GetSourcePosition(provenance->start()) : std::nullopt}; @@ -145,14 +172,18 @@ } if (column > 72) { // Wrap long lines in a portable fashion that works in both - // of the Fortran source forms. The first free-form continuation + // of the Fortran source forms. The first free-form continuation // marker ("&") lands in column 73, which begins the card commentary // field of fixed form, and the second one is put in column 6, // where it signifies fixed form line continuation. // The standard Fortran fixed form column limit (72) is used // for output, even if the input was parsed with a nonstandard // column limit override option. - out << "&\n &"; + // OpenMP and OpenACC directives' continuations should have the + // corresponding sentinel at the next line. + const auto continuation{ + inDirective ? "&\n!$" + directive + "&" : "&\n &"s}; + out << continuation; column = 7; // start of fixed form source field ++sourceLine; inContinuation = true; @@ -169,16 +200,8 @@ out << ' '; } } - if (ch >= 'a' && ch <= 'z' && provenance && provenance->size() == 1) { - // Preserve original case - if (const char *orig{allSources.GetSource(*provenance)}) { - auto upper{static_cast(ch + 'A' - 'a')}; - if (*orig == upper) { - ch = upper; - } - } - } - out << ch; + out << getOriginalChar(ch); + lineWasBlankBefore = ch == ' ' && lineWasBlankBefore; ++column; } } diff --git a/flang/test/Preprocessing/pp132.f90 b/flang/test/Preprocessing/pp132.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Preprocessing/pp132.f90 @@ -0,0 +1,18 @@ +! RUN: %flang -E -fopenmp -fopenacc %s 2>&1 | FileCheck %s +! CHECK: !$OMP parallel default(shared) private(super_very_long_name_for_the_va& +! CHECK: !$OMP&riable) +! CHECK: !$acc data copyin(super_very_long_name_for_the_variable, another_super& +! CHECK: !$acc&_wordy_variable_to_test) +! Test correct continuations in compiler directives +subroutine foo + integer :: super_very_long_name_for_the_variable + integer :: another_super_wordy_variable_to_test + + super_very_long_name_for_the_variable = 42 + another_super_wordy_variable_to_test = super_very_long_name_for_the_variable * 2 + !$OMP parallel default(shared) private(super_very_long_name_for_the_variable) + !$omp end parallel + + !$acc data copyin(super_very_long_name_for_the_variable, another_super_wordy_variable_to_test) + !$acc end data +end subroutine foo diff --git a/flang/test/Preprocessing/pp133.f90 b/flang/test/Preprocessing/pp133.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Preprocessing/pp133.f90 @@ -0,0 +1,14 @@ +! RUN: %flang -E %s 2>&1 | FileCheck %s +! CHECK: character(*), parameter :: simple_literal = "!!!!!!!!!!!!!!!!!!!!!& +! CHECK: &!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!& +! CHECK: &!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!& +! CHECK: &!!!!!!!!!!!!!" +! CHECK: character(*), parameter :: hollerith_literal = 166H!!!!!!!!!!!!!!!& +! CHECK: &!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!& +! CHECK: &!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!& +! CHECK: &!!!!!!!!!!!!!!!!!!! +! Test correct continuations in string literals +subroutine foo + character(*), parameter :: simple_literal = "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + character(*), parameter :: hollerith_literal = 166H!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +end subroutine foo