diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4269,6 +4269,12 @@ HelpText<"Unparse and stop.">; def fdebug_unparse_with_symbols : Flag<["-"], "fdebug-unparse-with-symbols">, Group, HelpText<"Unparse and stop.">; +def fdebug_dump_symbols : Flag<["-"], "fdebug-dump-symbols">, Group, + HelpText<"Dump symbols after the semantic analysis">; +def fdebug_dump_parse_tree : Flag<["-"], "fdebug-dump-parse-tree">, Group, + HelpText<"Dump the parse tree">; +def fdebug_dump_provenance : Flag<["-"], "fdebug-dump-provenance">, Group, + HelpText<"Dump provenance">; } diff --git a/flang/include/flang/Frontend/FrontendActions.h b/flang/include/flang/Frontend/FrontendActions.h --- a/flang/include/flang/Frontend/FrontendActions.h +++ b/flang/include/flang/Frontend/FrontendActions.h @@ -10,6 +10,8 @@ #define LLVM_FLANG_FRONTEND_FRONTENDACTIONS_H #include "flang/Frontend/FrontendAction.h" +#include "flang/Semantics/semantics.h" +#include namespace Fortran::frontend { @@ -37,12 +39,26 @@ void ExecuteAction() override; }; +class DebugDumpProvenanceAction : public PrescanAction { + void ExecuteAction() override; +}; + //===----------------------------------------------------------------------===// // PrescanAndSema Actions //===----------------------------------------------------------------------===// class PrescanAndSemaAction : public FrontendAction { + std::unique_ptr semantics_; + void ExecuteAction() override = 0; bool BeginSourceFileAction(CompilerInstance &ci) override; + +public: + Fortran::semantics::Semantics &semantics() { return *semantics_; } + const Fortran::semantics::Semantics &semantics() const { return *semantics_; } + + void setSemantics(std::unique_ptr semantics) { + semantics_ = std::move(semantics); + } }; class DebugUnparseWithSymbolsAction : public PrescanAndSemaAction { @@ -53,6 +69,14 @@ void ExecuteAction() override; }; +class DebugDumpSymbolsAction : public PrescanAndSemaAction { + void ExecuteAction() override; +}; + +class DebugDumpParseTreeAction : public PrescanAndSemaAction { + void ExecuteAction() override; +}; + class ParseSyntaxOnlyAction : public PrescanAndSemaAction { void ExecuteAction() override; }; diff --git a/flang/include/flang/Frontend/FrontendOptions.h b/flang/include/flang/Frontend/FrontendOptions.h --- a/flang/include/flang/Frontend/FrontendOptions.h +++ b/flang/include/flang/Frontend/FrontendOptions.h @@ -41,6 +41,15 @@ /// Fortran source file DebugUnparseWithSymbols, + /// Parse, run semantics and then output symbols from semantics + DebugDumpSymbols, + + /// Parse, run semantics and then output the parse tree + DebugDumpParseTree, + + /// Dump provenance + DebugDumpProvenance + /// TODO: RunPreprocessor, EmitLLVM, EmitLLVMOnly, /// EmitCodeGenOnly, EmitAssembly, (...) }; diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -116,6 +116,15 @@ case clang::driver::options::OPT_fdebug_unparse_with_symbols: opts.programAction_ = DebugUnparseWithSymbols; break; + case clang::driver::options::OPT_fdebug_dump_symbols: + opts.programAction_ = DebugDumpSymbols; + break; + case clang::driver::options::OPT_fdebug_dump_parse_tree: + opts.programAction_ = DebugDumpParseTree; + break; + case clang::driver::options::OPT_fdebug_dump_provenance: + opts.programAction_ = DebugDumpProvenance; + break; // TODO: // case calng::driver::options::OPT_emit_llvm: diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -10,15 +10,28 @@ #include "flang/Common/default-kinds.h" #include "flang/Frontend/CompilerInstance.h" #include "flang/Frontend/FrontendOptions.h" +#include "flang/Parser/dump-parse-tree.h" #include "flang/Parser/parsing.h" #include "flang/Parser/provenance.h" #include "flang/Parser/source.h" #include "flang/Parser/unparse.h" #include "flang/Semantics/semantics.h" #include "flang/Semantics/unparse-with-symbols.h" +#include "llvm/ADT/StringRef.h" +#include +#include using namespace Fortran::frontend; +void reportFatalSemanticErrors(const Fortran::semantics::Semantics &semantics, + clang::DiagnosticsEngine &diags, const llvm::StringRef &bufferName) { + if (semantics.AnyFatalError()) { + unsigned DiagID = diags.getCustomDiagID( + clang::DiagnosticsEngine::Error, "Semantic errors in %0"); + diags.Report(DiagID) << bufferName; + } +} + bool PrescanAction::BeginSourceFileAction(CompilerInstance &c1) { CompilerInstance &ci = this->instance(); @@ -101,23 +114,16 @@ auto &parseTree{*ci.parsing().parseTree()}; // Prepare semantics - Fortran::semantics::Semantics semantics{ci.invocation().semanticsContext(), - parseTree, ci.parsing().cooked().AsCharBlock()}; + setSemantics(std::make_unique( + ci.invocation().semanticsContext(), parseTree, + ci.parsing().cooked().AsCharBlock())); + auto &semantics = this->semantics(); // Run semantic checks semantics.Perform(); // Report the diagnostics from the semantic checks semantics.EmitMessages(ci.semaOutputStream()); - - if (semantics.AnyFatalError()) { - unsigned DiagID = ci.diagnostics().getCustomDiagID( - clang::DiagnosticsEngine::Error, "Semantic errors in %0"); - ci.diagnostics().Report(DiagID) << GetCurrentFileOrBufferName(); - - return false; - } - return true; } @@ -183,7 +189,14 @@ } } -void ParseSyntaxOnlyAction::ExecuteAction() {} +void DebugDumpProvenanceAction::ExecuteAction() { + this->instance().parsing().DumpProvenance(llvm::outs()); +} + +void ParseSyntaxOnlyAction::ExecuteAction() { + reportFatalSemanticErrors(semantics(), this->instance().diagnostics(), + GetCurrentFileOrBufferName()); +} void DebugUnparseAction::ExecuteAction() { auto &parseTree{instance().parsing().parseTree()}; @@ -195,6 +208,10 @@ /*encoding=*/Fortran::parser::Encoding::UTF_8, /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, /*preStatement=*/nullptr, &asFortran); + + // Report fatal semantic errors + reportFatalSemanticErrors(semantics(), this->instance().diagnostics(), + GetCurrentFileOrBufferName()); } void DebugUnparseWithSymbolsAction::ExecuteAction() { @@ -202,6 +219,32 @@ Fortran::semantics::UnparseWithSymbols( llvm::outs(), parseTree, /*encoding=*/Fortran::parser::Encoding::UTF_8); + + // Report fatal semantic errors + reportFatalSemanticErrors(semantics(), this->instance().diagnostics(), + GetCurrentFileOrBufferName()); +} + +void DebugDumpSymbolsAction::ExecuteAction() { + auto &semantics = this->semantics(); + + // Dump symbols + semantics.DumpSymbols(llvm::outs()); + // Report fatal semantic errors + reportFatalSemanticErrors( + semantics, this->instance().diagnostics(), GetCurrentFileOrBufferName()); +} + +void DebugDumpParseTreeAction::ExecuteAction() { + auto &parseTree{instance().parsing().parseTree()}; + Fortran::parser::AnalyzedObjectsAsFortran asFortran = + Fortran::frontend::getBasicAsFortran(); + + // Dump parse tree + Fortran::parser::DumpTree(llvm::outs(), parseTree, &asFortran); + // Report fatal semantic errors + reportFatalSemanticErrors(semantics(), this->instance().diagnostics(), + GetCurrentFileOrBufferName()); } void EmitObjAction::ExecuteAction() { diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp --- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -43,6 +43,15 @@ case DebugUnparseWithSymbols: return std::make_unique(); break; + case DebugDumpSymbols: + return std::make_unique(); + break; + case DebugDumpParseTree: + return std::make_unique(); + break; + case DebugDumpProvenance: + return std::make_unique(); + break; default: break; // TODO: diff --git a/flang/test/Flang-Driver/debug-provenance.f90 b/flang/test/Flang-Driver/debug-provenance.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Flang-Driver/debug-provenance.f90 @@ -0,0 +1,26 @@ +! Ensure argument -fdebug-dump-provenance works as expected. + +! REQUIRES: new-flang-driver + +!-------------------------- +! FLANG DRIVER (flang-new) +!-------------------------- +! RUN: not %flang-new -fdebug-dump-provenance %s 2>&1 | FileCheck %s --check-prefix=FLANG + +!---------------------------------------- +! FRONTEND FLANG DRIVER (flang-new -fc1) +!---------------------------------------- +! RUN: %flang-new -fc1 -fdebug-dump-provenance %s 2>&1 | FileCheck %s --check-prefix=FRONTEND + +!---------------------------------- +! EXPECTED OUTPUT WITH `flang-new` +!---------------------------------- +! FLANG:warning: argument unused during compilation: '-fdebug-dump-provenance' + +!--------------------------------------- +! EXPECTED OUTPUT WITH `flang-new -fc1` +!--------------------------------------- +! FRONTEND:AllSources: +! FRONTEND:CookedSource::provenanceMap_: +program A +end diff --git a/flang/test/Flang-Driver/driver-help.f90 b/flang/test/Flang-Driver/driver-help.f90 --- a/flang/test/Flang-Driver/driver-help.f90 +++ b/flang/test/Flang-Driver/driver-help.f90 @@ -56,6 +56,9 @@ ! HELP-FC1-NEXT: -falternative-parameter-statement ! HELP-FC1-NEXT: Enable the old style PARAMETER statement ! HELP-FC1-NEXT: -fbackslash Specify that backslash in string introduces an escape character +! HELP-FC1-NEXT: -fdebug-dump-parse-tree Dump the parse tree +! HELP-FC1-NEXT: -fdebug-dump-provenance Dump provenance +! HELP-FC1-NEXT: -fdebug-dump-symbols Dump symbols after the semantic analysis ! HELP-FC1-NEXT: -fdebug-unparse-with-symbols ! HELP-FC1-NEXT: Unparse and stop. ! HELP-FC1-NEXT: -fdebug-unparse Unparse and stop. diff --git a/flang/test/Semantics/data05.f90 b/flang/test/Semantics/data05.f90 --- a/flang/test/Semantics/data05.f90 +++ b/flang/test/Semantics/data05.f90 @@ -1,4 +1,4 @@ -!RUN: %f18 -fdebug-dump-symbols %s | FileCheck %s +!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s module m interface integer function ifunc(n) diff --git a/flang/test/Semantics/data08.f90 b/flang/test/Semantics/data08.f90 --- a/flang/test/Semantics/data08.f90 +++ b/flang/test/Semantics/data08.f90 @@ -1,4 +1,4 @@ -! RUN: %f18 -fdebug-dump-symbols %s 2>&1 | FileCheck %s +! RUN: %flang_fc1 -fdebug-dump-symbols %s 2>&1 | FileCheck %s ! CHECK: DATA statement value initializes 'jx' of type 'INTEGER(4)' with CHARACTER ! CHECK: DATA statement value initializes 'jy' of type 'INTEGER(4)' with CHARACTER ! CHECK: DATA statement value initializes 'jz' of type 'INTEGER(4)' with CHARACTER diff --git a/flang/test/Semantics/data09.f90 b/flang/test/Semantics/data09.f90 --- a/flang/test/Semantics/data09.f90 +++ b/flang/test/Semantics/data09.f90 @@ -1,4 +1,4 @@ -! RUN: %f18 -fsyntax-only -fdebug-dump-symbols %s 2>&1 | FileCheck %s +! RUN: %flang_fc1 -fsyntax-only -fdebug-dump-symbols %s 2>&1 | FileCheck %s ! CHECK: init:[INTEGER(4)::1065353216_4,1073741824_4,1077936128_4,1082130432_4] ! Verify that the closure of EQUIVALENCE'd symbols with any DATA ! initialization produces a combined initializer. diff --git a/flang/test/Semantics/offsets01.f90 b/flang/test/Semantics/offsets01.f90 --- a/flang/test/Semantics/offsets01.f90 +++ b/flang/test/Semantics/offsets01.f90 @@ -1,4 +1,4 @@ -!RUN: %f18 -fdebug-dump-symbols %s | FileCheck %s +!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s ! Size and alignment of intrinsic types subroutine s1 diff --git a/flang/test/Semantics/offsets02.f90 b/flang/test/Semantics/offsets02.f90 --- a/flang/test/Semantics/offsets02.f90 +++ b/flang/test/Semantics/offsets02.f90 @@ -1,4 +1,4 @@ -!RUN: %f18 -fdebug-dump-symbols %s | FileCheck %s +!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s ! Size and alignment of derived types diff --git a/flang/test/Semantics/offsets03.f90 b/flang/test/Semantics/offsets03.f90 --- a/flang/test/Semantics/offsets03.f90 +++ b/flang/test/Semantics/offsets03.f90 @@ -1,4 +1,4 @@ -!RUN: %f18 -fdebug-dump-symbols %s | FileCheck %s +!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s ! Size and alignment with EQUIVALENCE and COMMON diff --git a/flang/test/Semantics/resolve100.f90 b/flang/test/Semantics/resolve100.f90 --- a/flang/test/Semantics/resolve100.f90 +++ b/flang/test/Semantics/resolve100.f90 @@ -1,4 +1,4 @@ -!RUN: %f18 -fdebug-dump-symbols %s | FileCheck %s +!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s program p ! CHECK: a size=4 offset=0: ObjectEntity type: LOGICAL(4) diff --git a/flang/test/Semantics/rewrite01.f90 b/flang/test/Semantics/rewrite01.f90 --- a/flang/test/Semantics/rewrite01.f90 +++ b/flang/test/Semantics/rewrite01.f90 @@ -1,4 +1,4 @@ -! RUN: %f18 -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s +! RUN: %flang_fc1 -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s ! Ensure that READ(CVAR) [, item-list] is corrected when CVAR is a ! character variable so as to be a formatted read from the default ! unit, not an unformatted read from an internal unit (which is not