[flang-commits] [flang] [Flang] Avoid crash resolving restricted specific intrinsics (PR #217852)
via flang-commits
flang-commits at lists.llvm.org
Sun Aug 30 02:28:02 PDT 2026
https://github.com/keepyixiao updated https://github.com/llvm/llvm-project/pull/217852
>From 02912de83ff65fe50bcf1fc073295211dc6d0b28 Mon Sep 17 00:00:00 2001
From: yixiao <yixiao at hygon.cn>
Date: Fri, 21 Aug 2026 16:58:50 +0800
Subject: [PATCH] [Flang] Avoid crash resolving restricted specific intrinsics
Name resolution assumed that every specific intrinsic function handled in
a procedure context was unrestricted and had a numeric result. An
undeclared LLT used as a procedure pointer target therefore triggered a
CHECK because LLT is restricted and returns LOGICAL.
Rename the handler to reflect that it resolves both restricted and
unrestricted specific intrinsic functions. Preserve result types only
for unrestricted intrinsics; restricted intrinsics retain an untyped
symbol so later semantic checks can issue the appropriate diagnostic.
---
flang/lib/Semantics/resolve-names.cpp | 27 ++++++++++++---------
flang/test/Semantics/resolve46.f90 | 34 +++++++++++++++++++++++++++
2 files changed, 50 insertions(+), 11 deletions(-)
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 17abba65bdae5..707e87fe7caa0 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1329,7 +1329,7 @@ class DeclarationVisitor : public ArraySpecVisitor,
const parser::TypeParamValue &, common::TypeParamAttr attr);
Attrs HandleSaveName(const SourceName &, Attrs);
void AddSaveName(std::set<SourceName> &, const SourceName &);
- bool HandleUnrestrictedSpecificIntrinsicFunction(const parser::Name &);
+ bool HandleSpecificIntrinsicFunction(const parser::Name &);
const parser::Name *FindComponent(const parser::Name *, const parser::Name &);
void Initialization(const parser::Name &, const parser::Initialization &,
bool inComponentDecl);
@@ -8274,10 +8274,13 @@ Symbol &DeclarationVisitor::MakeCommonBlockSymbol(
}
bool DeclarationVisitor::NameIsKnownOrIntrinsic(const parser::Name &name) {
- return FindSymbol(name) || HandleUnrestrictedSpecificIntrinsicFunction(name);
+ return FindSymbol(name) || HandleSpecificIntrinsicFunction(name);
}
-bool DeclarationVisitor::HandleUnrestrictedSpecificIntrinsicFunction(
+// Create a symbol for a specific intrinsic function. Unrestricted names
+// receive their result type here; restricted names are kept typeless so
+// that later semantic checks can diagnose their invalid use.
+bool DeclarationVisitor::HandleSpecificIntrinsicFunction(
const parser::Name &name) {
if (auto interface{context().intrinsics().IsSpecificIntrinsicFunction(
name.source.ToString())}) {
@@ -8286,17 +8289,19 @@ bool DeclarationVisitor::HandleUnrestrictedSpecificIntrinsicFunction(
// INTRINSIC flag will cause this symbol to have a complete interface
// recreated for it later on demand, but capturing its result type here
// will make GetType() return a correct result without having to
- // probe the intrinsics table again.
+ // probe the intrinsics table again. Restricted specific intrinsic
+ // function names are also resolved here so that their use can be
+ // diagnosed later, but they do not need a result type.
Symbol &symbol{MakeSymbol(InclusiveScope(), name.source, Attrs{})};
SetImplicitAttr(symbol, Attr::INTRINSIC);
- CHECK(interface->functionResult.has_value());
- evaluate::DynamicType dyType{
- DEREF(interface->functionResult->GetTypeAndShape()).type()};
- CHECK(common::IsNumericTypeCategory(dyType.category()));
- const DeclTypeSpec &typeSpec{
- MakeNumericType(dyType.category(), dyType.kind())};
ProcEntityDetails details;
- details.set_type(typeSpec);
+ if (!interface->isRestrictedSpecific) {
+ CHECK(interface->functionResult.has_value());
+ evaluate::DynamicType dyType{
+ DEREF(interface->functionResult->GetTypeAndShape()).type()};
+ CHECK(common::IsNumericTypeCategory(dyType.category()));
+ details.set_type(MakeNumericType(dyType.category(), dyType.kind()));
+ }
symbol.set_details(std::move(details));
symbol.set(Symbol::Flag::Function);
if (interface->IsElemental()) {
diff --git a/flang/test/Semantics/resolve46.f90 b/flang/test/Semantics/resolve46.f90
index d473226edaabe..45e4f930f664a 100644
--- a/flang/test/Semantics/resolve46.f90
+++ b/flang/test/Semantics/resolve46.f90
@@ -45,3 +45,37 @@ end function chrcmp
!ERROR: 'llt' is not an unrestricted specific intrinsic procedure
u => llt
end program main
+
+! A restricted specific intrinsic used with an implicit procedure interface
+! must be diagnosed even without an explicit INTRINSIC statement.
+subroutine testRestrictedSpecificWithoutIntrinsicStmt
+ procedure(), pointer :: p
+ !ERROR: 'llt' is not an unrestricted specific intrinsic procedure
+ p => llt
+end subroutine
+
+! A restricted specific intrinsic used in a procedure pointer assignment
+! must be diagnosed even without an explicit INTRINSIC statement.
+subroutine testRestrictedSpecificWithoutIntrinsicStmt1
+ !ERROR: 'llt' is not an unrestricted specific intrinsic procedure
+ u => llt
+end subroutine
+
+! Restricted intrinsic used as a procedure pointer interface.
+subroutine testRestrictedSpecificInterfaceWithoutIntrinsicStmt
+ !ERROR: Intrinsic procedure 'llt' is not an unrestricted specific intrinsic permitted for use as the definition of the interface to procedure pointer 'p'
+ procedure(llt), pointer :: p
+end subroutine
+
+! Restricted intrinsic with a numeric result.
+subroutine testRestrictedSpecificIntegerWithoutIntrinsicStmt
+ procedure(), pointer :: p
+ !ERROR: 'amin0' is not an unrestricted specific intrinsic procedure
+ p => amin0
+end subroutine
+
+! A restricted intrinsic remains valid when used as an ordinary function call.
+subroutine testRestrictedSpecificCallWithoutIntrinsicStmt
+ logical :: result
+ result = llt('a', 'b')
+end subroutine
More information about the flang-commits
mailing list