[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:
Pete Steinfeld 2019-08-26 16:26:24 -07:00
parent ada293fa66
commit 73ef31b164
6 changed files with 92 additions and 0 deletions

View File

@ -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

View File

@ -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_;
};
}

View File

@ -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

View File

@ -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 {

View File

@ -146,6 +146,7 @@ set(ERROR_TESTS
dosemantics07.f90
dosemantics08.f90
dosemantics09.f90
dosemantics10.f90
expr-errors01.f90
null01.f90
omp-clause-validity01.f90

View File

@ -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