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

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


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

<details>
<summary>Changes</summary>

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.

---
Full diff: https://github.com/llvm/llvm-project/pull/183565.diff


3 Files Affected:

- (modified) flang/include/flang/Semantics/expression.h (+2-1) 
- (modified) flang/lib/Semantics/expression.cpp (+14-6) 
- (added) flang/test/Semantics/bug2295.f90 (+24) 


``````````diff
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

``````````

</details>


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


More information about the flang-commits mailing list