diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index d2be1ea645047..e360e5b7ae3bf 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -245,8 +245,9 @@ static LValueTypeData getPhysicalStorageTypeData(TypeExpansionContext context, } static bool shouldUseUnsafeEnforcement(VarDecl *var) { - if (var->isDebuggerVar()) + if (var->isDebuggerVar()) { return true; + } return false; } @@ -277,6 +278,22 @@ SILGenFunction::getDynamicEnforcement(VarDecl *var) { } else if (hasExclusivityAttr(var, ExclusivityAttr::Checked)) { return SILAccessEnforcement::Dynamic; } + + // Access markers are especially load-bearing for the move-only checker, + // so we also emit `begin_access` markers for cases where storage + // is move-only. + // TODO: It seems useful to do this for all unchecked declarations, since + // access scopes are useful semantic information. + if (var->getTypeInContext()->isNoncopyable()) { + return SILAccessEnforcement::Unsafe; + } + if (auto param = dyn_cast(var)) { + if (param->getSpecifier() == ParamSpecifier::Borrowing + || param->getSpecifier() == ParamSpecifier::Consuming) { + return SILAccessEnforcement::Unsafe; + } + } + return std::nullopt; } diff --git a/test/SILOptimizer/moveonly_unchecked_exclusivity.swift b/test/SILOptimizer/moveonly_unchecked_exclusivity.swift new file mode 100644 index 0000000000000..01115806fba52 --- /dev/null +++ b/test/SILOptimizer/moveonly_unchecked_exclusivity.swift @@ -0,0 +1,25 @@ +// RUN: %target-swift-frontend -enforce-exclusivity=unchecked -emit-sil %s | %FileCheck %s + +struct Foo: ~Copyable { + var x: Any +} + +final class Bar { + init() { fatalError() } + + // Ensure that noncopyable bindings still get [unsafe] exclusivity markers + // and get checked properly by the move-only checker. + + // Bar.foo.setter: + // CHECK-LABEL: sil {{.*}} @$s{{.*}}3BarC3foo{{.*}}vs + // CHECK: [[FIELD:%.*]] = ref_element_addr {{.*}}, #Bar.foo + // CHECK: [[FIELD_ACCESS:%.*]] = begin_access [modify] [unsafe] [[FIELD]] + // CHECK-NEXT: destroy_addr [[FIELD_ACCESS]] + // CHECK-NEXT: copy_addr [take] {{.*}} to [init] [[FIELD_ACCESS]] + // CHECK-NEXT: end_access [[FIELD_ACCESS]] + // CHECK-NOT: [[FIELD]] + // CHECK-NOT: [[FIELD_ACCESS]] + // CHECK: } // end sil {{.*}} '$s{{.*}}3BarC3foo{{.*}}vs' + + var foo: Foo +}