forked from OSchip/llvm-project
[flang] Changes to add an executable construct stack
I added a stack of ExecutableConstruct's to SemanticsContext along with functions to push and pop constructs. I added code to the SemanticsVisitor to use these new functions. I also added functions Pre and Post functions for UnlabeledStatement's so that we could isolate the source positions for statements embedded in "if" statements to improve error messages. I also added code to check-do.[h,cc] to use this new infrastructure to check for CYCLE and EXIT statements that are not contained within DO constructs along with a test. Original-commit: flang-compiler/f18@b8370bdeb8 Reviewed-on: https://github.com/flang-compiler/f18/pull/686 Tree-same-pre-rewrite: false
This commit is contained in:
parent
ada293fa66
commit
73ef31b164
|
@ -647,4 +647,21 @@ void DoChecker::Leave(const parser::DoConstruct &x) {
|
|||
doContext.Check(x);
|
||||
}
|
||||
|
||||
void DoChecker::CheckLoneStmt(const char *stmtString) const {
|
||||
for (auto &executable : context_.executables()) {
|
||||
if (std::holds_alternative<common::Indirection<parser::DoConstruct>>(
|
||||
executable->u)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
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
|
||||
void DoChecker::Enter(const parser::ExitStmt &) { CheckLoneStmt("EXIT"); }
|
||||
|
||||
} // namespace Fortran::semantics
|
||||
|
|
|
@ -27,8 +27,12 @@ class DoChecker : public virtual BaseChecker {
|
|||
public:
|
||||
explicit DoChecker(SemanticsContext &context) : context_{context} {}
|
||||
void Leave(const parser::DoConstruct &);
|
||||
void Enter(const parser::CycleStmt &);
|
||||
void Enter(const parser::ExitStmt &);
|
||||
|
||||
private:
|
||||
void CheckLoneStmt(const char *const) const;
|
||||
|
||||
SemanticsContext &context_;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -67,10 +67,30 @@ public:
|
|||
Enter(node);
|
||||
return true;
|
||||
}
|
||||
template<typename T> bool Pre(const parser::UnlabeledStatement<T> &node) {
|
||||
context_.set_location(node.source);
|
||||
Enter(node);
|
||||
return true;
|
||||
}
|
||||
template<typename T> void Post(const parser::Statement<T> &node) {
|
||||
Leave(node);
|
||||
context_.set_location(std::nullopt);
|
||||
}
|
||||
template<typename T> void Post(const parser::UnlabeledStatement<T> &node) {
|
||||
Leave(node);
|
||||
context_.set_location(std::nullopt);
|
||||
}
|
||||
|
||||
bool Pre(const parser::ExecutableConstruct &executable) {
|
||||
context_.PushExecutable(executable);
|
||||
Enter(executable);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Post(const parser::ExecutableConstruct &executable) {
|
||||
Leave(executable);
|
||||
context_.PopExecutable();
|
||||
}
|
||||
|
||||
bool Walk(const parser::Program &program) {
|
||||
parser::Walk(program, *this);
|
||||
|
@ -168,6 +188,16 @@ Scope &SemanticsContext::FindScope(parser::CharBlock source) {
|
|||
}
|
||||
}
|
||||
|
||||
void SemanticsContext::PushExecutable(
|
||||
const parser::ExecutableConstruct &executable) {
|
||||
executables_.push_back(&executable);
|
||||
}
|
||||
|
||||
void SemanticsContext::PopExecutable() {
|
||||
CHECK(executables_.size() > 0);
|
||||
executables_.pop_back();
|
||||
}
|
||||
|
||||
bool Semantics::Perform() {
|
||||
return ValidateLabels(context_, program_) &&
|
||||
parser::CanonicalizeDo(program_) && // force line break
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../evaluate/intrinsics.h"
|
||||
#include "../parser/features.h"
|
||||
#include "../parser/message.h"
|
||||
#include "../parser/parse-tree.h"
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -120,6 +121,12 @@ public:
|
|||
const Scope &FindScope(parser::CharBlock) const;
|
||||
Scope &FindScope(parser::CharBlock);
|
||||
|
||||
const std::vector<const parser::ExecutableConstruct *> executables() const {
|
||||
return executables_;
|
||||
}
|
||||
void PushExecutable(const parser::ExecutableConstruct &executable);
|
||||
void PopExecutable();
|
||||
|
||||
private:
|
||||
const common::IntrinsicTypeDefaultKinds &defaultKinds_;
|
||||
const parser::LanguageFeatureControl languageFeatures_;
|
||||
|
@ -136,6 +143,7 @@ private:
|
|||
evaluate::FoldingContext foldingContext_{defaultKinds_};
|
||||
|
||||
bool CheckError(bool);
|
||||
std::vector<const parser::ExecutableConstruct *> executables_;
|
||||
};
|
||||
|
||||
class Semantics {
|
||||
|
|
|
@ -146,6 +146,7 @@ set(ERROR_TESTS
|
|||
dosemantics07.f90
|
||||
dosemantics08.f90
|
||||
dosemantics09.f90
|
||||
dosemantics10.f90
|
||||
expr-errors01.f90
|
||||
null01.f90
|
||||
omp-clause-validity01.f90
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
! Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
!
|
||||
! Licensed under the Apache License, Version 2.0 (the "License");
|
||||
! you may not use this file except in compliance with the License.
|
||||
! You may obtain a copy of the License at
|
||||
!
|
||||
! http://www.apache.org/licenses/LICENSE-2.0
|
||||
!
|
||||
! Unless required by applicable law or agreed to in writing, software
|
||||
! distributed under the License is distributed on an "AS IS" BASIS,
|
||||
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
! See the License for the specific language governing permissions and
|
||||
! limitations under the License.
|
||||
!
|
||||
! C1134 A CYCLE statement must be within a DO construct
|
||||
!
|
||||
! C1166 An EXIT statement must be within a DO construct
|
||||
|
||||
subroutine s1()
|
||||
!ERROR: CYCLE must be within a DO construct
|
||||
cycle
|
||||
|
||||
!ERROR: EXIT must be within a DO construct
|
||||
exit
|
||||
|
||||
!ERROR: CYCLE must be within a DO construct
|
||||
if(.true.) cycle
|
||||
|
||||
!ERROR: EXIT must be within a DO construct
|
||||
if(.true.) exit
|
||||
|
||||
end subroutine s1
|
Loading…
Reference in New Issue