Skip to content

Commit e93ffb7

Browse files
authored
Merge pull request #84504 from kavon/manual-ownership/usability-fixes-3
Usability improvements for ManualOwnership (part 3)
2 parents 8f7af45 + 0734267 commit e93ffb7

File tree

12 files changed

+353
-31
lines changed

12 files changed

+353
-31
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,6 +2141,8 @@ ERROR(attr_static_exclusive_no_setters,none,
21412141
// @_manualOwnership
21422142
ERROR(attr_manual_ownership_experimental,none,
21432143
"'@_manualOwnership' requires '-enable-experimental-feature ManualOwnership'", ())
2144+
ERROR(attr_manual_ownership_noimplicitcopy,none,
2145+
"'@_noImplicitCopy' cannot be used with ManualOwnership", ())
21442146

21452147
// @extractConstantsFromMembers
21462148
ERROR(attr_extractConstantsFromMembers_experimental,none,

lib/SILGen/SILGen.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,24 @@ void SILGenModule::preEmitFunction(SILDeclRef constant, SILFunction *F,
13601360
// Set our actor isolation.
13611361
F->setActorIsolation(constant.getActorIsolation());
13621362

1363+
// Closures automatically infer [manual_ownership] based on outermost func.
1364+
//
1365+
// We need to add this constraint _prior_ to emitting the closure's body,
1366+
// because the output from SILGen slightly differs because of this constraint
1367+
// when it comes to the CopyExpr and SILMoveOnlyWrappedType usage.
1368+
//
1369+
// If ManualOwnership ends up subsuming those prior mechanisms for an
1370+
// explicit-copy mode, we can move this somewhere else, like postEmitFunction.
1371+
if (auto *ace = constant.getAbstractClosureExpr()) {
1372+
if (auto *dc = ace->getOutermostFunctionContext()) {
1373+
if (auto *decl = dc->getAsDecl()) {
1374+
if (decl->getAttrs().hasAttribute<ManualOwnershipAttr>()) {
1375+
F->setPerfConstraints(PerformanceConstraints::ManualOwnership);
1376+
}
1377+
}
1378+
}
1379+
}
1380+
13631381
LLVM_DEBUG(llvm::dbgs() << "lowering ";
13641382
F->printName(llvm::dbgs());
13651383
llvm::dbgs() << " : ";

lib/SILGen/SILGenBuilder.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,10 @@ static ManagedValue createInputFunctionArgument(
537537
isNoImplicitCopy |= pd->getSpecifier() == ParamSpecifier::Borrowing;
538538
isNoImplicitCopy |= pd->getSpecifier() == ParamSpecifier::Consuming;
539539
}
540+
541+
// ManualOwnership checks everything for implicit copies already.
542+
if (B.hasManualOwnershipAttr())
543+
isNoImplicitCopy = false;
540544
}
541545
if (isNoImplicitCopy)
542546
arg->setNoImplicitCopy(isNoImplicitCopy);

lib/SILGen/SILGenDecl.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,11 @@ class LocalVariableInitialization : public SingleBufferInitialization {
561561

562562
// If our instance type is not already @moveOnly wrapped, and it's a
563563
// no-implicit-copy parameter, wrap it.
564-
if (!isNoImplicitCopy && instanceType->isCopyable()) {
564+
//
565+
// Unless the function is using ManualOwnership, which checks for
566+
// no-implicit-copies using a different mechanism.
567+
if (!isNoImplicitCopy && instanceType->isCopyable() &&
568+
!SGF.B.hasManualOwnershipAttr()) {
565569
if (auto *pd = dyn_cast<ParamDecl>(decl)) {
566570
isNoImplicitCopy = pd->isNoImplicitCopy();
567571
isNoImplicitCopy |= pd->getSpecifier() == ParamSpecifier::Consuming;

lib/SILGen/SILGenExpr.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7271,6 +7271,25 @@ RValue RValueEmitter::visitCopyExpr(CopyExpr *E, SGFContext C) {
72717271

72727272
if (auto *li = dyn_cast<LoadExpr>(subExpr)) {
72737273
FormalEvaluationScope writeback(SGF);
7274+
7275+
// If we're relying on ManualOwnership for explicit-copies enforcement,
7276+
// avoid doing address-based emission for loadable types.
7277+
if (subType.isLoadableOrOpaque(SGF.F) && SGF.B.hasManualOwnershipAttr()) {
7278+
// Do a read on the lvalue. If we get back an address, do a load before
7279+
// emitting the explicit copy.
7280+
LValue lv =
7281+
SGF.emitLValue(li->getSubExpr(), SGFAccessKind::BorrowedObjectRead);
7282+
auto value = SGF.emitRawProjectedLValue(E, std::move(lv));
7283+
if (value.getType().isAddress()) {
7284+
// We don't have 'load [explicit_copy]' so do this instead:
7285+
// %x = load [copy] %value
7286+
// %y = explicit_copy_value %x
7287+
value = SGF.emitManagedLoadCopy(E, value.getUnmanagedValue());
7288+
}
7289+
ManagedValue copy = SGF.B.createExplicitCopyValue(E, value);
7290+
return RValue(SGF, {copy}, subType.getASTType());
7291+
}
7292+
72747293
LValue lv =
72757294
SGF.emitLValue(li->getSubExpr(), SGFAccessKind::BorrowedAddressRead);
72767295
auto address = SGF.emitAddressOfLValue(subExpr, std::move(lv));

lib/SILGen/SILGenPattern.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,10 @@ void PatternMatchEmission::bindBorrow(Pattern *pattern, VarDecl *var,
14051405
auto bindValue = value.asBorrowedOperand2(SGF, pattern).getFinalManagedValue();
14061406

14071407
// Borrow bindings of copyable type should still be no-implicit-copy.
1408-
if (!bindValue.getType().isMoveOnly()) {
1408+
//
1409+
// If we're relying on ManualOwnership for explicit-copies enforcement,
1410+
// we don't need the MoveOnlyWrapper.
1411+
if (!bindValue.getType().isMoveOnly() && !SGF.B.hasManualOwnershipAttr()) {
14091412
if (bindValue.getType().isAddress()) {
14101413
bindValue = ManagedValue::forBorrowedAddressRValue(
14111414
SGF.B.createCopyableToMoveOnlyWrapperAddr(pattern, bindValue.getValue()));

lib/SILGen/SILGenProlog.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,10 @@ class ArgumentInitHelper {
793793
}
794794
}
795795
}
796+
// If we're relying on ManualOwnership for explicit-copies enforcement,
797+
// we don't need @noImplicitCopy / MoveOnlyWrapper.
798+
if (SGF.B.hasManualOwnershipAttr())
799+
isNoImplicitCopy = false;
796800

797801
// If we have a no implicit copy argument and the argument is trivial,
798802
// we need to use copyable to move only to convert it to its move only
@@ -1216,8 +1220,9 @@ static void emitCaptureArguments(SILGenFunction &SGF,
12161220
SILType ty = lowering.getLoweredType();
12171221

12181222
bool isNoImplicitCopy;
1219-
1220-
if (ty.isTrivial(SGF.F) || ty.isMoveOnly()) {
1223+
1224+
if (ty.isTrivial(SGF.F) || ty.isMoveOnly() ||
1225+
SGF.B.hasManualOwnershipAttr()) {
12211226
isNoImplicitCopy = false;
12221227
} else if (VD->isNoImplicitCopy()) {
12231228
isNoImplicitCopy = true;

lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
383383
case SILInstructionKind::PartialApplyInst:
384384
case SILInstructionKind::DestroyAddrInst:
385385
case SILInstructionKind::DestroyValueInst:
386+
case SILInstructionKind::StoreInst:
386387
break; // These modify reference counts, but aren't copies.
387388
case SILInstructionKind::ExplicitCopyAddrInst:
388389
case SILInstructionKind::ExplicitCopyValueInst:
@@ -441,7 +442,11 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
441442

442443
// There's no hope of borrowing access if there's a consuming use.
443444
for (auto op : svi->getUses()) {
444-
if (op->getOperandOwnership() == OperandOwnership::ForwardingConsume) {
445+
auto useKind = op->getOperandOwnership();
446+
447+
// Only some DestroyingConsume's, like 'store', are interesting.
448+
if (useKind == OperandOwnership::ForwardingConsume
449+
|| isa<StoreInst>(op->getUser())) {
445450
LLVM_DEBUG(llvm::dbgs() << "demanded by "<< *(op->getUser()));
446451
diagnose(loc, diag::manualownership_copy_demanded, *name);
447452
return false;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,11 @@ void AttributeChecker::visitNoImplicitCopyAttr(NoImplicitCopyAttr *attr) {
497497
return;
498498
}
499499

500+
// Don't allow it to be combined with ManualOwnership.
501+
if (D->getASTContext().LangOpts.hasFeature(Feature::ManualOwnership)) {
502+
diagnoseAndRemoveAttr(attr, diag::attr_manual_ownership_noimplicitcopy);
503+
}
504+
500505
if (auto *funcDecl = dyn_cast<FuncDecl>(D)) {
501506
if (visitOwnershipAttr(attr))
502507
return;

0 commit comments

Comments
 (0)