mirror of
https://github.com/intel/llvm.git
synced 2026-01-18 16:50:51 +08:00
[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:
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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_)};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
! Test that compiler directives can appear in various places.
|
||||
|
||||
!dir$ integer
|
||||
module m
|
||||
!dir$ integer
|
||||
use iso_fortran_env
|
||||
|
||||
Reference in New Issue
Block a user