[flang-commits] [flang] 2ca2e1c - [flang] Tune warning about incompatible implicit interfaces (#136788)
via flang-commits
flang-commits at lists.llvm.org
Tue May 13 07:48:09 PDT 2025
Author: Peter Klausler
Date: 2025-05-13T07:48:05-07:00
New Revision: 2ca2e1c9d5e353064586ccc314377dc4ef1bf25d
URL: https://github.com/llvm/llvm-project/commit/2ca2e1c9d5e353064586ccc314377dc4ef1bf25d
DIFF: https://github.com/llvm/llvm-project/commit/2ca2e1c9d5e353064586ccc314377dc4ef1bf25d.diff
LOG: [flang] Tune warning about incompatible implicit interfaces (#136788)
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.
Added:
flang/test/Semantics/call43.f90
Modified:
flang/include/flang/Evaluate/characteristics.h
flang/include/flang/Evaluate/tools.h
flang/lib/Evaluate/characteristics.cpp
flang/lib/Semantics/check-call.cpp
Removed:
################################################################################
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 922af4190822d..0318a468f3811 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -396,7 +396,7 @@ std::optional<DataRef> ExtractDataRef(const ActualArgument &,
// Predicate: is an expression is an array element reference?
template <typename T>
-bool IsArrayElement(const Expr<T> &expr, bool intoSubstring = true,
+const Symbol *IsArrayElement(const Expr<T> &expr, bool intoSubstring = true,
bool skipComponents = false) {
if (auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
for (const DataRef *ref{&*dataRef}; ref;) {
@@ -404,12 +404,14 @@ bool IsArrayElement(const Expr<T> &expr, bool intoSubstring = true,
ref = skipComponents ? &component->base() : nullptr;
} else if (const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
ref = &coarrayRef->base();
+ } else if (const auto *arrayRef{std::get_if<ArrayRef>(&ref->u)}) {
+ return &arrayRef->GetLastSymbol();
} else {
- return std::holds_alternative<ArrayRef>(ref->u);
+ break;
}
}
}
- return false;
+ return nullptr;
}
template <typename A>
diff --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp
index 63040feae43fc..89547733ea33c 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
diff erences{type.attrs() ^ actual.type.attrs()};
+ auto sep{": "s};
+
diff erences.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
diff erences{attrs ^ actual.attrs};
+ auto sep{": "s};
+
diff erences.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/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index 3cf95fdab44f5..dfc2ddbacf071 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -561,7 +561,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
"Coindexed scalar actual argument must be associated with a scalar %s"_err_en_US,
dummyName);
}
- bool actualIsArrayElement{IsArrayElement(actual)};
+ bool actualIsArrayElement{IsArrayElement(actual) != nullptr};
bool actualIsCKindCharacter{
actualType.type().category() == TypeCategory::Character &&
actualType.type().kind() == 1};
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
More information about the flang-commits
mailing list