diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -547,7 +547,8 @@ std::variant, common::Indirection, common::Indirection, common::Indirection, - common::Indirection, common::Indirection> + common::Indirection, common::Indirection, + common::Indirection> u; }; diff --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp --- a/flang/lib/Parser/program-parsers.cpp +++ b/flang/lib/Parser/program-parsers.cpp @@ -20,20 +20,6 @@ namespace Fortran::parser { -// R501 program -> program-unit [program-unit]... -// This is the top-level production for the Fortran language. -// F'2018 6.3.1 defines a program unit as a sequence of one or more lines, -// implying that a line can't be part of two distinct program units. -// 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( - extension(skipStuffBeforeStatement >> - !nextCh >> pure>()) || - some(StartNewSubprogram{} >> Parser{} / skipMany(";"_tok) / - space / recovery(endOfLine, SkipPast<'\n'>{})) / - skipStuffBeforeStatement)) - // R502 program-unit -> // main-program | external-subprogram | module | submodule | block-data // R503 external-subprogram -> function-subprogram | subroutine-subprogram @@ -49,12 +35,30 @@ // variant parsers for several productions; giving the "module" production // priority here is a cleaner solution, though regrettably subtle. Enforcing // C1547 is done in semantics. -TYPE_PARSER(construct(indirect(Parser{})) || +static constexpr auto programUnit{ + construct(indirect(Parser{})) || construct(indirect(functionSubprogram)) || construct(indirect(subroutineSubprogram)) || construct(indirect(Parser{})) || construct(indirect(Parser{})) || - construct(indirect(Parser{}))) + construct(indirect(Parser{}))}; +static constexpr auto normalProgramUnit{StartNewSubprogram{} >> programUnit / + skipMany(";"_tok) / space / recovery(endOfLine, SkipPast<'\n'>{})}; +static constexpr auto globalCompilerDirective{ + construct(indirect(compilerDirective))}; + +// R501 program -> program-unit [program-unit]... +// This is the top-level production for the Fortran language. +// F'2018 6.3.1 defines a program unit as a sequence of one or more lines, +// implying that a line can't be part of two distinct program units. +// 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( + extension(skipStuffBeforeStatement >> + !nextCh >> pure>()) || + some(globalCompilerDirective || normalProgramUnit) / + skipStuffBeforeStatement)) // R504 specification-part -> // [use-stmt]... [import-stmt]... [implicit-part] diff --git a/flang/lib/Semantics/program-tree.h b/flang/lib/Semantics/program-tree.h --- a/flang/lib/Semantics/program-tree.h +++ b/flang/lib/Semantics/program-tree.h @@ -38,6 +38,7 @@ static ProgramTree Build(const parser::Module &); static ProgramTree Build(const parser::Submodule &); static ProgramTree Build(const parser::BlockData &); + static ProgramTree Build(const parser::CompilerDirective &); ENUM_CLASS(Kind, // kind of node Program, Function, Subroutine, MpSubprogram, Module, Submodule, BlockData) diff --git a/flang/lib/Semantics/program-tree.cpp b/flang/lib/Semantics/program-tree.cpp --- a/flang/lib/Semantics/program-tree.cpp +++ b/flang/lib/Semantics/program-tree.cpp @@ -112,6 +112,10 @@ return result.set_stmt(stmt).set_endStmt(end); } +ProgramTree ProgramTree::Build(const parser::CompilerDirective &) { + DIE("ProgramTree::Build() called for CompilerDirective"); +} + const parser::ParentIdentifier &ProgramTree::GetParentId() const { const auto *stmt{ std::get *>(stmt_)}; diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -6226,6 +6226,11 @@ } bool ResolveNamesVisitor::Pre(const parser::ProgramUnit &x) { + if (std::holds_alternative>( + x.u)) { + // TODO: global directives + return true; + } auto root{ProgramTree::Build(x)}; SetScope(context().globalScope()); ResolveSpecificationParts(root); diff --git a/flang/test/Parser/compiler-directives.f90 b/flang/test/Parser/compiler-directives.f90 --- a/flang/test/Parser/compiler-directives.f90 +++ b/flang/test/Parser/compiler-directives.f90 @@ -2,6 +2,7 @@ ! Test that compiler directives can appear in various places. +!dir$ integer module m !dir$ integer use iso_fortran_env