Skip to content

Commit ed5e6b8

Browse files
authored
[flang] Catch calls to impure intrinsics from PURE subprograms (llvm#160947)
The code in expression semantics that catches a call to an impure procedure in a PURE context misses calls to impure intrinsics, since their designators have a SpecificIntrinsic rather than a Symbol. Replace the current check with a new one that uses the characteristics of the called procedure, which works for both intrinsic and non-intrinsic cases. Testing this change revealed that an explicit INTRINSIC statement wasn't doing the right thing for extension "dual" intrinsics that can be called as either a function or as a subroutine; the use of an INTRINSIC statement would disallow its use as a subroutine. I've fixed that here as well. Fixes llvm#157124.
1 parent 52afb8d commit ed5e6b8

File tree

5 files changed

+33
-12
lines changed

5 files changed

+33
-12
lines changed

flang/include/flang/Evaluate/intrinsics.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class IntrinsicProcTable {
8686
bool IsIntrinsic(const std::string &) const;
8787
bool IsIntrinsicFunction(const std::string &) const;
8888
bool IsIntrinsicSubroutine(const std::string &) const;
89+
bool IsDualIntrinsic(const std::string &) const;
8990

9091
// Inquiry intrinsics are defined in section 16.7, table 16.1
9192
IntrinsicClass GetIntrinsicClass(const std::string &) const;

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,7 +1674,7 @@ static const IntrinsicInterface intrinsicSubroutine[]{
16741674
{"to", SameIntOrUnsigned, Rank::elemental, Optionality::required,
16751675
common::Intent::Out},
16761676
{"topos", AnyInt}},
1677-
{}, Rank::elemental, IntrinsicClass::elementalSubroutine}, // elemental
1677+
{}, Rank::elemental, IntrinsicClass::elementalSubroutine},
16781678
{"random_init",
16791679
{{"repeatable", AnyLogical, Rank::scalar},
16801680
{"image_distinct", AnyLogical, Rank::scalar}},
@@ -2903,7 +2903,7 @@ bool IntrinsicProcTable::Implementation::IsDualIntrinsic(
29032903
// Collection for some intrinsics with function and subroutine form,
29042904
// in order to pass the semantic check.
29052905
static const std::string dualIntrinsic[]{{"chdir"}, {"etime"}, {"fseek"},
2906-
{"ftell"}, {"getcwd"}, {"hostnm"}, {"putenv"s}, {"rename"}, {"second"},
2906+
{"ftell"}, {"getcwd"}, {"hostnm"}, {"putenv"}, {"rename"}, {"second"},
29072907
{"system"}, {"unlink"}};
29082908
return llvm::is_contained(dualIntrinsic, name);
29092909
}
@@ -3766,6 +3766,9 @@ bool IntrinsicProcTable::IsIntrinsicFunction(const std::string &name) const {
37663766
bool IntrinsicProcTable::IsIntrinsicSubroutine(const std::string &name) const {
37673767
return DEREF(impl_.get()).IsIntrinsicSubroutine(name);
37683768
}
3769+
bool IntrinsicProcTable::IsDualIntrinsic(const std::string &name) const {
3770+
return DEREF(impl_.get()).IsDualIntrinsic(name);
3771+
}
37693772

37703773
IntrinsicClass IntrinsicProcTable::GetIntrinsicClass(
37713774
const std::string &name) const {

flang/lib/Semantics/expression.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3644,19 +3644,24 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
36443644
Say(callSite,
36453645
"Assumed-length character function must be defined with a length to be called"_err_en_US);
36463646
}
3647+
if (!chars->IsPure()) {
3648+
if (const semantics::Scope *pure{semantics::FindPureProcedureContaining(
3649+
context_.FindScope(callSite))}) {
3650+
std::string name;
3651+
if (procSymbol) {
3652+
name = "'"s + procSymbol->name().ToString() + "'";
3653+
} else if (const auto *intrinsic{proc.GetSpecificIntrinsic()}) {
3654+
name = "'"s + intrinsic->name + "'";
3655+
}
3656+
Say(callSite,
3657+
"Procedure %s referenced in pure subprogram '%s' must be pure too"_err_en_US,
3658+
name, DEREF(pure->symbol()).name());
3659+
}
3660+
}
36473661
ok &= semantics::CheckArguments(*chars, arguments, context_,
36483662
context_.FindScope(callSite), treatExternalAsImplicit,
36493663
/*ignoreImplicitVsExplicit=*/false, specificIntrinsic);
36503664
}
3651-
if (procSymbol && !IsPureProcedure(*procSymbol)) {
3652-
if (const semantics::Scope *
3653-
pure{semantics::FindPureProcedureContaining(
3654-
context_.FindScope(callSite))}) {
3655-
Say(callSite,
3656-
"Procedure '%s' referenced in pure subprogram '%s' must be pure too"_err_en_US,
3657-
procSymbol->name(), DEREF(pure->symbol()).name());
3658-
}
3659-
}
36603665
if (ok && !treatExternalAsImplicit && procSymbol &&
36613666
!(chars && chars->HasExplicitInterface())) {
36623667
if (const Symbol *global{FindGlobal(*procSymbol)};

flang/lib/Semantics/resolve-names.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5726,7 +5726,8 @@ void DeclarationVisitor::DeclareIntrinsic(const parser::Name &name) {
57265726
}
57275727
}
57285728
if (!symbol.test(Symbol::Flag::Function) &&
5729-
!symbol.test(Symbol::Flag::Subroutine)) {
5729+
!symbol.test(Symbol::Flag::Subroutine) &&
5730+
!context().intrinsics().IsDualIntrinsic(name.source.ToString())) {
57305731
if (context().intrinsics().IsIntrinsicFunction(name.source.ToString())) {
57315732
symbol.set(Symbol::Flag::Function);
57325733
} else if (context().intrinsics().IsIntrinsicSubroutine(

flang/test/Semantics/bug157124.f90

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1
2+
pure subroutine puresub
3+
intrinsic sleep, chdir, get_command
4+
character(80) str
5+
!ERROR: Procedure 'impureexternal' referenced in pure subprogram 'puresub' must be pure too
6+
call impureExternal ! implicit interface
7+
!ERROR: Procedure 'sleep' referenced in pure subprogram 'puresub' must be pure too
8+
call sleep(1) ! intrinsic subroutine, debatably impure
9+
!ERROR: Procedure 'chdir' referenced in pure subprogram 'puresub' must be pure too
10+
call chdir('.') ! "dual" function/subroutine, impure
11+
end

0 commit comments

Comments
 (0)