[flang-commits] [flang] ed5e6b8 - [flang] Catch calls to impure intrinsics from PURE subprograms (#160947)
via flang-commits
flang-commits at lists.llvm.org
Tue Sep 30 10:36:56 PDT 2025
Author: Peter Klausler
Date: 2025-09-30T10:36:52-07:00
New Revision: ed5e6b87013485c7b16d825e0cbf556a1e7e3e19
URL: https://github.com/llvm/llvm-project/commit/ed5e6b87013485c7b16d825e0cbf556a1e7e3e19
DIFF: https://github.com/llvm/llvm-project/commit/ed5e6b87013485c7b16d825e0cbf556a1e7e3e19.diff
LOG: [flang] Catch calls to impure intrinsics from PURE subprograms (#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 https://github.com/llvm/llvm-project/issues/157124.
Added:
flang/test/Semantics/bug157124.f90
Modified:
flang/include/flang/Evaluate/intrinsics.h
flang/lib/Evaluate/intrinsics.cpp
flang/lib/Semantics/expression.cpp
flang/lib/Semantics/resolve-names.cpp
Removed:
################################################################################
diff --git a/flang/include/flang/Evaluate/intrinsics.h b/flang/include/flang/Evaluate/intrinsics.h
index dbe1ba7fe7ec1..fc1c8b2ba6ab7 100644
--- a/flang/include/flang/Evaluate/intrinsics.h
+++ b/flang/include/flang/Evaluate/intrinsics.h
@@ -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;
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index c7f174f7989dd..fe679da4ff98b 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -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}},
@@ -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);
}
@@ -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 {
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 3f048ab6f7a4d..836500145e4a2 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -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)};
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index ef0b8cdfd827b..d1150a9eb67f4 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -5726,7 +5726,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(
diff --git a/flang/test/Semantics/bug157124.f90 b/flang/test/Semantics/bug157124.f90
new file mode 100644
index 0000000000000..92326dc9e7b69
--- /dev/null
+++ b/flang/test/Semantics/bug157124.f90
@@ -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
More information about the flang-commits
mailing list