-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-flang-semantics Author: Peter Klausler (klausler) ChangesThe 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:
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
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this 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.
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.