diff --git a/flang/lib/semantics/CMakeLists.txt b/flang/lib/semantics/CMakeLists.txt index e38a7d2784eb..ad020e61b654 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 ad46ef208747..3218bf4d4942 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 73d222437269..49fe998f819a 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 403daf3b2e05..3b7563a0d18e 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 aad20294681a..c1b3bf4ec2c1 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 7bda1a7db4d8..afe33cc11c33 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 4a3ea6aeb13d..ad8fe6781d1b 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 25f8976268ce..e8b9a5043539 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 f071360241f7..632d0abbc586 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 13a200586160..e94853d42848 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 bd0557ac7322..c3368b4dc76b 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 e4ed1df1c60f..49ddf9048ea0 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 8db42a4d2581..756e8408a3b0 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 000000000000..bd9f81e31c62 --- /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 000000000000..abe4be15184c --- /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 6955ac23f299..ca92e8e61ec1 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); }