[flang] Responses to review comments and team meeting

The most significant change is that I replaced the stack of
ExecutableConstruct's with a stack composed of ConstructNode's, each of which
is a variant of the constructs that made up the type ExecutableConstruct.  This
change allows the nodes of the stack to be extended to include the types needed
for OMP semantic checking.

I also extended the existing test to include some correct DO loops with CYCLE
and EXIT statements to test the code more completely.

Original-commit: flang-compiler/f18@d26f34e3a4
Reviewed-on: https://github.com/flang-compiler/f18/pull/686
Tree-same-pre-rewrite: false
This commit is contained in:
Pete Steinfeld 2019-08-29 16:02:37 -07:00
parent 73ef31b164
commit eedbe90e72
5 changed files with 186 additions and 33 deletions

View File

@ -647,21 +647,20 @@ void DoChecker::Leave(const parser::DoConstruct &x) {
doContext.Check(x); doContext.Check(x);
} }
void DoChecker::CheckLoneStmt(const char *stmtString) const { // C1134
for (auto &executable : context_.executables()) { void DoChecker::Enter(const parser::CycleStmt &) {
if (std::holds_alternative<common::Indirection<parser::DoConstruct>>( if (!context_.InsideDoConstruct()) {
executable->u)) { context_.Say(
return; *context_.location(), "CYCLE must be within a DO construct"_err_en_US);
}
} }
context_.Say(*context_.location(),
"%s must be within a DO construct"_err_en_US, stmtString);
} }
// C1134
void DoChecker::Enter(const parser::CycleStmt &) { CheckLoneStmt("CYCLE"); }
// C1166 // C1166
void DoChecker::Enter(const parser::ExitStmt &) { CheckLoneStmt("EXIT"); } void DoChecker::Enter(const parser::ExitStmt &) {
if (!context_.InsideDoConstruct()) {
context_.Say(
*context_.location(), "EXIT must be within a DO construct"_err_en_US);
}
}
} // namespace Fortran::semantics } // namespace Fortran::semantics

View File

@ -19,6 +19,8 @@
namespace Fortran::parser { namespace Fortran::parser {
struct DoConstruct; struct DoConstruct;
struct CycleStmt;
struct ExitStmt;
} }
namespace Fortran::semantics { namespace Fortran::semantics {
@ -31,8 +33,6 @@ public:
void Enter(const parser::ExitStmt &); void Enter(const parser::ExitStmt &);
private: private:
void CheckLoneStmt(const char *const) const;
SemanticsContext &context_; SemanticsContext &context_;
}; };
} }

View File

