forked from OSchip/llvm-project
[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:
parent
c1a9cdb34f
commit
4f2c8fae65
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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:"
|
||||||
|
|
Loading…
Reference in New Issue