[flang] Parse global compiler directives

Accept and represent "global" compiler directives that appear
before and between program units in a source file.

Differential Revision: https://reviews.llvm.org/D86555
This commit is contained in:
peter klausler
2020-08-25 09:39:52 -07:00
parent ef76686916
commit 13cee14bb1
6 changed files with 33 additions and 17 deletions

View File

@@ -547,7 +547,8 @@ struct ProgramUnit {
std::variant<common::Indirection<MainProgram>,
common::Indirection<FunctionSubprogram>,
common::Indirection<SubroutineSubprogram>, common::Indirection<Module>,
common::Indirection<Submodule>, common::Indirection<BlockData>>
common::Indirection<Submodule>, common::Indirection<BlockData>,
common::Indirection<CompilerDirective>>
u;
};

View File

@@ -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<Program>(
extension<LanguageFeature::EmptySourceFile>(skipStuffBeforeStatement >>
!nextCh >> pure<std::list<ProgramUnit>>()) ||
some(StartNewSubprogram{} >> Parser<ProgramUnit>{} / 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 @@ TYPE_PARSER(construct<Program>(
// 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<ProgramUnit>(indirect(Parser<Module>{})) ||
static constexpr auto programUnit{
construct<ProgramUnit>(indirect(Parser<Module>{})) ||
construct<ProgramUnit>(indirect(functionSubprogram)) ||
construct<ProgramUnit>(indirect(subroutineSubprogram)) ||
construct<ProgramUnit>(indirect(Parser<Submodule>{})) ||
construct<ProgramUnit>(indirect(Parser<BlockData>{})) ||
construct<ProgramUnit>(indirect(Parser<MainProgram>{})))
construct<ProgramUnit>(indirect(Parser<MainProgram>{}))};
static constexpr auto normalProgramUnit{StartNewSubprogram{} >> programUnit /
skipMany(";"_tok) / space / recovery(endOfLine, SkipPast<'\n'>{})};
static constexpr auto globalCompilerDirective{
construct<ProgramUnit>(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<Program>(
extension<LanguageFeature::EmptySourceFile>(skipStuffBeforeStatement >>
!nextCh >> pure<std::list<ProgramUnit>>()) ||
some(globalCompilerDirective || normalProgramUnit) /
skipStuffBeforeStatement))
// R504 specification-part ->
// [use-stmt]... [import-stmt]... [implicit-part]

View File

@@ -112,6 +112,10 @@ ProgramTree ProgramTree::Build(const parser::BlockData &x) {
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<const parser::Statement<parser::SubmoduleStmt> *>(stmt_)};

View File

@@ -38,6 +38,7 @@ public:
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)

View File

@@ -6226,6 +6226,11 @@ void ResolveNamesVisitor::Post(const parser::AssignedGotoStmt &x) {
}
bool ResolveNamesVisitor::Pre(const parser::ProgramUnit &x) {
if (std::holds_alternative<common::Indirection<parser::CompilerDirective>>(
x.u)) {
// TODO: global directives
return true;
}
auto root{ProgramTree::Build(x)};
SetScope(context().globalScope());
ResolveSpecificationParts(root);

View File

@@ -2,6 +2,7 @@
! Test that compiler directives can appear in various places.
!dir$ integer
module m
!dir$ integer
use iso_fortran_env