forked from OSchip/llvm-project
[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:
parent
00b5ab683f
commit
b8b0c82a18
|
@ -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
|
||||
|
|
|
@ -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>;
|
|
@ -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_
|
|
@ -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)};
|
||||
|
|
|
@ -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>;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue