From 7edb7ec69bc9d23ea31e5629a10892f65f543bc9 Mon Sep 17 00:00:00 2001 From: Tim Keith Date: Fri, 14 Sep 2018 15:04:50 -0700 Subject: [PATCH] [flang] Add top-level Semantics class Refactor to create the Semantics class that is responsible for holding state during semantics (the scope tree and messages) and managing the logic of the various phases of semantic processing. Eliminate static Scope::globalScope. The messages generated during semantic processing are accumulated in a Messages data member of Semantics so that individual phases don't need to emit them to std::cerr. This is now done by the driver so that it has control over where they go and eliminates other includes of iostream. To do this, the messages object is passed in to the various semantics operations. Move DumpSymbols into semantics.cc: it doesn't belong in resolve-names.cc and it depends on the global scope, so it's as good a place as any. The call to RewriteParseTree is also moved to Semantics. Original-commit: flang-compiler/f18@771d0e1293c460fe28946f20464587f9a993586d Reviewed-on: https://github.com/flang-compiler/f18/pull/186 Tree-same-pre-rewrite: false --- flang/lib/semantics/CMakeLists.txt | 3 +- flang/lib/semantics/attr.cc | 1 + flang/lib/semantics/attr.h | 1 - flang/lib/semantics/mod-file.cc | 29 ++++----- flang/lib/semantics/mod-file.h | 9 +-- flang/lib/semantics/resolve-labels.cc | 26 +++----- flang/lib/semantics/resolve-labels.h | 11 ++-- flang/lib/semantics/resolve-names.cc | 85 ++++++++++---------------- flang/lib/semantics/resolve-names.h | 7 ++- flang/lib/semantics/rewrite-parse-tree.cc | 18 +++--- flang/lib/semantics/rewrite-parse-tree.h | 7 ++- flang/lib/semantics/scope.cc | 3 - flang/lib/semantics/scope.h | 6 +- flang/lib/semantics/semantics.cc | 99 +++++++++++++++++++++++++++++++ flang/lib/semantics/semantics.h | 47 +++++++++++++++ flang/tools/f18/f18.cc | 39 ++++++------ 16 files changed, 244 insertions(+), 147 deletions(-) create mode 100644 flang/lib/semantics/semantics.cc create mode 100644 flang/lib/semantics/semantics.h diff --git a/flang/lib/semantics/CMakeLists.txt b/flang/lib/semantics/CMakeLists.txt index e38a7d2..ad020e6 100644 --- a/flang/lib/semantics/CMakeLists.txt +++ b/flang/lib/semantics/CMakeLists.txt @@ -17,10 +17,11 @@ add_library(FortranSemantics attr.cc expression.cc mod-file.cc - resolve-names.cc resolve-labels.cc + resolve-names.cc rewrite-parse-tree.cc scope.cc + semantics.cc symbol.cc type.cc unparse-with-symbols.cc diff --git a/flang/lib/semantics/attr.cc b/flang/lib/semantics/attr.cc index ad46ef2..3218bf4 100644 --- a/flang/lib/semantics/attr.cc +++ b/flang/lib/semantics/attr.cc @@ -14,6 +14,7 @@ #include "attr.h" #include "../common/idioms.h" +#include #include namespace Fortran::semantics { diff --git a/flang/lib/semantics/attr.h b/flang/lib/semantics/attr.h index 73d2224..49fe998 100644 --- a/flang/lib/semantics/attr.h +++ b/flang/lib/semantics/attr.h @@ -18,7 +18,6 @@ #include "../common/enum-set.h" #include "../common/idioms.h" #include -#include #include namespace Fortran::semantics { diff --git a/flang/lib/semantics/mod-file.cc b/flang/lib/semantics/mod-file.cc index 403daf3..3b7563a 100644 --- a/flang/lib/semantics/mod-file.cc +++ b/flang/lib/semantics/mod-file.cc @@ -15,15 +15,11 @@ #include "mod-file.h" #include "scope.h" #include "symbol.h" -#include "../parser/message.h" #include "../parser/parsing.h" #include #include -#include #include -#include #include -#include #include #include #include @@ -57,15 +53,11 @@ static bool FileContentsMatch( static std::string GetHeader(const std::string &); static std::size_t GetFileSize(const std::string &); -bool ModFileWriter::WriteAll() { - WriteChildren(Scope::globalScope); - return errors_.empty(); -} - -void ModFileWriter::WriteChildren(const Scope &scope) { +bool ModFileWriter::WriteAll(const Scope &scope) { for (const auto &child : scope.children()) { WriteOne(child); } + return errors_.empty(); } void ModFileWriter::WriteOne(const Scope &scope) { @@ -74,7 +66,7 @@ void ModFileWriter::WriteOne(const Scope &scope) { if (!symbol->test(Symbol::Flag::ModFile)) { Write(*symbol); } - WriteChildren(scope); // write out submodules + WriteAll(scope); // write out submodules } } @@ -463,7 +455,8 @@ static std::size_t GetFileSize(const std::string &path) { } } -Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) { +Scope *ModFileReader::Read( + Scope &globalScope, const SourceName &name, Scope *ancestor) { std::string ancestorName; // empty for module if (ancestor) { if (auto *scope{ancestor->FindSubmodule(name)}) { @@ -471,8 +464,8 @@ Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) { } ancestorName = ancestor->name().ToString(); } else { - auto it{Scope::globalScope.find(name)}; - if (it != Scope::globalScope.end()) { + auto it{globalScope.find(name)}; + if (it != globalScope.end()) { return it->second->scope(); } } @@ -492,7 +485,7 @@ Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) { parser::Options options; options.isModuleFile = true; parsing.Prescan(*path, options); - parsing.Parse(&std::cout); + parsing.Parse(nullptr); auto &parseTree{parsing.parseTree()}; if (!parsing.messages().empty() || !parsing.consumedWholeFile() || !parseTree.has_value()) { @@ -502,13 +495,13 @@ Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) { } Scope *parentScope; // the scope this module/submodule goes into if (!ancestor) { - parentScope = &Scope::globalScope; + parentScope = &globalScope; } else if (auto *parent{GetSubmoduleParent(*parseTree)}) { - parentScope = Read(*parent, ancestor); + parentScope = Read(globalScope, *parent, ancestor); } else { parentScope = ancestor; } - ResolveNames(*parentScope, *parseTree, parsing.cooked(), directories_); + ResolveNames(errors_, *parentScope, *parseTree, directories_); const auto &it{parentScope->find(name)}; if (it == parentScope->end()) { return nullptr; diff --git a/flang/lib/semantics/mod-file.h b/flang/lib/semantics/mod-file.h index aad2029..c1b3bf4 100644 --- a/flang/lib/semantics/mod-file.h +++ b/flang/lib/semantics/mod-file.h @@ -18,8 +18,6 @@ #include "attr.h" #include "resolve-names.h" #include "../parser/message.h" -#include "../parser/provenance.h" -#include #include #include #include @@ -41,10 +39,10 @@ public: void set_directory(const std::string &dir) { dir_ = dir; } // Errors encountered during writing. Non-empty if WriteAll returns false. - parser::Messages &errors() { return errors_; } + parser::Messages &&errors() { return std::move(errors_); } // Write out all .mod files; if error return false. - bool WriteAll(); + bool WriteAll(const Scope &); private: std::string dir_{"."}; @@ -56,7 +54,6 @@ private: // Any errors encountered during writing: parser::Messages errors_; - void WriteChildren(const Scope &); void WriteOne(const Scope &); void Write(const Symbol &); std::string GetAsString(const Symbol &); @@ -77,7 +74,7 @@ public: // Find and read the module file for a module or submodule. // If ancestor is specified, look for a submodule of that module. // Return the Scope for that module/submodule or nullptr on error. - Scope *Read(const SourceName &, Scope *ancestor = nullptr); + Scope *Read(Scope &, const SourceName &, Scope *ancestor = nullptr); // Errors that occurred when Read returns nullptr. parser::Messages &errors() { return errors_; } diff --git a/flang/lib/semantics/resolve-labels.cc b/flang/lib/semantics/resolve-labels.cc index 7bda1a7..afe33cc 100644 --- a/flang/lib/semantics/resolve-labels.cc +++ b/flang/lib/semantics/resolve-labels.cc @@ -18,7 +18,6 @@ #include "../parser/parse-tree-visitor.h" #include #include -#include namespace Fortran::semantics { @@ -217,12 +216,8 @@ struct UnitAnalysis { class ParseTreeAnalyzer { public: - ParseTreeAnalyzer() {} - ParseTreeAnalyzer(ParseTreeAnalyzer &&that) - : programUnits_{std::move(that.programUnits_)}, - errorHandler_{std::move(that.errorHandler_)}, currentPosition_{std::move( - that.currentPosition_)}, - constructNames_{std::move(that.constructNames_)} {} + ParseTreeAnalyzer(parser::Messages &errorHandler) + : errorHandler_{errorHandler} {} template constexpr bool Pre(const A &) { return true; } template constexpr void Post(const A &) {} @@ -827,7 +822,7 @@ private: } std::vector programUnits_; - parser::Messages errorHandler_; + parser::Messages &errorHandler_; parser::CharBlock currentPosition_{nullptr}; ProxyForScope currentScope_{0}; std::vector constructNames_; @@ -843,8 +838,9 @@ bool InInclusiveScope(const std::vector &scopes, return true; } -ParseTreeAnalyzer LabelAnalysis(const parser::Program &program) { - ParseTreeAnalyzer analysis; +ParseTreeAnalyzer LabelAnalysis( + parser::Messages &errorHandler, const parser::Program &program) { + ParseTreeAnalyzer analysis{errorHandler}; Walk(program, analysis); return analysis; } @@ -1040,8 +1036,7 @@ void CheckDataTransferConstraints(const SourceStmtList &dataTransfers, CheckDataXferTargetConstraints(dataTransfers, labels, errorHandler); } -bool CheckConstraints(ParseTreeAnalyzer &&parseTreeAnalysis, - const parser::CookedSource &cookedSource) { +bool CheckConstraints(ParseTreeAnalyzer &&parseTreeAnalysis) { auto &errorHandler{parseTreeAnalysis.errorHandler()}; for (const auto &programUnit : parseTreeAnalysis.programUnits()) { const auto &dos{programUnit.doStmtSources}; @@ -1053,15 +1048,12 @@ bool CheckConstraints(ParseTreeAnalyzer &&parseTreeAnalysis, const auto &dataTransfers{programUnit.formatStmtSources}; CheckDataTransferConstraints(dataTransfers, labels, scopes, errorHandler); } - if (!errorHandler.empty()) { - errorHandler.Emit(std::cerr, cookedSource); - } return !errorHandler.AnyFatalError(); } bool ValidateLabels( - const parser::Program &program, const parser::CookedSource &cookedSource) { - return CheckConstraints(LabelAnalysis(program), cookedSource); + parser::Messages &errorHandler, const parser::Program &program) { + return CheckConstraints(LabelAnalysis(errorHandler, program)); } } // namespace Fortran::semantics diff --git a/flang/lib/semantics/resolve-labels.h b/flang/lib/semantics/resolve-labels.h index 4a3ea6a..ad8fe67 100644 --- a/flang/lib/semantics/resolve-labels.h +++ b/flang/lib/semantics/resolve-labels.h @@ -16,18 +16,17 @@ #define FORTRAN_SEMANTICS_RESOLVE_LABELS_H_ namespace Fortran::parser { +class Messages; struct Program; -class CookedSource; } // namespace Fortran::parser namespace Fortran::semantics { /// \brief Validate the labels in the program -/// \param ParseTree the parse tree -/// \param Source the cooked source +/// \param messages where to emit messages +/// \param program the parse tree of the program /// \return true, iff the program's labels pass semantics checks -bool ValidateLabels( - const parser::Program &ParseTree, const parser::CookedSource &Source); -} // namespace Fortran::semantics +bool ValidateLabels(parser::Messages &messages, const parser::Program &program); +} // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_RESOLVE_LABELS_H_ diff --git a/flang/lib/semantics/resolve-names.cc b/flang/lib/semantics/resolve-names.cc index 25f8976..e8b9a50 100644 --- a/flang/lib/semantics/resolve-names.cc +++ b/flang/lib/semantics/resolve-names.cc @@ -187,7 +187,7 @@ public: using Message = parser::Message; using MessageFixedText = parser::MessageFixedText; - const parser::Messages &messages() const { return messages_; } + void set_messages(parser::Messages &messages) { messages_ = &messages; } template bool Pre(const parser::Statement &x) { currStmtSource_ = &x.source; @@ -218,14 +218,13 @@ public: private: // Where messages are emitted: - parser::Messages messages_; + parser::Messages *messages_; // Source location of current statement; null if not in a statement const SourceName *currStmtSource_{nullptr}; }; // Visit ImplicitStmt and related parse tree nodes and updates implicit rules. -class ImplicitRulesVisitor : public DeclTypeSpecVisitor, - public virtual MessageHandler { +class ImplicitRulesVisitor : public DeclTypeSpecVisitor, public MessageHandler { public: using DeclTypeSpecVisitor::Post; using DeclTypeSpecVisitor::Pre; @@ -301,12 +300,13 @@ private: }; // Manage a stack of Scopes -class ScopeHandler : public virtual ImplicitRulesVisitor { +class ScopeHandler : public ImplicitRulesVisitor { public: - void set_rootScope(Scope &scope) { PushScope(scope); } Scope &currScope() { return *currScope_; } // The enclosing scope, skipping blocks and derived types. Scope &InclusiveScope(); + // The global scope, containing program units. + Scope &GlobalScope(); // Create a new scope and push it on the scope stack. void PushScope(Scope::Kind kind, Symbol *symbol); @@ -646,6 +646,11 @@ public: using SubprogramVisitor::Post; using SubprogramVisitor::Pre; + ResolveNamesVisitor(parser::Messages &messages, Scope &rootScope) { + set_messages(messages); + PushScope(rootScope); + } + // Default action for a parse tree node is to visit children. template bool Pre(const T &) { return true; } template void Post(const T &) {} @@ -963,7 +968,7 @@ int DeclTypeSpecVisitor::GetKindParamValue( MessageHandler::Message &MessageHandler::Say(MessageFixedText &&msg) { CHECK(currStmtSource_); - return messages_.Say(*currStmtSource_, std::move(msg)); + return messages_->Say(*currStmtSource_, std::move(msg)); } MessageHandler::Message &MessageHandler::Say( const SourceName &name, MessageFixedText &&msg) { @@ -971,15 +976,15 @@ MessageHandler::Message &MessageHandler::Say( } MessageHandler::Message &MessageHandler::Say( const parser::Name &name, MessageFixedText &&msg) { - return messages_.Say(name.source, std::move(msg), name.ToString().c_str()); + return messages_->Say(name.source, std::move(msg), name.ToString().c_str()); } MessageHandler::Message &MessageHandler::Say(const SourceName &location, MessageFixedText &&msg, const std::string &arg1) { - return messages_.Say(location, std::move(msg), arg1.c_str()); + return messages_->Say(location, std::move(msg), arg1.c_str()); } MessageHandler::Message &MessageHandler::Say(const SourceName &location, MessageFixedText &&msg, const SourceName &arg1, const SourceName &arg2) { - return messages_.Say(location, std::move(msg), arg1.ToString().c_str(), + return messages_->Say(location, std::move(msg), arg1.ToString().c_str(), arg2.ToString().c_str()); } void MessageHandler::SayAlreadyDeclared( @@ -992,7 +997,7 @@ void MessageHandler::Say2(const SourceName &name1, MessageFixedText &&msg1, Say(name1, std::move(msg1)).Attach(name2, msg2, name2.ToString().c_str()); } void MessageHandler::Annex(parser::Messages &&msgs) { - messages_.Annex(std::move(msgs)); + messages_->Annex(std::move(msgs)); } // ImplicitRulesVisitor implementation @@ -1184,6 +1189,15 @@ Scope &ScopeHandler::InclusiveScope() { return *scope; } } + common::die("inclusive scope not found"); +} +Scope &ScopeHandler::GlobalScope() { + for (auto *scope = currScope_; scope; scope = &scope->parent()) { + if (scope->kind() == Scope::Kind::Global) { + return *scope; + } + } + common::die("global scope not found"); } void ScopeHandler::PushScope(Scope::Kind kind, Symbol *symbol) { PushScope(currScope().MakeScope(kind, symbol)); @@ -1411,7 +1425,7 @@ Symbol &ModuleVisitor::BeginModule(const SourceName &name, bool isSubmodule, // If an error occurs, report it and return nullptr. Scope *ModuleVisitor::FindModule(const SourceName &name, Scope *ancestor) { ModFileReader reader{searchDirectories_}; - auto *scope{reader.Read(name, ancestor)}; + auto *scope{reader.Read(GlobalScope(), name, ancestor)}; if (!scope) { Annex(std::move(reader.errors())); return nullptr; @@ -2842,20 +2856,14 @@ void ResolveNamesVisitor::Post(const parser::Program &) { CHECK(!GetDeclTypeSpec()); } -void ResolveNames(Scope &rootScope, parser::Program &program, - const parser::CookedSource &cookedSource, +void ResolveNames(parser::Messages &messages, Scope &rootScope, + const parser::Program &program, const std::vector &searchDirectories) { - ResolveNamesVisitor visitor; - visitor.set_rootScope(rootScope); + ResolveNamesVisitor visitor{messages, rootScope}; for (auto &dir : searchDirectories) { visitor.add_searchDirectory(dir); } - parser::Walk(const_cast(program), visitor); - if (!visitor.messages().empty()) { - visitor.messages().Emit(std::cerr, cookedSource); - return; - } - RewriteParseTree(program, cookedSource); + parser::Walk(program, visitor); } // Map the enum in the parser to the one in GenericSpec @@ -2940,37 +2948,4 @@ static GenericSpec MapGenericSpec(const parser::GenericSpec &genericSpec) { genericSpec.u); } -static void PutIndent(std::ostream &os, int indent) { - for (int i = 0; i < indent; ++i) { - os << " "; - } -} - -static void DumpSymbols(std::ostream &os, const Scope &scope, int indent = 0) { - PutIndent(os, indent); - os << Scope::EnumToString(scope.kind()) << " scope:"; - if (const auto *symbol{scope.symbol()}) { - os << ' ' << symbol->name().ToString(); - } - os << '\n'; - ++indent; - for (const auto &pair : scope) { - const auto &symbol{*pair.second}; - PutIndent(os, indent); - os << symbol << '\n'; - if (const auto *details{symbol.detailsIf()}) { - if (const auto &type{details->derivedType()}) { - PutIndent(os, indent); - os << *type << '\n'; - } - } - } - for (const auto &child : scope.children()) { - DumpSymbols(os, child, indent); - } - --indent; -} - -void DumpSymbols(std::ostream &os) { DumpSymbols(os, Scope::globalScope); } - } // namespace Fortran::semantics diff --git a/flang/lib/semantics/resolve-names.h b/flang/lib/semantics/resolve-names.h index f071360..632d0ab 100644 --- a/flang/lib/semantics/resolve-names.h +++ b/flang/lib/semantics/resolve-names.h @@ -16,19 +16,20 @@ #define FORTRAN_SEMANTICS_RESOLVE_NAMES_H_ #include +#include #include namespace Fortran::parser { +class Messages; struct Program; -class CookedSource; } // namespace Fortran::parser namespace Fortran::semantics { class Scope; -void ResolveNames(Scope &rootScope, parser::Program &, - const parser::CookedSource &, const std::vector &); +void ResolveNames(parser::Messages &, Scope &, const parser::Program &, + const std::vector &); void DumpSymbols(std::ostream &); } // namespace Fortran::semantics diff --git a/flang/lib/semantics/rewrite-parse-tree.cc b/flang/lib/semantics/rewrite-parse-tree.cc index 13a2005..e94853d 100644 --- a/flang/lib/semantics/rewrite-parse-tree.cc +++ b/flang/lib/semantics/rewrite-parse-tree.cc @@ -31,9 +31,8 @@ using symbolMap = std::map; /// Convert mis-identified statement functions to array element assignments. class RewriteMutator { public: - RewriteMutator(const symbolMap &symbols) : symbols_{symbols} {} - - const parser::Messages &messages() const { return messages_; } + RewriteMutator(parser::Messages &messages, const symbolMap &symbols) + : messages_{messages}, symbols_{symbols} {} // Default action for a parse tree node is to visit children. template bool Pre(T &) { return true; } @@ -67,9 +66,9 @@ private: using stmtFuncType = parser::Statement>; bool errorOnUnresolvedName_{true}; + parser::Messages &messages_; const symbolMap &symbols_; std::list stmtFuncsToConvert_; - parser::Messages messages_; // For T = Variable or Expr, if x has a function reference that really // should be an array element reference (i.e. the name occurs in an @@ -95,7 +94,7 @@ void RewriteMutator::Post(parser::Name &name) { if (it != symbols_.end()) { name.symbol = it->second; } else if (errorOnUnresolvedName_) { - messages_.Say(name.source, "Internal: no symbol found for '%s'"_err_en_US, + messages_.Say(name.source, "Internal: no symbol found for '%s'"_en_US, name.ToString().c_str()); } } @@ -136,7 +135,7 @@ static void CollectSymbol(Symbol &symbol, symbolMap &symbols) { } } -static void CollectSymbols(Scope &scope, symbolMap &symbols) { +static void CollectSymbols(const Scope &scope, symbolMap &symbols) { for (auto &pair : scope) { Symbol *symbol{pair.second}; CollectSymbol(*symbol, symbols); @@ -152,12 +151,11 @@ static void CollectSymbols(Scope &scope, symbolMap &symbols) { } void RewriteParseTree( - parser::Program &program, const parser::CookedSource &cookedSource) { + parser::Messages &messages, const Scope &scope, parser::Program &program) { symbolMap symbols; - CollectSymbols(Scope::globalScope, symbols); - RewriteMutator mutator{symbols}; + CollectSymbols(scope, symbols); + RewriteMutator mutator{messages, symbols}; parser::Walk(program, mutator); - mutator.messages().Emit(std::cerr, cookedSource); } } // namespace Fortran::semantics diff --git a/flang/lib/semantics/rewrite-parse-tree.h b/flang/lib/semantics/rewrite-parse-tree.h index bd0557a..c3368b4 100644 --- a/flang/lib/semantics/rewrite-parse-tree.h +++ b/flang/lib/semantics/rewrite-parse-tree.h @@ -16,12 +16,15 @@ #define FORTRAN_SEMANTICS_REWRITE_PARSE_TREE_H_ namespace Fortran::parser { +class Messages; struct Program; -class CookedSource; } // namespace Fortran::parser +namespace Fortran::semantics { +class Scope; +} // namespace Fortran::semantics namespace Fortran::semantics { -void RewriteParseTree(parser::Program &, const parser::CookedSource &); +void RewriteParseTree(parser::Messages &, const Scope &, parser::Program &); } // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_REWRITE_PARSE_TREE_H_ diff --git a/flang/lib/semantics/scope.cc b/flang/lib/semantics/scope.cc index e4ed1df..49ddf90 100644 --- a/flang/lib/semantics/scope.cc +++ b/flang/lib/semantics/scope.cc @@ -18,9 +18,6 @@ namespace Fortran::semantics { -Scope Scope::systemScope{Scope::systemScope, Scope::Kind::System, nullptr}; -Scope Scope::globalScope{Scope::systemScope, Scope::Kind::Global, nullptr}; - Symbols<1024> Scope::allSymbols; bool Scope::IsModule() const { diff --git a/flang/lib/semantics/scope.h b/flang/lib/semantics/scope.h index 8db42a4..756e840 100644 --- a/flang/lib/semantics/scope.h +++ b/flang/lib/semantics/scope.h @@ -33,14 +33,12 @@ class Scope { using mapType = std::map; public: - // root of the scope tree; contains intrinsics: - static Scope systemScope; - static Scope globalScope; // contains program-units - ENUM_CLASS( Kind, System, Global, Module, MainProgram, Subprogram, DerivedType, Block) using ImportKind = common::ImportKind; + // Create the Global scope -- the root of the scope tree + Scope() : Scope{*this, Kind::Global, nullptr} {} Scope(Scope &parent, Kind kind, Symbol *symbol) : parent_{parent}, kind_{kind}, symbol_{symbol} { if (symbol) { diff --git a/flang/lib/semantics/semantics.cc b/flang/lib/semantics/semantics.cc new file mode 100644 index 0000000..bd9f81e --- /dev/null +++ b/flang/lib/semantics/semantics.cc @@ -0,0 +1,99 @@ +// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "semantics.h" +#include "mod-file.h" +#include "resolve-labels.h" +#include "resolve-names.h" +#include "rewrite-parse-tree.h" +#include "scope.h" +#include "symbol.h" + +namespace Fortran::semantics { + +static void DoDumpSymbols(std::ostream &, const Scope &, int indent = 0); +static void PutIndent(std::ostream &, int indent); + +Semantics &Semantics::set_searchDirectories( + const std::vector &directories) { + for (auto directory : directories) { + directories_.push_back(directory); + } + return *this; +} + +Semantics &Semantics::set_moduleDirectory(const std::string &directory) { + moduleDirectory_ = directory; + directories_.insert(directories_.begin(), directory); + return *this; +} + +bool Semantics::Perform(parser::Program &program) { + ValidateLabels(messages_, program); + if (AnyFatalError()) { + return false; + } + ResolveNames(messages_, globalScope_, program, directories_); + if (AnyFatalError()) { + return false; + } + RewriteParseTree(messages_, globalScope_, program); + if (AnyFatalError()) { + return false; + } + ModFileWriter writer; + writer.set_directory(moduleDirectory_); + if (!writer.WriteAll(globalScope_)) { + messages_.Annex(writer.errors()); + return false; + } + return true; +} + +void Semantics::DumpSymbols(std::ostream &os) { + DoDumpSymbols(os, globalScope_); +} + +void DoDumpSymbols(std::ostream &os, const Scope &scope, int indent) { + PutIndent(os, indent); + os << Scope::EnumToString(scope.kind()) << " scope:"; + if (const auto *symbol{scope.symbol()}) { + os << ' ' << symbol->name().ToString(); + } + os << '\n'; + ++indent; + for (const auto &pair : scope) { + const auto &symbol{*pair.second}; + PutIndent(os, indent); + os << symbol << '\n'; + if (const auto *details{symbol.detailsIf()}) { + if (const auto &type{details->derivedType()}) { + PutIndent(os, indent); + os << *type << '\n'; + } + } + } + for (const auto &child : scope.children()) { + DoDumpSymbols(os, child, indent); + } + --indent; +} + +static void PutIndent(std::ostream &os, int indent) { + for (int i = 0; i < indent; ++i) { + os << " "; + } +} + +} // namespace Fortran::semantics diff --git a/flang/lib/semantics/semantics.h b/flang/lib/semantics/semantics.h new file mode 100644 index 0000000..abe4be1 --- /dev/null +++ b/flang/lib/semantics/semantics.h @@ -0,0 +1,47 @@ +// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FORTRAN_SEMANTICS_SEMANTICS_H_ +#define FORTRAN_SEMANTICS_SEMANTICS_H_ + +#include "scope.h" +#include "../parser/message.h" +#include +#include + +namespace Fortran::parser { + struct Program; +} + +namespace Fortran::semantics { + +class Semantics { +public: + Semantics() { directories_.push_back("."s); } + const parser::Messages &messages() const { return messages_; } + Semantics &set_searchDirectories(const std::vector &); + Semantics &set_moduleDirectory(const std::string &); + bool AnyFatalError() const { return messages_.AnyFatalError(); } + bool Perform(parser::Program &); + void DumpSymbols(std::ostream &); + +private: + Scope globalScope_; + std::vector directories_; + std::string moduleDirectory_{"."s}; + parser::Messages messages_; +}; +} // namespace Fortran::semantics + +#endif diff --git a/flang/tools/f18/f18.cc b/flang/tools/f18/f18.cc index 6955ac2..ca92e8e 100644 --- a/flang/tools/f18/f18.cc +++ b/flang/tools/f18/f18.cc @@ -24,10 +24,7 @@ #include "../../lib/parser/unparse.h" #include "../../lib/semantics/dump-parse-tree.h" #include "../../lib/semantics/expression.h" -#include "../../lib/semantics/mod-file.h" -#include "../../lib/semantics/resolve-labels.h" -#include "../../lib/semantics/resolve-names.h" -#include "../../lib/semantics/scope.h" +#include "../../lib/semantics/semantics.h" #include "../../lib/semantics/unparse-with-symbols.h" #include #include @@ -159,8 +156,8 @@ std::string RelocatableName(const DriverOptions &driver, std::string path) { int exitStatus{EXIT_SUCCESS}; -std::string CompileFortran( - std::string path, Fortran::parser::Options options, DriverOptions &driver) { +std::string CompileFortran(std::string path, Fortran::parser::Options options, + DriverOptions &driver, Fortran::semantics::Semantics &semantics) { if (!driver.forcedForm) { auto dot{path.rfind(".")}; if (dot != std::string::npos) { @@ -211,20 +208,17 @@ std::string CompileFortran( } if (driver.debugResolveNames || driver.dumpSymbols || driver.dumpUnparseWithSymbols || driver.debugExpressions) { - std::vector directories{options.searchDirectories}; - directories.insert(directories.begin(), "."s); - if (driver.moduleDirectory != "."s) { - directories.insert(directories.begin(), driver.moduleDirectory); - } - (void)Fortran::semantics::ValidateLabels(parseTree, parsing.cooked()); - Fortran::semantics::ResolveNames(Fortran::semantics::Scope::globalScope, - parseTree, parsing.cooked(), directories); - Fortran::semantics::ModFileWriter writer; - writer.set_directory(driver.moduleDirectory); - writer.WriteAll(); - writer.errors().Emit(std::cerr, parsing.cooked()); + semantics.Perform(parseTree); + auto &messages{semantics.messages()}; + messages.Emit(std::cerr, parsing.cooked()); if (driver.dumpSymbols) { - Fortran::semantics::DumpSymbols(std::cout); + semantics.DumpSymbols(std::cout); + } + if (!messages.empty() && + (driver.warningsAreErrors || messages.AnyFatalError())) { + std::cerr << driver.prefix << "semantic errors in " << path << '\n'; + exitStatus = EXIT_FAILURE; + return {}; } if (driver.dumpUnparseWithSymbols) { Fortran::semantics::UnparseWithSymbols( @@ -493,14 +487,17 @@ int main(int argc, char *const argv[]) { driver.pgf90Args.push_back("-Mbackslash"); } + Fortran::semantics::Semantics semantics; + semantics.set_searchDirectories(options.searchDirectories); + semantics.set_moduleDirectory(driver.moduleDirectory); if (!anyFiles) { driver.measureTree = true; driver.dumpUnparse = true; - CompileFortran("-", options, driver); + CompileFortran("-", options, driver, semantics); return exitStatus; } for (const auto &path : fortranSources) { - std::string relo{CompileFortran(path, options, driver)}; + std::string relo{CompileFortran(path, options, driver, semantics)}; if (!driver.compileOnly && !relo.empty()) { relocatables.push_back(relo); } -- 2.7.4