Skip to content

Commit b0a4318

Browse files
authored
Merge pull request swiftlang#8954 from rjmccall/writeback-conflict-access-markers
Fix the writeback-conflict diagnostic to look through access markers
2 parents 1c1b2b9 + 0d4e0a9 commit b0a4318

File tree

7 files changed

+62
-33
lines changed

7 files changed

+62
-33
lines changed

lib/SILGen/LValue.h

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -497,22 +497,7 @@ struct LLVM_LIBRARY_VISIBILITY ExclusiveBorrowFormalAccess : FormalAccess {
497497
component(std::move(comp)), base(base), materialized(materialized) {}
498498

499499
void diagnoseConflict(const ExclusiveBorrowFormalAccess &rhs,
500-
SILGenFunction &SGF) const {
501-
// If the two writebacks we're comparing are of different kinds (e.g.
502-
// ownership conversion vs a computed property) then they aren't the
503-
// same and thus cannot conflict.
504-
if (component->getKind() != rhs.component->getKind())
505-
return;
506-
507-
// If the lvalues don't have the same base value, then they aren't the same.
508-
// Note that this is the primary source of false negative for this
509-
// diagnostic.
510-
if (base.getValue() != rhs.base.getValue())
511-
return;
512-
513-
component->diagnoseWritebackConflict(rhs.component.get(), loc, rhs.loc,
514-
SGF);
515-
}
500+
SILGenFunction &SGF) const;
516501

517502
void performWriteback(SILGenFunction &SGF, bool isFinal) {
518503
Scope S(SGF.Cleanups, CleanupLocation::get(loc));

lib/SILGen/RValue.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,3 +690,30 @@ ManagedValue RValue::materialize(SILGenFunction &SGF, SILLocation loc) && {
690690
std::move(*this).forwardInto(SGF, loc, temp.get());
691691
return temp->getManagedAddress();
692692
}
693+
694+
bool RValue::isObviouslyEqual(const RValue &rhs) const {
695+
assert(isComplete() && rhs.isComplete() && "Comparing incomplete rvalues");
696+
697+
// Compare the count of elements instead of the type.
698+
if (values.size() != rhs.values.size())
699+
return false;
700+
701+
return std::equal(values.begin(), values.end(), rhs.values.begin(),
702+
[](const ManagedValue &lhs, const ManagedValue &rhs) -> bool {
703+
return areObviouslySameValue(lhs.getValue(), rhs.getValue());
704+
});
705+
}
706+
707+
static SILValue getCanonicalValueSource(SILValue value) {
708+
while (true) {
709+
if (auto access = dyn_cast<BeginAccessInst>(value)) {
710+
value = access->getSource();
711+
} else {
712+
return value;
713+
}
714+
}
715+
}
716+
717+
bool RValue::areObviouslySameValue(SILValue lhs, SILValue rhs) {
718+
return getCanonicalValueSource(lhs) == getCanonicalValueSource(rhs);
719+
}

lib/SILGen/RValue.h

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -222,19 +222,8 @@ class RValue {
222222
return RValue(*this, SGF, l);
223223
}
224224

225-
bool isObviouslyEqual(const RValue &rhs) const {
226-
assert(isComplete() && rhs.isComplete() && "Comparing incomplete rvalues");
227-
228-
// Compare the count of elements instead of the type.
229-
if (values.size() != rhs.values.size())
230-
return false;
231-
232-
return std::equal(values.begin(), values.end(), rhs.values.begin(),
233-
[](const ManagedValue &lhs, const ManagedValue &rhs) -> bool {
234-
return lhs.getValue() == rhs.getValue() &&
235-
lhs.getCleanup() == rhs.getCleanup();
236-
});
237-
}
225+
static bool areObviouslySameValue(SILValue lhs, SILValue rhs);
226+
bool isObviouslyEqual(const RValue &rhs) const;
238227
};
239228

240229
} // end namespace Lowering

