From 6c390a780b4195a0498802f0a2e8658e934cc4ad Mon Sep 17 00:00:00 2001 From: peter klausler Date: Fri, 6 Dec 2019 09:37:07 -0800 Subject: [PATCH] [flang] Accept source files with no program units (flang-compiler/f18#658) update documentation Original-commit: flang-compiler/f18@3dfb8314991035a428c514cf0ad46af446d64a4e Reviewed-on: https://github.com/flang-compiler/f18/pull/859 --- flang/documentation/Extensions.md | 6 ++++-- flang/lib/common/Fortran-features.h | 3 ++- flang/lib/parser/grammar.h | 10 ++++++---- flang/lib/parser/parsing.cc | 10 +++++----- flang/lib/parser/provenance.cc | 2 ++ flang/lib/parser/provenance.h | 1 + flang/lib/parser/source.cc | 16 +++++----------- 7 files changed, 25 insertions(+), 23 deletions(-) diff --git a/flang/documentation/Extensions.md b/flang/documentation/Extensions.md index 1fe4d46c8c25..03f7cfafd823 100644 --- a/flang/documentation/Extensions.md +++ b/flang/documentation/Extensions.md @@ -109,8 +109,10 @@ Extensions, deletions, and legacy features supported by default * When a dummy argument is `POINTER` or `ALLOCATABLE` and is `INTENT(IN)`, we relax enforcement of some requirements on actual arguments that must otherwise hold true for definable arguments. -* Assignment of `LOGICAL` to `INTEGER` and vice versa (but not other types). - The values are normalized. +* Assignment of `LOGICAL` to `INTEGER` and vice versa (but not other types) is + allowed. The values are normalized. +* An effectively empty source file (no program unit) is accepted and + produces an empty relocatable output file. Extensions supported when enabled by options -------------------------------------------- diff --git a/flang/lib/common/Fortran-features.h b/flang/lib/common/Fortran-features.h index c9b3f13c1158..ec9323e52be3 100644 --- a/flang/lib/common/Fortran-features.h +++ b/flang/lib/common/Fortran-features.h @@ -33,7 +33,8 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines, Hollerith, ArithmeticIF, Assign, AssignedGOTO, Pause, OpenMP, CruftAfterAmpersand, ClassicCComments, AdditionalFormats, BigIntLiterals, RealDoControls, EquivalenceNumericWithCharacter, AdditionalIntrinsics, - AnonymousParents, OldLabelDoEndStatements, LogicalIntegerAssignment) + AnonymousParents, OldLabelDoEndStatements, LogicalIntegerAssignment, + EmptySourceFile) using LanguageFeatures = EnumSet; diff --git a/flang/lib/parser/grammar.h b/flang/lib/parser/grammar.h index 600f6b74a190..4e0b3d68e853 100644 --- a/flang/lib/parser/grammar.h +++ b/flang/lib/parser/grammar.h @@ -276,10 +276,12 @@ constexpr auto scalarIntConstantExpr{scalar(intConstantExpr)}; // Consequently, a program unit END statement should be the last statement // on its line. We parse those END statements via unterminatedStatement() // and then skip over the end of the line here. -TYPE_PARSER(construct(some(StartNewSubprogram{} >> - Parser{} / skipMany(";"_tok) / space / - recovery(endOfLine, SkipPast<'\n'>{}))) / - skipStuffBeforeStatement) +TYPE_PARSER(construct( + extension(skipStuffBeforeStatement >> + !nextCh >> defaulted(cut >> some(Parser{}))) || + some(StartNewSubprogram{} >> Parser{} / skipMany(";"_tok) / + space / recovery(endOfLine, SkipPast<'\n'>{})) / + skipStuffBeforeStatement)) // R502 program-unit -> // main-program | external-subprogram | module | submodule | block-data diff --git a/flang/lib/parser/parsing.cc b/flang/lib/parser/parsing.cc index 30b405580596..92e328715900 100644 --- a/flang/lib/parser/parsing.cc +++ b/flang/lib/parser/parsing.cc @@ -50,11 +50,6 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) { return sourceFile; } CHECK(sourceFile); - if (sourceFile->bytes() == 0) { - ProvenanceRange range{allSources.AddCompilerInsertion(path)}; - messages_.Say(range, "file is empty"_err_en_US); - return sourceFile; - } if (!options.isModuleFile) { // For .mod files we always want to look in the search directories. @@ -86,6 +81,11 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) { ProvenanceRange range{allSources.AddIncludedFile( *sourceFile, ProvenanceRange{}, options.isModuleFile)}; prescanner.Prescan(range); + if (cooked_.BufferedBytes() == 0 && !options.isModuleFile) { + // Input is empty. Append a newline so that any warning + // message about nonstandard usage will have provenance. + cooked_.Put('\n', range.start()); + } cooked_.Marshal(); if (options.needProvenanceRangeToCharBlockMappings) { cooked_.CompileProvenanceRangeToOffsetMappings(); diff --git a/flang/lib/parser/provenance.cc b/flang/lib/parser/provenance.cc index 279e6fa399a9..542f048caa5a 100644 --- a/flang/lib/parser/provenance.cc +++ b/flang/lib/parser/provenance.cc @@ -461,6 +461,8 @@ std::optional CookedSource::GetCharBlock( } } +std::size_t CookedSource::BufferedBytes() const { return buffer_.bytes(); } + void CookedSource::Marshal() { CHECK(provenanceMap_.SizeInBytes() == buffer_.bytes()); provenanceMap_.Put(allSources_.AddCompilerInsertion("(after end of source)")); diff --git a/flang/lib/parser/provenance.h b/flang/lib/parser/provenance.h index 30d2058701dc..b978505b8077 100644 --- a/flang/lib/parser/provenance.h +++ b/flang/lib/parser/provenance.h @@ -262,6 +262,7 @@ public: provenanceMap_.Put(pm); } + std::size_t BufferedBytes() const; void Marshal(); // marshals text into one contiguous block void CompileProvenanceRangeToOffsetMappings(); std::string AcquireData() { return std::move(data_); } diff --git a/flang/lib/parser/source.cc b/flang/lib/parser/source.cc index 4c074b2e1c21..880bf0178b47 100644 --- a/flang/lib/parser/source.cc +++ b/flang/lib/parser/source.cc @@ -223,17 +223,11 @@ bool SourceFile::ReadFile(std::string errorPath, std::stringstream *error) { --openFileDescriptors; } fileDescriptor_ = -1; - if (buffer.bytes() == 0) { - // empty file - address_ = content_ = nullptr; - size_ = bytes_ = 0; - } else { - normalized_ = buffer.MarshalNormalized(); - address_ = normalized_.data(); - size_ = normalized_.size(); - IdentifyPayload(); - RecordLineStarts(); - } + normalized_ = buffer.MarshalNormalized(); + address_ = normalized_.c_str(); + size_ = normalized_.size(); + IdentifyPayload(); + RecordLineStarts(); return true; }