[flang] Fix source provenance of .NOT., add ALLOCATED intrinsic

Original-commit: flang-compiler/f18@e7e0de9e0d
Reviewed-on: https://github.com/flang-compiler/f18/pull/505
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-06-19 11:50:07 -07:00
parent c1a9cdb34f
commit 4f2c8fae65
5 changed files with 49 additions and 34 deletions

View File

@ -245,6 +245,8 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"aint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal}, {"aint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal},
{"all", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical, {"all", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
Rank::dimReduced}, Rank::dimReduced},
{"allocated", {{"array", Anything, Rank::array}}, DefaultLogical},
{"allocated", {{"scalar", Anything, Rank::scalar}}, DefaultLogical},
{"anint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal}, {"anint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal},
{"any", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical, {"any", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
Rank::dimReduced}, Rank::dimReduced},
@ -618,7 +620,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
// NUM_IMAGES, STOPPED_IMAGES, TEAM_NUMBER, THIS_IMAGE, // NUM_IMAGES, STOPPED_IMAGES, TEAM_NUMBER, THIS_IMAGE,
// COSHAPE // COSHAPE
// TODO: Object characteristic inquiry functions // TODO: Object characteristic inquiry functions
// ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, IS_CONTIGUOUS, // ASSOCIATED, EXTENDS_TYPE_OF, IS_CONTIGUOUS,
// SAME_TYPE, STORAGE_SIZE // SAME_TYPE, STORAGE_SIZE
// TODO: Type inquiry intrinsic functions - these return constants // TODO: Type inquiry intrinsic functions - these return constants
// BIT_SIZE, DIGITS, EPSILON, HUGE, KIND, MAXEXPONENT, MINEXPONENT, // BIT_SIZE, DIGITS, EPSILON, HUGE, KIND, MAXEXPONENT, MINEXPONENT,
@ -1384,6 +1386,40 @@ SpecificCall IntrinsicProcTable::Implementation::HandleNull(
std::move(arguments)}; std::move(arguments)};
} }
// Applies any semantic checks peculiar to an intrinsic.
static bool ApplySpecificChecks(
SpecificCall &call, parser::ContextualMessages &messages) {
bool ok{true};
const std::string &name{call.specificIntrinsic.name};
if (name == "allocated") {
if (const auto &arg{call.arguments[0]}) {
if (const auto *expr{arg->UnwrapExpr()}) {
if (const Symbol * symbol{GetLastSymbol(*expr)}) {
ok = symbol->has<semantics::ObjectEntityDetails>() &&
symbol->attrs().test(semantics::Attr::ALLOCATABLE);
}
}
}
if (!ok) {
messages.Say(
"Argument of ALLOCATED() must be an ALLOCATABLE object or component"_err_en_US);
}
} else if (name == "present") {
if (const auto &arg{call.arguments[0]}) {
if (const auto *expr{arg->UnwrapExpr()}) {
if (const Symbol * symbol{UnwrapWholeSymbolDataRef(*expr)}) {
ok = symbol->attrs().test(semantics::Attr::OPTIONAL);
}
}
}
if (!ok) {
messages.Say(
"Argument of PRESENT() must be the name of an OPTIONAL dummy argument"_err_en_US);
}
}
return ok;
};
// Probe the configured intrinsic procedure pattern tables in search of a // Probe the configured intrinsic procedure pattern tables in search of a
// match for a given procedure reference. // match for a given procedure reference.
std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe( std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
@ -1417,21 +1453,7 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
CHECK(localBuffer.empty()); CHECK(localBuffer.empty());
if (auto specificCall{ if (auto specificCall{
iter->second->Match(call, defaults_, arguments, localContext)}) { iter->second->Match(call, defaults_, arguments, localContext)}) {
// Apply any semantic checks peculiar to the intrinsic ApplySpecificChecks(*specificCall, localMessages);
if (call.name == "present") {
bool ok{false};
if (const auto &arg{specificCall->arguments[0]}) {
if (const auto *expr{arg->UnwrapExpr()}) {
if (const Symbol * symbol{UnwrapWholeSymbolDataRef(*expr)}) {
ok = symbol->attrs().test(semantics::Attr::OPTIONAL);
}
}
}
if (!ok) {
localMessages.Say(
"Argument of PRESENT() must be the name of an OPTIONAL dummy argument"_err_en_US);
}
}
if (finalBuffer != nullptr) { if (finalBuffer != nullptr) {
finalBuffer->Annex(std::move(localBuffer)); finalBuffer->Annex(std::move(localBuffer));
} }

View File

@ -1799,18 +1799,12 @@ constexpr struct AndOperand {
} andOperand; } andOperand;
inline std::optional<Expr> AndOperand::Parse(ParseState &state) { inline std::optional<Expr> AndOperand::Parse(ParseState &state) {
static constexpr auto op{attempt(".NOT."_tok)}; static constexpr auto notOp{attempt(".NOT."_tok >> andOperand)};
int complements{0}; if (std::optional<Expr> negation{notOp.Parse(state)}) {
while (op.Parse(state)) { return Expr{Expr::NOT{std::move(*negation)}};
++complements; } else {
return level4Expr.Parse(state);
} }
std::optional<Expr> result{level4Expr.Parse(state)};
if (result.has_value()) {
while (complements-- > 0) {
result = Expr{Expr::NOT{std::move(*result)}};
}
}
return result;
} }
// R1015 or-operand -> [or-operand and-op] and-operand // R1015 or-operand -> [or-operand and-op] and-operand
@ -1820,7 +1814,8 @@ constexpr struct OrOperand {
using resultType = Expr; using resultType = Expr;
constexpr OrOperand() {} constexpr OrOperand() {}
static inline std::optional<Expr> Parse(ParseState &state) { static inline std::optional<Expr> Parse(ParseState &state) {
std::optional<Expr> result{andOperand.Parse(state)}; static constexpr auto operand{sourced(andOperand)};
std::optional<Expr> result{operand.Parse(state)};
if (result) { if (result) {
auto source{result->source}; auto source{result->source};
std::function<Expr(Expr &&)> logicalAnd{[&result](Expr &&right) { std::function<Expr(Expr &&)> logicalAnd{[&result](Expr &&right) {

View File

@ -1613,8 +1613,6 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::NOT &x) {
return {AsGenericExpr(LogicalNegation(std::move(lx)))}; return {AsGenericExpr(LogicalNegation(std::move(lx)))};
}, },
[&](auto &&) -> MaybeExpr { [&](auto &&) -> MaybeExpr {
// TODO: accept INTEGER operand and maybe typeless
// if not overridden
Say("Operand of .NOT. must be LOGICAL"_err_en_US); Say("Operand of .NOT. must be LOGICAL"_err_en_US);
return std::nullopt; return std::nullopt;
}, },
@ -1871,7 +1869,7 @@ MaybeExpr ExpressionAnalyzer::ExprOrVariable(const PARSED &x) {
if constexpr (std::is_same_v<PARSED, parser::Expr>) { if constexpr (std::is_same_v<PARSED, parser::Expr>) {
// Analyze the expression in a specified source position context for // Analyze the expression in a specified source position context for
// better error reporting. // better error reporting.
auto save{GetFoldingContext().messages().SetLocation(x.source)}; auto save{GetContextualMessages().SetLocation(x.source)};
result = Analyze(x.u); result = Analyze(x.u);
} else { } else {
result = Analyze(x.u); result = Analyze(x.u);

View File

@ -185,10 +185,10 @@ public:
return result; return result;
} }
template<typename A> MaybeExpr Analyze(const parser::Constant<A> &x) { template<typename A> MaybeExpr Analyze(const parser::Constant<A> &x) {
auto result{Analyze(x.thing)};
if (result.has_value()) {
auto save{ auto save{
GetFoldingContext().messages().SetLocation(FindSourceLocation(x))}; GetFoldingContext().messages().SetLocation(FindSourceLocation(x))};
auto result{Analyze(x.thing)};
if (result.has_value()) {
*result = Fold(GetFoldingContext(), std::move(*result)); *result = Fold(GetFoldingContext(), std::move(*result));
if (!IsConstantExpr(*result)) { if (!IsConstantExpr(*result)) {
SayAt(x, "Must be a constant value"_err_en_US); SayAt(x, "Must be a constant value"_err_en_US);

View File

@ -60,7 +60,7 @@ for src in "$@"; do
exit 1 exit 1
fi fi
# The first three bytes of the file are a UTF-8 BOM # The first three bytes of the file are a UTF-8 BOM
sed '/^.!mod\$/d' $temp/$mod > $actual sed '/^[^!]*!mod\$/d' $temp/$mod > $actual
sed '1,/^!Expect: '"$mod"'/d' $src | sed -e '/^$/,$d' -e 's/^! *//' > $expect sed '1,/^!Expect: '"$mod"'/d' $src | sed -e '/^$/,$d' -e 's/^! *//' > $expect
if ! diff -U999999 $expect $actual > $diffs; then if ! diff -U999999 $expect $actual > $diffs; then
echo "Module file $mod differs from expected:" echo "Module file $mod differs from expected:"