lib/SILGen/SILGenApply.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1981,9 +1981,7 @@ static void beginInOutFormalAccesses(SILGenFunction &SGF,
19811981
for (auto i = emittedInoutArgs.begin(), e = emittedInoutArgs.end();
19821982
i != e; ++i) {
19831983
for (auto j = emittedInoutArgs.begin(); j != i; ++j) {
1984-
// TODO: This uses exact SILValue equivalence to detect aliases,
1985-
// we could do something stronger here to catch other obvious cases.
1986-
if (i->first != j->first) continue;
1984+
if (!RValue::areObviouslySameValue(i->first, j->first)) continue;
19871985

19881986
SGF.SGM.diagnose(i->second, diag::inout_argument_alias)
19891987
.highlight(i->second.getSourceRange());

lib/SILGen/SILGenLValue.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,28 @@ static void pushWriteback(SILGenFunction &SGF,
7878
cleanup.Depth = context.stable_begin();
7979
}
8080

81+
void ExclusiveBorrowFormalAccess::diagnoseConflict(
82+
const ExclusiveBorrowFormalAccess &rhs,
83+
SILGenFunction &SGF) const {
84+
// If the two writebacks we're comparing are of different kinds (e.g.
85+
// ownership conversion vs a computed property) then they aren't the
86+
// same and thus cannot conflict.
87+
if (component->getKind() != rhs.component->getKind())
88+
return;
89+
90+
// If the lvalues don't have the same base value (possibly null), then
91+
// they aren't the same. Note that this is the primary source of false
92+
// negative for this diagnostic.
93+
SILValue lhsBaseValue = base.getValue(), rhsBaseValue = rhs.base.getValue();
94+
if (lhsBaseValue != rhsBaseValue &&
95+
(!lhsBaseValue || !rhsBaseValue ||
96+
!RValue::areObviouslySameValue(lhsBaseValue, rhsBaseValue))) {
97+
return;
98+
}
99+
100+
component->diagnoseWritebackConflict(rhs.component.get(), loc, rhs.loc, SGF);
101+
}
102+
81103
//===----------------------------------------------------------------------===//
82104

83105
static CanType getSubstFormalRValueType(Expr *expr) {

test/SILGen/writeback_conflict_diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %target-swift-frontend %s -o /dev/null -emit-silgen -verify
2-
2+
// RUN: %target-swift-frontend -enforce-exclusivity=checked %s -o /dev/null -emit-silgen -verify
33

44
struct MutatorStruct {
55
mutating func f(_ x : inout MutatorStruct) {}

test/SILOptimizer/exclusivity_static_diagnostics.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ func takesTwoInouts<T>(_ p1: inout T, _ p2: inout T) { }
77
func simpleInoutDiagnostic() {
88
var i = 7
99

10+
// expected-error@+4{{inout arguments are not allowed to alias each other}}
11+
// expected-note@+3{{previous aliasing argument}}
1012
// expected-warning@+2{{simultaneous accesses to var 'i'; modification requires exclusive access}}
1113
// expected-note@+1{{conflicting access is here}}
1214
takesTwoInouts(&i, &i)
1315
}
1416

1517
func inoutOnInoutParameter(p: inout Int) {
18+
// expected-error@+4{{inout arguments are not allowed to alias each other}}
19+
// expected-note@+3{{previous aliasing argument}}
1620
// expected-warning@+2{{simultaneous accesses to parameter 'p'; modification requires exclusive access}}
1721
// expected-note@+1{{conflicting access is here}}
1822
takesTwoInouts(&p, &p)
@@ -34,6 +38,8 @@ struct StructWithMutatingMethodThatTakesSelfInout {
3438
mutating func mutate(_ other: inout SomeClass) { }
3539

3640
mutating func callMutatingMethodThatTakesSelfInout() {
41+
// expected-error@+4{{inout arguments are not allowed to alias each other}}
42+
// expected-note@+3{{previous aliasing argument}}
3743
// expected-warning@+2{{simultaneous accesses to parameter 'self'; modification requires exclusive access}}
3844
// expected-note@+1{{conflicting access is here}}
3945
mutate(&self)
@@ -74,6 +80,8 @@ class ClassWithFinalStoredProp {
7480

7581
func violationWithGenericType<T>(_ p: T) {
7682
var local = p
83+
// expected-error@+4{{inout arguments are not allowed to alias each other}}
84+
// expected-note@+3{{previous aliasing argument}}
7785
// expected-warning@+2{{simultaneous accesses to var 'local'; modification requires exclusive access}}
7886
// expected-note@+1{{conflicting access is here}}
7987
takesTwoInouts(&local, &local)

0 commit comments

Comments
 (0)