Skip to content

[flang] Fix spurious error message due to inaccessible generic binding #122810

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 14, 2025

Conversation

klausler
Copy link
Contributor

Generic operator/assignment checks for distinguishable specific procedures must ignore inaccessible generic bindings.

Fixes #122764.

Generic operator/assignment checks for distinguishable specific
procedures must ignore inaccessible generic bindings.

Fixes llvm#122764.
@klausler klausler requested a review from DanielCChen January 13, 2025 22:27
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics labels Jan 13, 2025
@llvmbot
Copy link
Member

llvmbot commented Jan 13, 2025

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

Generic operator/assignment checks for distinguishable specific procedures must ignore inaccessible generic bindings.

Fixes #122764.


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

4 Files Affected:

  • (modified) flang/include/flang/Semantics/tools.h (+2)
  • (modified) flang/lib/Semantics/check-declarations.cpp (+3)
  • (modified) flang/lib/Semantics/tools.cpp (+23-17)
  • (added) flang/test/Semantics/generic12.f90 (+30)
diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index 96d4dbb2acaa11..1ec78acbd73c2d 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -240,6 +240,8 @@ inline bool NeedCUDAAlloc(const Symbol &sym) {
 const Scope *FindCUDADeviceContext(const Scope *);
 std::optional<common::CUDADataAttr> GetCUDADataAttr(const Symbol *);
 
+bool IsAccessible(const Symbol &, const Scope &);
+
 // Return an error if a symbol is not accessible from a scope
 std::optional<parser::MessageFormattedText> CheckAccessibleSymbol(
     const Scope &, const Symbol &);
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 99c6e16c4260f1..a7e6cf32e85eea 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -2742,6 +2742,9 @@ void CheckHelper::CheckBlockData(const Scope &scope) {
 void CheckHelper::CheckGenericOps(const Scope &scope) {
   DistinguishabilityHelper helper{context_};
   auto addSpecifics{[&](const Symbol &generic) {
+    if (!IsAccessible(generic, scope)) {
+      return;
+    }
     const auto *details{generic.GetUltimate().detailsIf<GenericDetails>()};
     if (!details) {
       // Not a generic; ensure characteristics are defined if a function.
diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index 9e180605c1b3bd..627d8b35353f54 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -544,9 +544,7 @@ const Symbol *FindOverriddenBinding(
           if (const Symbol *
               overridden{parentScope->FindComponent(symbol.name())}) {
             // 7.5.7.3 p1: only accessible bindings are overridden
-            if (!overridden->attrs().test(Attr::PRIVATE) ||
-                FindModuleContaining(overridden->owner()) ==
-                    FindModuleContaining(symbol.owner())) {
+            if (IsAccessible(*overridden, symbol.owner())) {
               return overridden;
             } else if (overridden->attrs().test(Attr::DEFERRED)) {
               isInaccessibleDeferred = true;
@@ -1120,23 +1118,31 @@ std::optional<common::CUDADataAttr> GetCUDADataAttr(const Symbol *symbol) {
   return object ? object->cudaDataAttr() : std::nullopt;
 }
 
+bool IsAccessible(const Symbol &original, const Scope &scope) {
+  const Symbol &ultimate{original.GetUltimate()};
+  if (ultimate.attrs().test(Attr::PRIVATE)) {
+    const Scope *module{FindModuleContaining(ultimate.owner())};
+    return !module || module->Contains(scope);
+  } else {
+    return true;
+  }
+}
+
 std::optional<parser::MessageFormattedText> CheckAccessibleSymbol(
     const Scope &scope, const Symbol &symbol) {
-  if (symbol.attrs().test(Attr::PRIVATE)) {
-    if (FindModuleFileContaining(scope)) {
-      // Don't enforce component accessibility checks in module files;
-      // there may be forward-substituted named constants of derived type
-      // whose structure constructors reference private components.
-    } else if (const Scope *
-        moduleScope{FindModuleContaining(symbol.owner())}) {
-      if (!moduleScope->Contains(scope)) {
-        return parser::MessageFormattedText{
-            "PRIVATE name '%s' is only accessible within module '%s'"_err_en_US,
-            symbol.name(), moduleScope->GetName().value()};
-      }
-    }
+  if (IsAccessible(symbol, scope)) {
+    return std::nullopt;
+  } else if (FindModuleFileContaining(scope)) {
+    // Don't enforce component accessibility checks in module files;
+    // there may be forward-substituted named constants of derived type
+    // whose structure constructors reference private components.
+    return std::nullopt;
+  } else {
+    return parser::MessageFormattedText{
+        "PRIVATE name '%s' is only accessible within module '%s'"_err_en_US,
+        symbol.name(),
+        DEREF(FindModuleContaining(symbol.owner())).GetName().value()};
   }
-  return std::nullopt;
 }
 
 SymbolVector OrderParameterNames(const Symbol &typeSymbol) {
diff --git a/flang/test/Semantics/generic12.f90 b/flang/test/Semantics/generic12.f90
new file mode 100644
index 00000000000000..1ac76c13b7a2b0
--- /dev/null
+++ b/flang/test/Semantics/generic12.f90
@@ -0,0 +1,30 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+module m
+  type t
+   contains
+    procedure :: tweedledee
+    generic :: operator(.ga.) => tweedledee
+    generic, private :: operator(.gb.) => tweedledee
+  end type
+  interface operator(.gc.)
+    module procedure tweedledum
+  end interface
+ contains
+  integer function tweedledee(x,y)
+    class(t), intent(in) :: x, y
+    tweedledee = 1
+  end
+  integer function tweedledum(x,y)
+    class(t), intent(in) :: x, y
+    tweedledum = 2
+  end
+end
+
+module badDueToAccessibility
+  !ERROR: Generic 'OPERATOR(.ga.)' may not have specific procedures 'tweedledum' and 't%tweedledee' as their interfaces are not distinguishable
+  use m, operator(.ga.) => operator(.gc.)
+end
+
+module goodDueToInaccessibility
+  use m, operator(.gb.) => operator(.gc.)
+end

Copy link
Contributor

@DanielCChen DanielCChen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.
Thanks for the quick fix!

@klausler klausler merged commit ecf264d into llvm:main Jan 14, 2025
9 of 11 checks passed
@klausler klausler deleted the bug122764 branch January 14, 2025 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Flang] Incorrect diagnostic on renaming generic operator
3 participants