[flang] Adding semantic checks for Block Construct

Original-commit: flang-compiler/f18@e626f431d4
Reviewed-on: https://github.com/flang-compiler/f18/pull/584
Tree-same-pre-rewrite: false
This commit is contained in:
Caroline Concatto 2019-07-17 11:24:42 +01:00
parent 00b5ab683f
commit b8b0c82a18
9 changed files with 325 additions and 9 deletions

View File

@ -18,6 +18,7 @@ add_library(FortranSemantics
canonicalize-do.cc
check-allocate.cc
check-arithmeticif.cc
check-block.cc
check-coarray.cc
check-deallocate.cc
check-do.cc

View File

@ -0,0 +1,101 @@
// Copyright (c) 2019, ARM Ltd. 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.
#include <iostream>
#include "../parser/message.h"
#include "../parser/parse-tree-visitor.h"
#include "attr.h"
#include "check-block.h"
#include "scope.h"
#include "semantics.h"
#include "symbol.h"
#include "tools.h"
#include "type.h"
namespace Fortran::semantics {
class BlockEnforcement {
public:
BlockEnforcement(parser::Messages &messages) : messages_{messages} {}
std::set<parser::Label> labels() { return labels_; }
template <typename T> bool Pre(const T &) { return true; }
template <typename T> void Post(const T &) {}
template <typename T> bool Pre(const parser::Statement<T> &statement) {
currentStatementSourcePosition_ = statement.source;
if (statement.label.has_value()) {
labels_.insert(*statement.label);
}
return true;
}
// C1107$
void Post(const parser::EquivalenceStmt &) {
messages_.Say(
currentStatementSourcePosition_,
"EQUIVALENCE statement is not allowed in a BLOCK construct"_err_en_US);
}
void Post(const parser::StmtFunctionStmt &x) {
std::cout << "statementxxxxxxxx";
messages_.Say(
currentStatementSourcePosition_,
"STATEMENT FUNCTION is not allowed in a BLOCK construct"_err_en_US);
}
// C1108
void Post(const parser::SaveStmt &x) {
for (const parser::SavedEntity &y : x.v) {
auto kind{std::get<parser::SavedEntity::Kind>(y.t)};
if (kind == parser::SavedEntity::Kind::Common) {
messages_.Say(
currentStatementSourcePosition_,
"COMMON BLOCK NAME specifier not allowed in a BLOCK construct"_err_en_US);
}
}
}
private:
std::set<parser::Label> labels_;
parser::Messages &messages_;
parser::CharBlock currentStatementSourcePosition_;
}; // end BlockEnforcement
class BlockContext {
public:
BlockContext(SemanticsContext &context) : messages_{context.messages()} {}
bool operator==(const BlockContext &x) const { return this == &x; }
void Check(const parser::BlockConstruct &blockConstruct) {
BlockEnforcement blockEnforcement{messages_};
parser::Walk(std::get<parser::BlockSpecificationPart>(blockConstruct.t),
blockEnforcement);
}
private:
parser::Messages &messages_;
// parser::CharBlock currentStatementSourcePosition_;
};
BlockChecker::BlockChecker(SemanticsContext &context)
: context_{new BlockContext{context}} {}
BlockChecker::~BlockChecker() = default;
// 11.1.4 enforce semantics constraints on a Block loop body
void BlockChecker::Leave(const parser::BlockConstruct &x) {
context_.value().Check(x);
}
}
template class Fortran::common::Indirection<Fortran::semantics::BlockContext>;

View File

@ -0,0 +1,42 @@
// Copyright (c) 2019, Arm Ltd. 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.
#ifndef FORTRAN_SEMANTICS_CHECK_BLOCK_H_
#define FORTRAN_SEMANTICS_CHECK_BLOCK_H_
#include "semantics.h"
namespace Fortran::parser {
struct BlockConstruct;
}
namespace Fortran::semantics {
class BlockContext;
}
extern template class Fortran::common::Indirection<
Fortran::semantics::BlockContext>;
namespace Fortran::semantics {
class BlockChecker : public virtual BaseChecker {
public:
explicit BlockChecker(SemanticsContext &);
~BlockChecker();
void Leave(const parser::BlockConstruct &);
private:
common::Indirection<BlockContext> context_;
};
}
#endif // FORTRAN_SEMANTICS_CHECK_BLOCK_H_

View File

@ -2714,7 +2714,7 @@ bool DeclarationVisitor::Pre(const parser::ExternalStmt &x) {
bool DeclarationVisitor::Pre(const parser::IntentStmt &x) {
auto &intentSpec{std::get<parser::IntentSpec>(x.t)};
auto &names{std::get<std::list<parser::Name>>(x.t)};
return CheckNotInBlock("INTENT") &&
return CheckNotInBlock("INTENT") && //C1107
HandleAttributeStmt(IntentSpecToAttr(intentSpec), names);
}
bool DeclarationVisitor::Pre(const parser::IntrinsicStmt &x) {
@ -2733,14 +2733,15 @@ bool DeclarationVisitor::Pre(const parser::IntrinsicStmt &x) {
return false;
}
bool DeclarationVisitor::Pre(const parser::OptionalStmt &x) {
return CheckNotInBlock("OPTIONAL") &&
return CheckNotInBlock("OPTIONAL") && //C1107
HandleAttributeStmt(Attr::OPTIONAL, x.v);
}
bool DeclarationVisitor::Pre(const parser::ProtectedStmt &x) {
return HandleAttributeStmt(Attr::PROTECTED, x.v);
}
bool DeclarationVisitor::Pre(const parser::ValueStmt &x) {
return CheckNotInBlock("VALUE") && HandleAttributeStmt(Attr::VALUE, x.v);
return CheckNotInBlock("VALUE") && //C1107
HandleAttributeStmt(Attr::VALUE, x.v);
}
bool DeclarationVisitor::Pre(const parser::VolatileStmt &x) {
return HandleAttributeStmt(Attr::VOLATILE, x.v);
@ -2776,7 +2777,7 @@ Symbol &DeclarationVisitor::HandleAttributeStmt(
symbol->attrs() = HandleSaveName(name.source, symbol->attrs());
return *symbol;
}
//C1107
bool DeclarationVisitor::CheckNotInBlock(const char *stmt) {
if (currScope().kind() == Scope::Kind::Block) {
Say(MessageFormattedText{
@ -3530,7 +3531,7 @@ bool DeclarationVisitor::Pre(const parser::StructureConstructor &x) {
}
bool DeclarationVisitor::Pre(const parser::NamelistStmt::Group &x) {
if (!CheckNotInBlock("NAMELIST")) {
if (!CheckNotInBlock("NAMELIST")) { //C1107
return false;
}
@ -3572,7 +3573,7 @@ bool DeclarationVisitor::Pre(const parser::IoControlSpec &x) {
}
bool DeclarationVisitor::Pre(const parser::CommonStmt::Block &x) {
CheckNotInBlock("COMMON");
CheckNotInBlock("COMMON"); //C1107
const auto &optName{std::get<std::optional<parser::Name>>(x.t)};
parser::Name blankCommon;
blankCommon.source = SourceName{currStmtSource()->begin(), std::size_t{0}};
@ -3683,7 +3684,7 @@ void DeclarationVisitor::CheckSaveStmts() {
for (const SourceName &name : saveInfo_.commons) {
if (auto *symbol{currScope().FindCommonBlock(name)}) {
auto &objects{symbol->get<CommonBlockDetails>().objects()};
if (objects.empty()) {
if (objects.empty() && (currScope().kind() != Scope::Kind::Block)) {
Say(name,
"'%s' appears as a COMMON block in a SAVE statement but not in"
" a COMMON statement"_err_en_US);
@ -5230,7 +5231,8 @@ void ResolveNamesVisitor::CheckImport(
}
bool ResolveNamesVisitor::Pre(const parser::ImplicitStmt &x) {
return CheckNotInBlock("IMPLICIT") && ImplicitRulesVisitor::Pre(x);
return CheckNotInBlock("IMPLICIT") && //C1107
ImplicitRulesVisitor::Pre(x);
}
void ResolveNamesVisitor::Post(const parser::PointerObject &x) {
@ -5281,6 +5283,7 @@ void ResolveNamesVisitor::Post(const parser::TypeGuardStmt &x) {
ConstructVisitor::Post(x);
}
bool ResolveNamesVisitor::Pre(const parser::StmtFunctionStmt &x) {
CheckNotInBlock("STATEMENT FUNCTION"); //C1107
if (!HandleStmtFunction(x)) {
// This is an array element assignment: resolve names of indices
const auto &names{std::get<std::list<parser::Name>>(x.t)};

View File

@ -18,6 +18,7 @@
#include "check-allocate.h"
#include "check-arithmeticif.h"
#include "check-coarray.h"
#include "check-block.h"
#include "check-deallocate.h"
#include "check-do.h"
#include "check-if-stmt.h"
@ -82,7 +83,7 @@ private:
using StatementSemanticsPass1 = ExprChecker;
using StatementSemanticsPass2 = SemanticsVisitor<AllocateChecker,
ArithmeticIfStmtChecker, AssignmentChecker, CoarrayChecker,
ArithmeticIfStmtChecker, AssignmentChecker, BlockChecker, CoarrayChecker,
DeallocateChecker, DoChecker, IfStmtChecker, IoChecker, NullifyChecker,
OmpStructureChecker, ReturnStmtChecker, StopChecker>;

View File

@ -148,6 +148,9 @@ set(ERROR_TESTS
if_arith01.f90
if_construct01.f90
if_stmt01.f90
blockconstruct01.f90
blockconstruct02.f90
blockconstruct03.f90
)
# These test files have expected symbols in the source

View File

@ -0,0 +1,78 @@
! Copyright (c) 2019, ARM Ltd. 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.
! C1107 -- COMMON, EQUIVALENCE, INTENT, NAMELIST, OPTIONAL, VALEU or
! STATEMENT FUNCTIONS not allow in specification part
subroutine s1_c1107
common /nl/x
block
!ERROR: COMMON statement is not allowed in a BLOCK construct
common /nl/y
end block
end
subroutine s2_c1107
real x(100), i(5)
integer y(100), j(5)
equivalence (x, y)
block
!ERROR: EQUIVALENCE statement is not allowed in a BLOCK construct
equivalence (i, j)
end block
end
subroutine s3_c1107(x_in, x_out)
integer x_in, x_out
intent(in) x_in
block
!ERROR: INTENT statement is not allowed in a BLOCK construct
intent(out) x_out
end block
end
subroutine s4_c1107
namelist /nl/x
block
!ERROR: NAMELIST statement is not allowed in a BLOCK construct
namelist /nl/y
end block
end
subroutine s5_c1107
integer x, y
value x
block
!ERROR: VALUE statement is not allowed in a BLOCK construct
value y
end block
end
subroutine s6_c1107(x, y)
integer x, y
optional x
block
!ERROR: OPTIONAL statement is not allowed in a BLOCK construct
optional y
end block
end
subroutine s7_c1107
integer x
inc(x) = x + 1
block
!ERROR: STATEMENT FUNCTION statement is not allowed in a BLOCK construct
dec(x) = x - 1
end block
end

View File

@ -0,0 +1,27 @@
! Copyright (c) 2019, ARM Ltd. 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.
! C1108 -- Save statement in a BLOCK construct shall not conatin a
! saved-entity-list that does not specify a common-block-name
program main
integer x, y, z
real r, s, t
common /argmnt2/ r, s, t
!ERROR: 'argmnt1' appears as a COMMON block in a SAVE statement but not in a COMMON statement
save /argmnt1/
block
!ERROR: COMMON BLOCK NAME specifier not allowed in a BLOCK construct
save /argmnt2/
end block
end program

View File

@ -0,0 +1,60 @@
! Copyright (c) 2019, ARM Ltd. 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.
! Tests implemented fro this standard
! 11.1.4 - 4 It is permissible to branch to and en-block-stm only withinh its
! Block Construct
! C1109
! RUN: ${F18} -fdebug-semantics %s 2>&1 | ${FileCheck} %s
! CHECK: label '20' is not in scope
! CHECK: should be
subroutine s1
block
goto (10) 1
10 end block
block
20 end block
end
subroutine s2
block
goto (20) 1
10 end block
block
20 end block
end
subroutine s3
block
block
goto (10) 1
10 end block
20 end block
end
subroutine s4
block
block
goto (20) 1
10 end block
20 end block
end
subroutine s5_c1109
b1:block
!ERROR: BLOCK construct name mismatch
end block b2
end