Skip to content

Commit 2ca2e1c

Browse files
authored
[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.
1 parent 764e0cc commit 2ca2e1c

File tree

5 files changed

+81
-14
lines changed

5 files changed

+81
-14
lines changed

flang/include/flang/Evaluate/characteristics.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,14 @@ class TypeAndShape {
174174
}
175175
const std::optional<Shape> &shape() const { return shape_; }
176176
const Attrs &attrs() const { return attrs_; }
177+
Attrs &attrs() { return attrs_; }
178+
bool isPossibleSequenceAssociation() const {
179+
return isPossibleSequenceAssociation_;
180+
}
181+
TypeAndShape &set_isPossibleSequenceAssociation(bool yes) {
182+
isPossibleSequenceAssociation_ = yes;
183+
return *this;
184+
}
177185
int corank() const { return corank_; }
178186
void set_corank(int n) { corank_ = n; }
179187

@@ -209,11 +217,11 @@ class TypeAndShape {
209217
void AcquireLEN();
210218
void AcquireLEN(const semantics::Symbol &);
211219

212-
protected:
213220
DynamicType type_;
214221
std::optional<Expr<SubscriptInteger>> LEN_;
215222
std::optional<Shape> shape_;
216223
Attrs attrs_;
224+
bool isPossibleSequenceAssociation_{false};
217225
int corank_{0};
218226
};
219227

flang/include/flang/Evaluate/tools.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -396,20 +396,22 @@ std::optional<DataRef> ExtractDataRef(const ActualArgument &,
396396

397397
// Predicate: is an expression is an array element reference?
398398
template <typename T>
399-
bool IsArrayElement(const Expr<T> &expr, bool intoSubstring = true,
399+
const Symbol *IsArrayElement(const Expr<T> &expr, bool intoSubstring = true,
400400
bool skipComponents = false) {
401401
if (auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
402402
for (const DataRef *ref{&*dataRef}; ref;) {
403403
if (const Component * component{std::get_if<Component>(&ref->u)}) {
404404
ref = skipComponents ? &component->base() : nullptr;
405405
} else if (const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
406406
ref = &coarrayRef->base();
407+
} else if (const auto *arrayRef{std::get_if<ArrayRef>(&ref->u)}) {
408+
return &arrayRef->GetLastSymbol();
407409
} else {
408-
return std::holds_alternative<ArrayRef>(ref->u);
410+
break;
409411
}
410412
}
411413
}
412-
return false;
414+
return nullptr;
413415
}
414416

415417
template <typename A>

flang/lib/Evaluate/characteristics.cpp

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ llvm::raw_ostream &TypeAndShape::Dump(llvm::raw_ostream &o) const {
274274
}
275275
o << ')';
276276
}
277+
if (isPossibleSequenceAssociation_) {
278+
o << " isPossibleSequenceAssociation";
279+
}
277280
return o;
278281
}
279282

@@ -282,17 +285,26 @@ bool DummyDataObject::operator==(const DummyDataObject &that) const {
282285
coshape == that.coshape && cudaDataAttr == that.cudaDataAttr;
283286
}
284287

288+
static bool IsOkWithSequenceAssociation(
289+
const TypeAndShape &t1, const TypeAndShape &t2) {
290+
return t1.isPossibleSequenceAssociation() &&
291+
(t2.isPossibleSequenceAssociation() || t2.CanBeSequenceAssociated());
292+
}
293+
285294
bool DummyDataObject::IsCompatibleWith(const DummyDataObject &actual,
286295
std::string *whyNot, std::optional<std::string> *warning) const {
287-
bool possibleWarning{false};
288-
if (!ShapesAreCompatible(
289-
type.shape(), actual.type.shape(), &possibleWarning)) {
290-
if (whyNot) {
291-
*whyNot = "incompatible dummy data object shapes";
296+
if (!IsOkWithSequenceAssociation(type, actual.type) &&
297+
!IsOkWithSequenceAssociation(actual.type, type)) {
298+
bool possibleWarning{false};
299+
if (!ShapesAreCompatible(
300+
type.shape(), actual.type.shape(), &possibleWarning)) {
301+
if (whyNot) {
302+
*whyNot = "incompatible dummy data object shapes";
303+
}
304+
return false;
305+
} else if (warning && possibleWarning) {
306+
*warning = "distinct dummy data object shapes";
292307
}
293-
return false;
294-
} else if (warning && possibleWarning) {
295-
*warning = "distinct dummy data object shapes";
296308
}
297309
// Treat deduced dummy character type as if it were assumed-length character
298310
// to avoid useless "implicit interfaces have distinct type" warnings from
@@ -343,10 +355,29 @@ bool DummyDataObject::IsCompatibleWith(const DummyDataObject &actual,
343355
}
344356
}
345357
}
346-
if (!IdenticalSignificantAttrs(attrs, actual.attrs) ||
358+
if (!attrs.test(Attr::DeducedFromActual) &&
359+
!actual.attrs.test(Attr::DeducedFromActual) &&
347360
type.attrs() != actual.type.attrs()) {
361+
if (whyNot) {
362+
*whyNot = "incompatible dummy data object shape attributes";
363+
auto differences{type.attrs() ^ actual.type.attrs()};
364+
auto sep{": "s};
365+
differences.IterateOverMembers([&](TypeAndShape::Attr x) {
366+
*whyNot += sep + std::string{TypeAndShape::EnumToString(x)};
367+
sep = ", ";
368+
});
369+
}
370+
return false;
371+
}
372+
if (!IdenticalSignificantAttrs(attrs, actual.attrs)) {
348373
if (whyNot) {
349374
*whyNot = "incompatible dummy data object attributes";
375+
auto differences{attrs ^ actual.attrs};
376+
auto sep{": "s};
377+
differences.IterateOverMembers([&](DummyDataObject::Attr x) {
378+
*whyNot += sep + std::string{EnumToString(x)};
379+
sep = ", ";
380+
});
350381
}
351382
return false;
352383
}
@@ -900,6 +931,15 @@ std::optional<DummyArgument> DummyArgument::FromActual(std::string &&name,
900931
type->set_type(DynamicType{
901932
type->type().GetDerivedTypeSpec(), /*poly=*/false});
902933
}
934+
if (type->type().category() == TypeCategory::Character &&
935+
type->type().kind() == 1) {
936+
type->set_isPossibleSequenceAssociation(true);
937+
} else if (const Symbol * array{IsArrayElement(expr)}) {
938+
type->set_isPossibleSequenceAssociation(
939+
IsContiguous(*array, context).value_or(false));
940+
} else {
941+
type->set_isPossibleSequenceAssociation(expr.Rank() > 0);
942+
}
903943
DummyDataObject obj{std::move(*type)};
904944
obj.attrs.set(DummyDataObject::Attr::DeducedFromActual);
905945
return std::make_optional<DummyArgument>(

flang/lib/Semantics/check-call.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
561561
"Coindexed scalar actual argument must be associated with a scalar %s"_err_en_US,
562562
dummyName);
563563
}
564-
bool actualIsArrayElement{IsArrayElement(actual)};
564+
bool actualIsArrayElement{IsArrayElement(actual) != nullptr};
565565
bool actualIsCKindCharacter{
566566
actualType.type().category() == TypeCategory::Character &&
567567
actualType.type().kind() == 1};

flang/test/Semantics/call43.f90

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic -Werror
2+
subroutine from(a, b, c, d)
3+
real a(10), b(:), c
4+
real, contiguous :: d(:)
5+
call to(a)
6+
call to(a(1)) ! ok
7+
call to(b) ! ok, passed via temp
8+
!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
9+
call to(b(1))
10+
!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
11+
call to(c)
12+
!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
13+
call to(1.)
14+
call to([1., 2.]) ! ok
15+
call to(d) ! ok
16+
call to(d(1)) ! ok
17+
end

0 commit comments

Comments
 (0)