@ -81,15 +81,125 @@ public:
context_.set_location(std::nullopt); context_.set_location(std::nullopt);
} }
bool Pre(const parser::ExecutableConstruct &executable) { bool Pre(const parser::AssociateConstruct &associateConstruct) {
context_.PushExecutable(executable); context_.PushConstruct(&associateConstruct);
Enter(executable); Enter(associateConstruct);
return true; return true;
} }
void Post(const parser::ExecutableConstruct &executable) { bool Pre(const parser::BlockConstruct &blockConstruct) {
Leave(executable); context_.PushConstruct(&blockConstruct);
context_.PopExecutable(); Enter(blockConstruct);
return true;
}
bool Pre(const parser::CaseConstruct &caseConstruct) {
context_.PushConstruct(&caseConstruct);
Enter(caseConstruct);
return true;
}
bool Pre(const parser::DoConstruct &doConstruct) {
context_.PushConstruct(&doConstruct);
Enter(doConstruct);
return true;
}
bool Pre(const parser::CriticalConstruct &criticalConstruct) {
context_.PushConstruct(&criticalConstruct);
Enter(criticalConstruct);
return true;
}
bool Pre(const parser::ChangeTeamConstruct &changeTeamConstruct) {
context_.PushConstruct(&changeTeamConstruct);
Enter(changeTeamConstruct);
return true;
}
bool Pre(const parser::ForAllConstruct &forAllConstruct) {
context_.PushConstruct(&forAllConstruct);
Enter(forAllConstruct);
return true;
}
bool Pre(const parser::IfConstruct &ifConstruct) {
context_.PushConstruct(&ifConstruct);
Enter(ifConstruct);
return true;
}
bool Pre(const parser::SelectRankConstruct &selectRankConstruct) {
context_.PushConstruct(&selectRankConstruct);
Enter(selectRankConstruct);
return true;
}
bool Pre(const parser::SelectTypeConstruct &selectTypeConstruct) {
context_.PushConstruct(&selectTypeConstruct);
Enter(selectTypeConstruct);
return true;
}
bool Pre(const parser::WhereConstruct &whereConstruct) {
context_.PushConstruct(&whereConstruct);
Enter(whereConstruct);
return true;
}
void Post(const parser::AssociateConstruct &associateConstruct) {
Leave(associateConstruct);
context_.PopConstruct();
}
void Post(const parser::BlockConstruct &blockConstruct) {
Leave(blockConstruct);
context_.PopConstruct();
}
void Post(const parser::CaseConstruct &caseConstruct) {
Leave(caseConstruct);
context_.PopConstruct();
}
void Post(const parser::DoConstruct &doConstruct) {
Leave(doConstruct);
context_.PopConstruct();
}
void Post(const parser::CriticalConstruct &criticalConstruct) {
Leave(criticalConstruct);
context_.PopConstruct();
}
void Post(const parser::ChangeTeamConstruct &changeTeamConstruct) {
Leave(changeTeamConstruct);
context_.PopConstruct();
}
void Post(const parser::ForAllConstruct &forAllConstruct) {
Leave(forAllConstruct);
context_.PopConstruct();
}
void Post(const parser::IfConstruct &ifConstruct) {
Leave(ifConstruct);
context_.PopConstruct();
}
void Post(const parser::SelectRankConstruct &selectRankConstruct) {
Leave(selectRankConstruct);
context_.PopConstruct();
}
void Post(const parser::SelectTypeConstruct &selectTypeConstruct) {
Leave(selectTypeConstruct);
context_.PopConstruct();
}
void Post(const parser::WhereConstruct &whereConstruct) {
Leave(whereConstruct);
context_.PopConstruct();
} }
bool Walk(const parser::Program &program) { bool Walk(const parser::Program &program) {
@ -188,14 +298,22 @@ Scope &SemanticsContext::FindScope(parser::CharBlock source) {
} }
} }
void SemanticsContext::PushExecutable( void SemanticsContext::PushConstruct(const ConstructNode &construct) {
const parser::ExecutableConstruct &executable) { constructStack_.emplace_back(construct);
executables_.push_back(&executable);
} }
void SemanticsContext::PopExecutable() { void SemanticsContext::PopConstruct() {
CHECK(executables_.size() > 0); CHECK(!constructStack_.empty());
executables_.pop_back(); constructStack_.pop_back();
}
bool SemanticsContext::InsideDoConstruct() const {
for (const ConstructNode construct : constructStack_) {
if (std::holds_alternative<const parser::DoConstruct *>(construct)) {
return true;
}
}
return false;
} }
bool Semantics::Perform() { bool Semantics::Perform() {

View File

@ -20,7 +20,6 @@
#include "../evaluate/intrinsics.h" #include "../evaluate/intrinsics.h"
#include "../parser/features.h" #include "../parser/features.h"
#include "../parser/message.h" #include "../parser/message.h"
#include "../parser/parse-tree.h"
#include <iosfwd> #include <iosfwd>
#include <string> #include <string>
#include <vector> #include <vector>
@ -33,12 +32,31 @@ namespace Fortran::parser {
struct Name; struct Name;
struct Program; struct Program;
class CookedSource; class CookedSource;
struct AssociateConstruct;
struct BlockConstruct;
struct CaseConstruct;
struct DoConstruct;
struct CriticalConstruct;
struct ChangeTeamConstruct;
struct ForAllConstruct;
struct IfConstruct;
struct SelectRankConstruct;
struct SelectTypeConstruct;
struct WhereConstruct;
} }
namespace Fortran::semantics { namespace Fortran::semantics {
class Symbol; class Symbol;
using ConstructNode = std::variant<const parser::AssociateConstruct *,
const parser::BlockConstruct *, const parser::CaseConstruct *,
const parser::ChangeTeamConstruct *, const parser::CriticalConstruct *,
const parser::DoConstruct *, const parser::ForAllConstruct *,
const parser::IfConstruct *, const parser::SelectRankConstruct *,
const parser::SelectTypeConstruct *, const parser::WhereConstruct *>;
using ConstructStack = std::vector<ConstructNode>;
class SemanticsContext { class SemanticsContext {
public: public:
SemanticsContext(const common::IntrinsicTypeDefaultKinds &, SemanticsContext(const common::IntrinsicTypeDefaultKinds &,
@ -121,11 +139,10 @@ public:
const Scope &FindScope(parser::CharBlock) const; const Scope &FindScope(parser::CharBlock) const;
Scope &FindScope(parser::CharBlock); Scope &FindScope(parser::CharBlock);
const std::vector<const parser::ExecutableConstruct *> executables() const { const ConstructStack &constructStack() const { return constructStack_; }
return executables_; void PushConstruct(const ConstructNode &construct);
} void PopConstruct();
void PushExecutable(const parser::ExecutableConstruct &executable); bool InsideDoConstruct() const;
void PopExecutable();
private: private:
const common::IntrinsicTypeDefaultKinds &defaultKinds_; const common::IntrinsicTypeDefaultKinds &defaultKinds_;
@ -143,7 +160,7 @@ private:
evaluate::FoldingContext foldingContext_{defaultKinds_}; evaluate::FoldingContext foldingContext_{defaultKinds_};
bool CheckError(bool); bool CheckError(bool);
std::vector<const parser::ExecutableConstruct *> executables_; ConstructStack constructStack_;
}; };
class Semantics { class Semantics {

View File

@ -17,6 +17,25 @@
! C1166 An EXIT statement must be within a DO construct ! C1166 An EXIT statement must be within a DO construct
subroutine s1() subroutine s1()
! this one's OK
do i = 1,10
cycle
end do
! this one's OK
do i = 1,10
exit
end do
! all of these are OK
outer: do i = 1,10
cycle
inner: do j = 1,10
cycle
end do inner
cycle
end do outer
!ERROR: CYCLE must be within a DO construct !ERROR: CYCLE must be within a DO construct
cycle cycle