forked from OSchip/llvm-project
[flang] Build with all compilers * versions
Original-commit: flang-compiler/f18@7332caa613 Reviewed-on: https://github.com/flang-compiler/f18/pull/755 Tree-same-pre-rewrite: false
This commit is contained in:
parent
fc5d127c1c
commit
32f2ea0753
|
@ -17,6 +17,8 @@
|
|||
#include "../semantics/symbol.h"
|
||||
#include "../semantics/tools.h"
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
// Constant expression predicate IsConstantExpr().
|
||||
|
@ -45,7 +47,7 @@ public:
|
|||
template<typename T> bool operator()(const FunctionRef<T> &call) const {
|
||||
if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&call.proc().u)}) {
|
||||
return intrinsic->name == "kind";
|
||||
// TODO: Obviously many other intrinsics can be allowed
|
||||
// TODO: other inquiry intrinsics
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -130,103 +132,86 @@ bool IsInitialDataTarget(const Expr<SomeType> &x) {
|
|||
}
|
||||
|
||||
// Specification expression validation (10.1.11(2), C1010)
|
||||
class CheckSpecificationExprHelper
|
||||
: public AllTraverse<CheckSpecificationExprHelper> {
|
||||
public:
|
||||
using Base = AllTraverse<CheckSpecificationExprHelper>;
|
||||
struct CheckSpecificationExprHelper
|
||||
: public AnyTraverse<CheckSpecificationExprHelper,
|
||||
std::optional<std::string>> {
|
||||
using Result = std::optional<std::string>;
|
||||
using Base = AnyTraverse<CheckSpecificationExprHelper, Result>;
|
||||
CheckSpecificationExprHelper() : Base{*this} {}
|
||||
using Base::operator();
|
||||
|
||||
explicit CheckSpecificationExprHelper(std::string &why)
|
||||
: Base{*this}, why_{why} {
|
||||
why_.clear();
|
||||
Result operator()(const ProcedureDesignator &) const {
|
||||
return "dummy procedure argument";
|
||||
}
|
||||
Result operator()(const CoarrayRef &) const { return "coindexed reference"; }
|
||||
|
||||
bool operator()(const ProcedureDesignator &) {
|
||||
return Say("dummy procedure argument");
|
||||
}
|
||||
bool operator()(const CoarrayRef &) { return Say("coindexed reference"); }
|
||||
|
||||
bool operator()(const semantics::Symbol &symbol) {
|
||||
Result operator()(const semantics::Symbol &symbol) const {
|
||||
if (semantics::IsNamedConstant(symbol)) {
|
||||
return true;
|
||||
return std::nullopt;
|
||||
} else if (symbol.IsDummy()) {
|
||||
if (symbol.attrs().test(semantics::Attr::OPTIONAL)) {
|
||||
return Say("reference to OPTIONAL dummy argument '" +
|
||||
symbol.name().ToString() + "'");
|
||||
return "reference to OPTIONAL dummy argument '"s +
|
||||
symbol.name().ToString() + "'";
|
||||
} else if (symbol.attrs().test(semantics::Attr::INTENT_OUT)) {
|
||||
return Say("reference to INTENT(OUT) dummy argument '" +
|
||||
symbol.name().ToString() + "'");
|
||||
return "reference to INTENT(OUT) dummy argument '"s +
|
||||
symbol.name().ToString() + "'";
|
||||
} else if (symbol.has<semantics::ObjectEntityDetails>()) {
|
||||
return true;
|
||||
return std::nullopt;
|
||||
} else {
|
||||
return Say("dummy procedure argument");
|
||||
return "dummy procedure argument";
|
||||
}
|
||||
} else if (symbol.has<semantics::UseDetails>() ||
|
||||
symbol.has<semantics::HostAssocDetails>() ||
|
||||
symbol.owner().kind() == semantics::Scope::Kind::Module) {
|
||||
return true;
|
||||
return std::nullopt;
|
||||
} else if (const auto *object{
|
||||
symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
// TODO: what about EQUIVALENCE with data in COMMON?
|
||||
// TODO: does this work for blank COMMON?
|
||||
if (object->commonBlock() != nullptr) {
|
||||
return true;
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
return Say("reference to local entity '" + symbol.name().ToString() + "'");
|
||||
return "reference to local entity '"s + symbol.name().ToString() + "'";
|
||||
}
|
||||
|
||||
bool operator()(const Component &x) {
|
||||
Result operator()(const Component &x) const {
|
||||
// Don't look at the component symbol.
|
||||
return (*this)(x.base());
|
||||
}
|
||||
|
||||
template<typename T> bool operator()(const FunctionRef<T> &x) {
|
||||
template<typename T> Result operator()(const FunctionRef<T> &x) const {
|
||||
if (const auto *symbol{x.proc().GetSymbol()}) {
|
||||
if (!symbol->attrs().test(semantics::Attr::PURE)) {
|
||||
return Say(
|
||||
"reference to impure function '" + symbol->name().ToString() + "'");
|
||||
return "reference to impure function '"s + symbol->name().ToString() +
|
||||
"'";
|
||||
} else if (symbol->owner().kind() == semantics::Scope::Kind::Subprogram) {
|
||||
return Say("reference to internal function '" +
|
||||
symbol->name().ToString() + "'");
|
||||
return "reference to internal function '"s + symbol->name().ToString() +
|
||||
"'";
|
||||
}
|
||||
// TODO: other checks for standard module procedures
|
||||
} else {
|
||||
const SpecificIntrinsic &intrin{DEREF(x.proc().GetSpecificIntrinsic())};
|
||||
if (intrin.name == "present") {
|
||||
return true; // no need to check argument(s)
|
||||
return std::nullopt; // no need to check argument(s)
|
||||
}
|
||||
if (IsConstantExpr(x)) {
|
||||
return true; // inquiry functions may not need to check argument(s)
|
||||
return std::nullopt; // inquiry functions may not need to check
|
||||
// argument(s)
|
||||
}
|
||||
}
|
||||
return (*this)(x.arguments());
|
||||
}
|
||||
|
||||
private:
|
||||
bool Say(std::string &&s) {
|
||||
if (!why_.empty()) {
|
||||
why_ += "; ";
|
||||
}
|
||||
why_ += std::move(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string &why_;
|
||||
};
|
||||
|
||||
template<typename A>
|
||||
void CheckSpecificationExpr(const A &x, parser::ContextualMessages &messages) {
|
||||
std::string why;
|
||||
if (!CheckSpecificationExprHelper{why}(x)) {
|
||||
if (auto why{CheckSpecificationExprHelper{}(x)}) {
|
||||
std::stringstream ss;
|
||||
ss << x;
|
||||
if (!why.empty()) {
|
||||
why = " ("s + why + ')';
|
||||
}
|
||||
messages.Say("The expression (%s) cannot be used as a "
|
||||
"specification expression%s"_err_en_US,
|
||||
ss.str(), why);
|
||||
"specification expression (%s)"_err_en_US,
|
||||
ss.str(), *why);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
namespace Fortran::parser {
|
||||
class ContextualMessages;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
|
|
|
@ -390,12 +390,12 @@ auto GetShapeHelper::operator()(const NamedEntity &base) const -> Result {
|
|||
if (IsImpliedShape(symbol)) {
|
||||
return (*this)(object->init());
|
||||
} else {
|
||||
Shape result;
|
||||
Shape shape;
|
||||
int n{object->shape().Rank()};
|
||||
for (int dimension{0}; dimension < n; ++dimension) {
|
||||
result.emplace_back(GetExtent(context_, base, dimension));
|
||||
shape.emplace_back(GetExtent(context_, base, dimension));
|
||||
}
|
||||
return std::move(result);
|
||||
return shape;
|
||||
}
|
||||
} else {
|
||||
return (*this)(symbol);
|
||||
|
@ -414,7 +414,7 @@ auto GetShapeHelper::operator()(const ArrayRef &arrayRef) const -> Result {
|
|||
if (shape.empty()) {
|
||||
return (*this)(arrayRef.base());
|
||||
} else {
|
||||
return std::move(shape);
|
||||
return shape;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,7 +431,7 @@ auto GetShapeHelper::operator()(const CoarrayRef &coarrayRef) const -> Result {
|
|||
if (shape.empty()) {
|
||||
return (*this)(base);
|
||||
} else {
|
||||
return std::move(shape);
|
||||
return shape;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -125,9 +125,9 @@ public:
|
|||
template<typename D, typename R, typename LO, typename RO>
|
||||
Result operator()(const Operation<D, R, LO, RO> &operation) const {
|
||||
if (operation.right().Rank() > 0) {
|
||||
(*this)(operation.right());
|
||||
return (*this)(operation.right());
|
||||
} else {
|
||||
(*this)(operation.left());
|
||||
return (*this)(operation.left());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -279,7 +279,10 @@ struct SetTraverse : public Base {
|
|||
using Base::Base;
|
||||
using Base::operator();
|
||||
static Set Combine(Set &&x, Set &&y) {
|
||||
x.merge(y);
|
||||
// TODO: use x.merge(y) instead when clang headers support it
|
||||
for (auto &value : y) {
|
||||
x.insert(std::move(value));
|
||||
}
|
||||
return std::move(x);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -51,45 +51,7 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
void Check(const Symbol &symbol) const {
|
||||
if (context_.HasError(symbol) || symbol.has<UseDetails>() ||
|
||||
symbol.has<HostAssocDetails>()) {
|
||||
return;
|
||||
}
|
||||
auto save{messages_.SetLocation(symbol.name())};
|
||||
context_.set_location(symbol.name());
|
||||
if (const DeclTypeSpec * type{symbol.GetType()}) {
|
||||
Check(*type);
|
||||
}
|
||||
if (IsAssumedLengthCharacterFunction(symbol)) { // C723
|
||||
if (symbol.attrs().test(Attr::RECURSIVE)) {
|
||||
context_.Say(
|
||||
"An assumed-length CHARACTER(*) function cannot be RECURSIVE"_err_en_US);
|
||||
}
|
||||
if (symbol.Rank() > 0) {
|
||||
context_.Say(
|
||||
"An assumed-length CHARACTER(*) function cannot return an array"_err_en_US);
|
||||
}
|
||||
if (symbol.attrs().test(Attr::PURE)) {
|
||||
context_.Say(
|
||||
"An assumed-length CHARACTER(*) function cannot be PURE"_err_en_US);
|
||||
}
|
||||
if (symbol.attrs().test(Attr::ELEMENTAL)) {
|
||||
context_.Say(
|
||||
"An assumed-length CHARACTER(*) function cannot be ELEMENTAL"_err_en_US);
|
||||
}
|
||||
if (const Symbol * result{FindFunctionResult(symbol)}) {
|
||||
if (result->attrs().test(Attr::POINTER)) {
|
||||
context_.Say(
|
||||
"An assumed-length CHARACTER(*) function cannot return a POINTER"_err_en_US);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
|
||||
Check(object->shape());
|
||||
Check(object->coshape());
|
||||
}
|
||||
}
|
||||
void Check(const Symbol &) const;
|
||||
void Check(const Scope &scope) const {
|
||||
for (const auto &pair : scope) {
|
||||
Check(*pair.second);
|
||||
|
@ -108,6 +70,46 @@ private:
|
|||
parser::ContextualMessages &messages_{context_.foldingContext().messages()};
|
||||
};
|
||||
|
||||
void CheckHelper::Check(const Symbol &symbol) const {
|
||||
if (context_.HasError(symbol) || symbol.has<UseDetails>() ||
|
||||
symbol.has<HostAssocDetails>()) {
|
||||
return;
|
||||
}
|
||||
auto save{messages_.SetLocation(symbol.name())};
|
||||
context_.set_location(symbol.name());
|
||||
if (const DeclTypeSpec * type{symbol.GetType()}) {
|
||||
Check(*type);
|
||||
}
|
||||
if (IsAssumedLengthCharacterFunction(symbol)) { // C723
|
||||
if (symbol.attrs().test(Attr::RECURSIVE)) {
|
||||
context_.Say(
|
||||
"An assumed-length CHARACTER(*) function cannot be RECURSIVE"_err_en_US);
|
||||
}
|
||||
if (symbol.Rank() > 0) {
|
||||
context_.Say(
|
||||
"An assumed-length CHARACTER(*) function cannot return an array"_err_en_US);
|
||||
}
|
||||
if (symbol.attrs().test(Attr::PURE)) {
|
||||
context_.Say(
|
||||
"An assumed-length CHARACTER(*) function cannot be PURE"_err_en_US);
|
||||
}
|
||||
if (symbol.attrs().test(Attr::ELEMENTAL)) {
|
||||
context_.Say(
|
||||
"An assumed-length CHARACTER(*) function cannot be ELEMENTAL"_err_en_US);
|
||||
}
|
||||
if (const Symbol * result{FindFunctionResult(symbol)}) {
|
||||
if (result->attrs().test(Attr::POINTER)) {
|
||||
context_.Say(
|
||||
"An assumed-length CHARACTER(*) function cannot return a POINTER"_err_en_US);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
|
||||
Check(object->shape());
|
||||
Check(object->coshape());
|
||||
}
|
||||
}
|
||||
|
||||
void CheckDeclarations(SemanticsContext &context) {
|
||||
CheckHelper{context}.Check();
|
||||
}
|
||||
|
|
|
@ -5047,8 +5047,6 @@ const parser::Name *DeclarationVisitor::FindComponent(
|
|||
// C764, C765
|
||||
void DeclarationVisitor::CheckInitialDataTarget(
|
||||
const Symbol &pointer, const SomeExpr &expr, SourceName source) {
|
||||
// TODO pmk: Combine into evaluate::CheckInitialDataTarget, call from
|
||||
// check-declarations.cc
|
||||
if (!evaluate::IsInitialDataTarget(expr)) {
|
||||
Say(source,
|
||||
"Pointer '%s' cannot be initialized with a reference to a designator with non-constant subscripts"_err_en_US,
|
||||
|
|
Loading…
Reference in New Issue