[flang] Add IntrinsicProcTable::IsSpecificIntrinsicFunction

This replaces IsUnrestrictedSpecificIntrinsicFunction and returns
information that allows the caller to distinguish between restricted
and unrestricted intrinsics.

The new case in `resolve46.f90` used to get an internal error.

Original-commit: flang-compiler/f18@4cb1ee10b9
Reviewed-on: https://github.com/flang-compiler/f18/pull/928
Tree-same-pre-rewrite: false
This commit is contained in:
Tim Keith 2020-01-06 15:56:32 -08:00
parent 355ab9bb82
commit a5db74b614
6 changed files with 52 additions and 49 deletions

View File

@ -636,7 +636,7 @@ std::optional<Procedure> Procedure::Characterize(
[&](const semantics::ProcEntityDetails &proc)
-> std::optional<Procedure> {
if (symbol.attrs().test(semantics::Attr::INTRINSIC)) {
return intrinsics.IsUnrestrictedSpecificIntrinsicFunction(
return intrinsics.IsSpecificIntrinsicFunction(
symbol.name().ToString());
}
const semantics::ProcInterface &interface{proc.interface()};

View File

@ -1508,8 +1508,8 @@ public:
std::optional<SpecificCall> Probe(const CallCharacteristics &,
ActualArguments &, FoldingContext &, const IntrinsicProcTable &) const;
std::optional<UnrestrictedSpecificIntrinsicFunctionInterface>
IsUnrestrictedSpecificIntrinsicFunction(const std::string &) const;
std::optional<SpecificIntrinsicFunctionInterface> IsSpecificIntrinsicFunction(
const std::string &) const;
std::ostream &Dump(std::ostream &) const;
@ -1927,35 +1927,33 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
return std::nullopt;
}
std::optional<UnrestrictedSpecificIntrinsicFunctionInterface>
IntrinsicProcTable::Implementation::IsUnrestrictedSpecificIntrinsicFunction(
std::optional<SpecificIntrinsicFunctionInterface>
IntrinsicProcTable::Implementation::IsSpecificIntrinsicFunction(
const std::string &name) const {
auto specificRange{specificFuncs_.equal_range(name)};
for (auto iter{specificRange.first}; iter != specificRange.second; ++iter) {
const SpecificIntrinsicInterface &specific{*iter->second};
if (!specific.isRestrictedSpecific) {
std::string genericName{name};
if (specific.generic) {
genericName = std::string(specific.generic);
}
characteristics::FunctionResult fResult{GetSpecificType(specific.result)};
characteristics::DummyArguments args;
int dummies{specific.CountArguments()};
for (int j{0}; j < dummies; ++j) {
characteristics::DummyDataObject dummy{
GetSpecificType(specific.dummy[j].typePattern)};
dummy.intent = common::Intent::In;
args.emplace_back(
std::string{specific.dummy[j].keyword}, std::move(dummy));
}
characteristics::Procedure::Attrs attrs;
attrs.set(characteristics::Procedure::Attr::Pure)
.set(characteristics::Procedure::Attr::Elemental);
characteristics::Procedure chars{
std::move(fResult), std::move(args), attrs};
return UnrestrictedSpecificIntrinsicFunctionInterface{
std::move(chars), genericName};
std::string genericName{name};
if (specific.generic) {
genericName = std::string(specific.generic);
}
characteristics::FunctionResult fResult{GetSpecificType(specific.result)};
characteristics::DummyArguments args;
int dummies{specific.CountArguments()};
for (int j{0}; j < dummies; ++j) {
characteristics::DummyDataObject dummy{
GetSpecificType(specific.dummy[j].typePattern)};
dummy.intent = common::Intent::In;
args.emplace_back(
std::string{specific.dummy[j].keyword}, std::move(dummy));
}
characteristics::Procedure::Attrs attrs;
attrs.set(characteristics::Procedure::Attr::Pure)
.set(characteristics::Procedure::Attr::Elemental);
characteristics::Procedure chars{
std::move(fResult), std::move(args), attrs};
return SpecificIntrinsicFunctionInterface{
std::move(chars), genericName, specific.isRestrictedSpecific};
}
return std::nullopt;
}
@ -1991,10 +1989,9 @@ std::optional<SpecificCall> IntrinsicProcTable::Probe(
return DEREF(impl_).Probe(call, arguments, context, *this);
}
std::optional<UnrestrictedSpecificIntrinsicFunctionInterface>
IntrinsicProcTable::IsUnrestrictedSpecificIntrinsicFunction(
const std::string &name) const {
return DEREF(impl_).IsUnrestrictedSpecificIntrinsicFunction(name);
std::optional<SpecificIntrinsicFunctionInterface>
IntrinsicProcTable::IsSpecificIntrinsicFunction(const std::string &name) const {
return DEREF(impl_).IsSpecificIntrinsicFunction(name);
}
std::ostream &TypePattern::Dump(std::ostream &o) const {

View File

@ -41,12 +41,13 @@ struct SpecificCall {
ActualArguments arguments;
};
struct UnrestrictedSpecificIntrinsicFunctionInterface
: public characteristics::Procedure {
UnrestrictedSpecificIntrinsicFunctionInterface(
characteristics::Procedure &&p, std::string n)
: characteristics::Procedure{std::move(p)}, genericName{n} {}
struct SpecificIntrinsicFunctionInterface : public characteristics::Procedure {
SpecificIntrinsicFunctionInterface(
characteristics::Procedure &&p, std::string n, bool isRestrictedSpecific)
: characteristics::Procedure{std::move(p)}, genericName{n},
isRestrictedSpecific{isRestrictedSpecific} {}
std::string genericName;
bool isRestrictedSpecific;
// N.B. If there are multiple arguments, they all have the same type.
// All argument and result types are intrinsic types with default kinds.
};
@ -71,10 +72,9 @@ public:
std::optional<SpecificCall> Probe(
const CallCharacteristics &, ActualArguments &, FoldingContext &) const;
// Probe the intrinsics with the name of a potential unrestricted specific
// intrinsic.
std::optional<UnrestrictedSpecificIntrinsicFunctionInterface>
IsUnrestrictedSpecificIntrinsicFunction(const std::string &) const;
// Probe the intrinsics with the name of a potential specific intrinsic.
std::optional<SpecificIntrinsicFunctionInterface> IsSpecificIntrinsicFunction(
const std::string &) const;
std::ostream &Dump(std::ostream &) const;

View File

@ -210,11 +210,12 @@ MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) {
} else {
CHECK(std::holds_alternative<SymbolRef>(ref.u));
if (symbol.attrs().test(semantics::Attr::INTRINSIC)) {
if (auto interface{
context_.intrinsics().IsUnrestrictedSpecificIntrinsicFunction(
symbol.name().ToString())}) {
return Expr<SomeType>{ProcedureDesignator{SpecificIntrinsic{
symbol.name().ToString(), std::move(*interface)}}};
if (auto interface{context_.intrinsics().IsSpecificIntrinsicFunction(
symbol.name().ToString())}) {
SpecificIntrinsic intrinsic{
symbol.name().ToString(), std::move(*interface)};
intrinsic.isRestrictedSpecific = interface->isRestrictedSpecific;
return Expr<SomeType>{ProcedureDesignator{std::move(intrinsic)}};
}
} else {
return Expr<SomeType>{ProcedureDesignator{symbol}};

View File

@ -4152,12 +4152,15 @@ void DeclarationVisitor::CheckCommonBlockDerivedType(
bool DeclarationVisitor::HandleUnrestrictedSpecificIntrinsicFunction(
const parser::Name &name) {
if (context().intrinsics().IsUnrestrictedSpecificIntrinsicFunction(
name.source.ToString())) {
if (auto interface{context().intrinsics().IsSpecificIntrinsicFunction(
name.source.ToString())}) {
// Unrestricted specific intrinsic function names (e.g., "cos")
// are acceptable as procedure interfaces.
Symbol &symbol{MakeSymbol(InclusiveScope(), name.source,
Attrs{Attr::INTRINSIC, Attr::ELEMENTAL})};
Symbol &symbol{
MakeSymbol(InclusiveScope(), name.source, Attrs{Attr::INTRINSIC})};
if (interface->IsElemental()) {
symbol.attrs().set(Attr::ELEMENTAL);
}
symbol.set_details(ProcEntityDetails{});
Resolve(name, symbol);
return true;

View File

@ -3,6 +3,7 @@ program main
intrinsic :: alog10 ! a specific intrinsic name, not generic
intrinsic :: null ! a weird special case
intrinsic :: bessel_j0 ! generic intrinsic, not specific
intrinsic :: amin0
!ERROR: 'haltandcatchfire' is not a known intrinsic procedure
intrinsic :: haltandcatchfire
procedure(sin), pointer :: p
@ -11,6 +12,7 @@ program main
p => cos ! ditto, but also generic
p => tan ! a generic & an unrestricted specific, not already declared
!TODO ERROR: a restricted specific, to be caught in ass't semantics
p => amin0
p => amin1
!TODO ERROR: a generic, to be caught in ass't semantics
p => bessel_j0