Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[flang] Tune warning about incompatible implicit interfaces #136788

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

klausler
Copy link
Contributor

The compiler was emitting a warning about incompatible shapes being used for two calls to the same procedure with an implicit interface when one passed a whole array and the other passed a scalar. When the scalar is a whole element of a contiguous array, however, we must allow for storage association and not flag it as being a problem.

@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics labels Apr 22, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 22, 2025

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

The compiler was emitting a warning about incompatible shapes being used for two calls to the same procedure with an implicit interface when one passed a whole array and the other passed a scalar. When the scalar is a whole element of a contiguous array, however, we must allow for storage association and not flag it as being a problem.


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

4 Files Affected:

  • (modified) flang/include/flang/Evaluate/characteristics.h (+9-1)
  • (modified) flang/include/flang/Evaluate/tools.h (+10-10)
  • (modified) flang/lib/Evaluate/characteristics.cpp (+49-9)
  • (added) flang/test/Semantics/call43.f90 (+17)
diff --git a/flang/include/flang/Evaluate/characteristics.h b/flang/include/flang/Evaluate/characteristics.h
index 6d29b57889681..d566c34ff71e8 100644
--- a/flang/include/flang/Evaluate/characteristics.h
+++ b/flang/include/flang/Evaluate/characteristics.h
@@ -174,6 +174,14 @@ class TypeAndShape {
   }
   const std::optional<Shape> &shape() const { return shape_; }
   const Attrs &attrs() const { return attrs_; }
+  Attrs &attrs() { return attrs_; }
+  bool isPossibleSequenceAssociation() const {
+    return isPossibleSequenceAssociation_;
+  }
+  TypeAndShape &set_isPossibleSequenceAssociation(bool yes) {
+    isPossibleSequenceAssociation_ = yes;
+    return *this;
+  }
   int corank() const { return corank_; }
   void set_corank(int n) { corank_ = n; }
 
@@ -209,11 +217,11 @@ class TypeAndShape {
   void AcquireLEN();
   void AcquireLEN(const semantics::Symbol &);
 
-protected:
   DynamicType type_;
   std::optional<Expr<SubscriptInteger>> LEN_;
   std::optional<Shape> shape_;
   Attrs attrs_;
+  bool isPossibleSequenceAssociation_{false};
   int corank_{0};
 };
 
diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 1414eaf14f7d6..f9c2c2028cf27 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -386,11 +386,11 @@ std::optional<DataRef> ExtractDataRef(
 std::optional<DataRef> ExtractDataRef(const ActualArgument &,
     bool intoSubstring = false, bool intoComplexPart = false);
 
-// Predicate: is an expression is an array element reference?
-template <typename T>
-bool IsArrayElement(const Expr<T> &expr, bool intoSubstring = true,
-    bool skipComponents = false) {
-  if (auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
+// Predicate: is an expression or designator an array element reference?
+template <typename A>
+const Symbol *IsArrayElement(
+    const A &x, bool intoSubstring = true, bool skipComponents = false) {
+  if (auto dataRef{ExtractDataRef(x, intoSubstring)}) {
     const DataRef *ref{&*dataRef};
     if (skipComponents) {
       while (const Component * component{std::get_if<Component>(&ref->u)}) {
@@ -398,13 +398,13 @@ bool IsArrayElement(const Expr<T> &expr, bool intoSubstring = true,
       }
     }
     if (const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
-      return !coarrayRef->subscript().empty();
-    } else {
-      return std::holds_alternative<ArrayRef>(ref->u);
+      return coarrayRef->subscript().empty() ? nullptr
+                                             : &coarrayRef->GetLastSymbol();
+    } else if (const auto *arrayRef{std::get_if<ArrayRef>(&ref->u)}) {
+      return &arrayRef->GetLastSymbol();
     }
-  } else {
-    return false;
   }
+  return nullptr;
 }
 
 template <typename A>
diff --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp
index 63040feae43fc..7de93bdf07415 100644
--- a/flang/lib/Evaluate/characteristics.cpp
+++ b/flang/lib/Evaluate/characteristics.cpp
@@ -274,6 +274,9 @@ llvm::raw_ostream &TypeAndShape::Dump(llvm::raw_ostream &o) const {
     }
     o << ')';
   }
+  if (isPossibleSequenceAssociation_) {
+    o << " isPossibleSequenceAssociation";
+  }
   return o;
 }
 
@@ -282,17 +285,26 @@ bool DummyDataObject::operator==(const DummyDataObject &that) const {
       coshape == that.coshape && cudaDataAttr == that.cudaDataAttr;
 }
 
+static bool IsOkWithSequenceAssociation(
+    const TypeAndShape &t1, const TypeAndShape &t2) {
+  return t1.isPossibleSequenceAssociation() &&
+      (t2.isPossibleSequenceAssociation() || t2.CanBeSequenceAssociated());
+}
+
 bool DummyDataObject::IsCompatibleWith(const DummyDataObject &actual,
     std::string *whyNot, std::optional<std::string> *warning) const {
-  bool possibleWarning{false};
-  if (!ShapesAreCompatible(
-          type.shape(), actual.type.shape(), &possibleWarning)) {
-    if (whyNot) {
-      *whyNot = "incompatible dummy data object shapes";
+  if (!IsOkWithSequenceAssociation(type, actual.type) &&
+      !IsOkWithSequenceAssociation(actual.type, type)) {
+    bool possibleWarning{false};
+    if (!ShapesAreCompatible(
+            type.shape(), actual.type.shape(), &possibleWarning)) {
+      if (whyNot) {
+        *whyNot = "incompatible dummy data object shapes";
+      }
+      return false;
+    } else if (warning && possibleWarning) {
+      *warning = "distinct dummy data object shapes";
     }
-    return false;
-  } else if (warning && possibleWarning) {
-    *warning = "distinct dummy data object shapes";
   }
   // Treat deduced dummy character type as if it were assumed-length character
   // to avoid useless "implicit interfaces have distinct type" warnings from
@@ -343,10 +355,29 @@ bool DummyDataObject::IsCompatibleWith(const DummyDataObject &actual,
       }
     }
   }
-  if (!IdenticalSignificantAttrs(attrs, actual.attrs) ||
+  if (!attrs.test(Attr::DeducedFromActual) &&
+      !actual.attrs.test(Attr::DeducedFromActual) &&
       type.attrs() != actual.type.attrs()) {
+    if (whyNot) {
+      *whyNot = "incompatible dummy data object shape attributes";
+      auto differences{type.attrs() ^ actual.type.attrs()};
+      auto sep{": "s};
+      differences.IterateOverMembers([&](TypeAndShape::Attr x) {
+        *whyNot += sep + std::string{TypeAndShape::EnumToString(x)};
+        sep = ", ";
+      });
+    }
+    return false;
+  }
+  if (!IdenticalSignificantAttrs(attrs, actual.attrs)) {
     if (whyNot) {
       *whyNot = "incompatible dummy data object attributes";
+      auto differences{attrs ^ actual.attrs};
+      auto sep{": "s};
+      differences.IterateOverMembers([&](DummyDataObject::Attr x) {
+        *whyNot += sep + std::string{EnumToString(x)};
+        sep = ", ";
+      });
     }
     return false;
   }
@@ -900,6 +931,15 @@ std::optional<DummyArgument> DummyArgument::FromActual(std::string &&name,
                 type->set_type(DynamicType{
                     type->type().GetDerivedTypeSpec(), /*poly=*/false});
               }
+              if (type->type().category() == TypeCategory::Character &&
+                  type->type().kind() == 1) {
+                type->set_isPossibleSequenceAssociation(true);
+              } else if (const Symbol *array{IsArrayElement(expr)}) {
+                type->set_isPossibleSequenceAssociation(
+                    IsContiguous(*array, context).value_or(false));
+              } else {
+                type->set_isPossibleSequenceAssociation(expr.Rank() > 0);
+              }
               DummyDataObject obj{std::move(*type)};
               obj.attrs.set(DummyDataObject::Attr::DeducedFromActual);
               return std::make_optional<DummyArgument>(
diff --git a/flang/test/Semantics/call43.f90 b/flang/test/Semantics/call43.f90
new file mode 100644
index 0000000000000..d8cc543a4838a
--- /dev/null
+++ b/flang/test/Semantics/call43.f90
@@ -0,0 +1,17 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic -Werror
+subroutine from(a, b, c, d)
+  real a(10), b(:), c
+  real, contiguous :: d(:)
+  call to(a)
+  call to(a(1)) ! ok
+  call to(b) ! ok, passed via temp
+  !WARNING: Reference to the procedure 'to' has an implicit interface that is distinct from another reference: incompatible dummy argument #1: incompatible dummy data object shapes
+  call to(b(1))
+  !WARNING: Reference to the procedure 'to' has an implicit interface that is distinct from another reference: incompatible dummy argument #1: incompatible dummy data object shapes
+  call to(c)
+  !WARNING: Reference to the procedure 'to' has an implicit interface that is distinct from another reference: incompatible dummy argument #1: incompatible dummy data object shapes
+  call to(1.)
+  call to([1., 2.]) ! ok
+  call to(d) ! ok
+  call to(d(1)) ! ok
+end

Copy link

github-actions bot commented Apr 22, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@akuhlens akuhlens left a comment

Choose a reason for hiding this comment

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

LGTM

The compiler was emitting a warning about incompatible shapes
being used for two calls to the same procedure with an implicit
interface when one passed a whole array and the other passed
a scalar.  When the scalar is a whole element of a contiguous
array, however, we must allow for storage association and not flag
it as being a problem.
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.

4 participants