[flang-commits] [flang] [flang] Fix explanatory messages for generic resolution error (PR #183565)

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Thu Feb 26 08:25:00 PST 2026


https://github.com/klausler created https://github.com/llvm/llvm-project/pull/183565

The compiler emits messages to explain why each of a generic procedure's specific procedures is not a match for a given set of actual arguments.  In the case of specific procedures with PASS arguments in derived type procedure bindings or procedure components, these explanatory messages are often bogus, because the re-analysis didn't adjust the actual arguments to account for the PASS argument.  Fix.

>From 0c2d11575113f22a6cd1eceea62a3ec1ae940090 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Thu, 26 Feb 2026 07:15:16 -0800
Subject: [PATCH] [flang] Fix explanatory messages for generic resolution error

The compiler emits messages to explain why each of a generic
procedure's specific procedures is not a match for a given set
of actual arguments.  In the case of specific procedures with
PASS arguments in derived type procedure bindings or procedure
components, these explanatory messages are often bogus, because
the re-analysis didn't adjust the actual arguments to account
for the PASS argument.  Fix.
---
 flang/include/flang/Semantics/expression.h |  3 ++-
 flang/lib/Semantics/expression.cpp         | 20 ++++++++++++------
 flang/test/Semantics/bug2295.f90           | 24 ++++++++++++++++++++++
 3 files changed, 40 insertions(+), 7 deletions(-)
 create mode 100644 flang/test/Semantics/bug2295.f90

diff --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h
index 0a78ac019972e..490399aa03ff8 100644
--- a/flang/include/flang/Semantics/expression.h
+++ b/flang/include/flang/Semantics/expression.h
@@ -377,7 +377,8 @@ class ExpressionAnalyzer {
       const AdjustActuals &, bool isSubroutine, SymbolVector &&tried,
       bool mightBeStructureConstructor = false);
   void EmitGenericResolutionError(const Symbol &, bool dueToNullActuals,
-      bool isSubroutine, ActualArguments &, const SymbolVector &);
+      bool isSubroutine, ActualArguments &, const SymbolVector &,
+      const AdjustActuals &);
   const Symbol &AccessSpecific(
       const Symbol &originalGeneric, const Symbol &specific);
   std::optional<CalleeAndArguments> GetCalleeAndArguments(const parser::Name &,
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 49c092b306e25..bb77622db8084 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -2605,7 +2605,7 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
           sym = result.specific;
           if (!sym) {
             EmitGenericResolutionError(generic, result.failedDueToAmbiguity,
-                isSubroutine, arguments, result.tried);
+                isSubroutine, arguments, result.tried, adjustment);
             return std::nullopt;
           }
           // re-resolve the name to the specific binding
@@ -3145,7 +3145,7 @@ const Symbol &ExpressionAnalyzer::AccessSpecific(
 
 void ExpressionAnalyzer::EmitGenericResolutionError(const Symbol &symbol,
     bool dueToAmbiguity, bool isSubroutine, ActualArguments &arguments,
-    const SymbolVector &tried) {
+    const SymbolVector &tried, const AdjustActuals &adjustment) {
   if (auto *msg{Say(dueToAmbiguity
               ? "The actual arguments to the generic procedure '%s' matched multiple specific procedures, perhaps due to use of NULL() without MOLD= or an actual procedure with an implicit interface"_err_en_US
               : semantics::IsGenericDefinedOp(symbol)
@@ -3158,7 +3158,14 @@ void ExpressionAnalyzer::EmitGenericResolutionError(const Symbol &symbol,
       if (auto procChars{characteristics::Procedure::Characterize(
               specific, GetFoldingContext())}) {
         if (procChars->HasExplicitInterface()) {
-          auto reasons{semantics::CheckExplicitInterface(*procChars, arguments,
+          ActualArguments *actuals{&arguments};
+          ActualArguments localActuals{arguments};
+          if (specific.has<semantics::ProcBindingDetails>() &&
+              adjustment.has_value() && (*adjustment)(specific, localActuals)) {
+            actuals = &localActuals;
+            ;
+          }
+          auto reasons{semantics::CheckExplicitInterface(*procChars, *actuals,
               context_, /*scope=*/nullptr, /*intrinsic=*/nullptr,
               /*allocActualArgumentConversions=*/false,
               /*extentErrors=*/false,
@@ -3256,8 +3263,9 @@ auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name,
           std::move(specificCall->arguments)};
     } else {
       if (isGenericInterface) {
-        EmitGenericResolutionError(
-            *symbol, dueToAmbiguity, isSubroutine, arguments, tried);
+        AdjustActuals noAdjustment;
+        EmitGenericResolutionError(*symbol, dueToAmbiguity, isSubroutine,
+            arguments, tried, noAdjustment);
       }
       return std::nullopt;
     }
@@ -5203,7 +5211,7 @@ const Symbol *ArgumentAnalyzer::FindBoundOp(parser::CharBlock oprName,
         *isAmbiguous = result.failedDueToAmbiguity;
       }
       context_.EmitGenericResolutionError(*generic, result.failedDueToAmbiguity,
-          isSubroutine, actuals_, result.tried);
+          isSubroutine, actuals_, result.tried, adjustment);
     }
   }
   return nullptr;
diff --git a/flang/test/Semantics/bug2295.f90 b/flang/test/Semantics/bug2295.f90
new file mode 100644
index 0000000000000..6db02a1a07a6d
--- /dev/null
+++ b/flang/test/Semantics/bug2295.f90
@@ -0,0 +1,24 @@
+!RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s
+module m
+  type t
+   contains
+    procedure :: s1, s2
+    generic :: g => s1, s2
+  end type
+ contains
+  subroutine s1(this, x, j)
+    class(t) this
+  end
+  subroutine s2(this, z, y)
+    class(t) this
+  end
+  subroutine test(that)
+    class(t) that
+!CHECK: error: No specific subroutine of generic 'g' matches the actual arguments
+!CHECK: Specific procedure 's1' does not match the actual arguments because
+!CHECK: Argument keyword 'z=' is not recognized for this procedure reference
+!CHECK: Specific procedure 's2' does not match the actual arguments because
+!CHECK: Keyword argument 'z=' has already been specified positionally (#2) in this procedure reference
+    call that%g(1., z=2.)
+  end
+end



More information about the flang-commits mailing list