forked from OSchip/llvm-project
[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:
parent
73ef31b164
commit
eedbe90e72
|
@ -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
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue