Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions flang/include/flang/Evaluate/intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class IntrinsicProcTable {
bool IsIntrinsic(const std::string &) const;
bool IsIntrinsicFunction(const std::string &) const;
bool IsIntrinsicSubroutine(const std::string &) const;
bool IsDualIntrinsic(const std::string &) const;

// Inquiry intrinsics are defined in section 16.7, table 16.1
IntrinsicClass GetIntrinsicClass(const std::string &) const;
Expand Down
7 changes: 5 additions & 2 deletions flang/lib/Evaluate/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1674,7 +1674,7 @@ static const IntrinsicInterface intrinsicSubroutine[]{
{"to", SameIntOrUnsigned, Rank::elemental, Optionality::required,
common::Intent::Out},
{"topos", AnyInt}},
{}, Rank::elemental, IntrinsicClass::elementalSubroutine}, // elemental
{}, Rank::elemental, IntrinsicClass::elementalSubroutine},
{"random_init",
{{"repeatable", AnyLogical, Rank::scalar},
{"image_distinct", AnyLogical, Rank::scalar}},
Expand Down Expand Up @@ -2903,7 +2903,7 @@ bool IntrinsicProcTable::Implementation::IsDualIntrinsic(
// Collection for some intrinsics with function and subroutine form,
// in order to pass the semantic check.
static const std::string dualIntrinsic[]{{"chdir"}, {"etime"}, {"fseek"},
{"ftell"}, {"getcwd"}, {"hostnm"}, {"putenv"s}, {"rename"}, {"second"},
{"ftell"}, {"getcwd"}, {"hostnm"}, {"putenv"}, {"rename"}, {"second"},
{"system"}, {"unlink"}};
return llvm::is_contained(dualIntrinsic, name);
}
Expand Down Expand Up @@ -3766,6 +3766,9 @@ bool IntrinsicProcTable::IsIntrinsicFunction(const std::string &name) const {
bool IntrinsicProcTable::IsIntrinsicSubroutine(const std::string &name) const {
return DEREF(impl_.get()).IsIntrinsicSubroutine(name);
}
bool IntrinsicProcTable::IsDualIntrinsic(const std::string &name) const {
return DEREF(impl_.get()).IsDualIntrinsic(name);
}

IntrinsicClass IntrinsicProcTable::GetIntrinsicClass(
const std::string &name) const {
Expand Down
23 changes: 14 additions & 9 deletions flang/lib/Semantics/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3644,19 +3644,24 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
Say(callSite,
"Assumed-length character function must be defined with a length to be called"_err_en_US);
}
if (!chars->IsPure()) {
if (const semantics::Scope *pure{semantics::FindPureProcedureContaining(
context_.FindScope(callSite))}) {
std::string name;
if (procSymbol) {
name = "'"s + procSymbol->name().ToString() + "'";
} else if (const auto *intrinsic{proc.GetSpecificIntrinsic()}) {
name = "'"s + intrinsic->name + "'";
}
Say(callSite,
"Procedure %s referenced in pure subprogram '%s' must be pure too"_err_en_US,
name, DEREF(pure->symbol()).name());
}
}
ok &= semantics::CheckArguments(*chars, arguments, context_,
context_.FindScope(callSite), treatExternalAsImplicit,
/*ignoreImplicitVsExplicit=*/false, specificIntrinsic);
}
if (procSymbol && !IsPureProcedure(*procSymbol)) {
if (const semantics::Scope *
pure{semantics::FindPureProcedureContaining(
context_.FindScope(callSite))}) {
Say(callSite,
"Procedure '%s' referenced in pure subprogram '%s' must be pure too"_err_en_US,
procSymbol->name(), DEREF(pure->symbol()).name());
}
}
if (ok && !treatExternalAsImplicit && procSymbol &&
!(chars && chars->HasExplicitInterface())) {
if (const Symbol *global{FindGlobal(*procSymbol)};
Expand Down
3 changes: 2 additions & 1 deletion flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5733,7 +5733,8 @@ void DeclarationVisitor::DeclareIntrinsic(const parser::Name &name) {
}
}
if (!symbol.test(Symbol::Flag::Function) &&
!symbol.test(Symbol::Flag::Subroutine)) {
!symbol.test(Symbol::Flag::Subroutine) &&
!context().intrinsics().IsDualIntrinsic(name.source.ToString())) {
if (context().intrinsics().IsIntrinsicFunction(name.source.ToString())) {
symbol.set(Symbol::Flag::Function);
} else if (context().intrinsics().IsIntrinsicSubroutine(
Expand Down
11 changes: 11 additions & 0 deletions flang/test/Semantics/bug157124.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
! RUN: %python %S/test_errors.py %s %flang_fc1
pure subroutine puresub
intrinsic sleep, chdir, get_command
character(80) str
!ERROR: Procedure 'impureexternal' referenced in pure subprogram 'puresub' must be pure too
call impureExternal ! implicit interface
!ERROR: Procedure 'sleep' referenced in pure subprogram 'puresub' must be pure too
call sleep(1) ! intrinsic subroutine, debatably impure
!ERROR: Procedure 'chdir' referenced in pure subprogram 'puresub' must be pure too
call chdir('.') ! "dual" function/subroutine, impure
end