[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:
peter klausler 2019-09-20 09:46:00 -07:00
parent fc5d127c1c
commit 32f2ea0753
7 changed files with 88 additions and 100 deletions

View File

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

View File

@ -23,7 +23,7 @@
namespace Fortran::parser {
class ContextualMessages;
};
}
namespace Fortran::evaluate {

View File

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

View File

@ -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());
}
}

View File

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

View File

@ -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();
}

View File

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