Skip to content

Commit bb0883d

Browse files
authored
Merge pull request #39991 from gottesmm/no_implicit_copy_arguments
[moveOnly] Allow the @_noImplicitCopy decl attribute to be applied to parameters
2 parents 0683b3f + 409a7d5 commit bb0883d

21 files changed

+329
-75
lines changed

include/swift/AST/Attr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ SIMPLE_DECL_ATTR(_noImplicitCopy, NoImplicitCopy,
676676
UserInaccessible |
677677
ABIStableToAdd | ABIBreakingToRemove |
678678
APIStableToAdd | APIBreakingToRemove |
679-
OnVar,
679+
OnParam | OnVar,
680680
122)
681681

682682
SIMPLE_DECL_ATTR(_noLocks, NoLocks,

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5371,6 +5371,10 @@ class ParamDecl : public VarDecl {
53715371
Bits.ParamDecl.defaultArgumentKind = static_cast<unsigned>(K);
53725372
}
53735373

5374+
bool isNoImplicitCopy() const {
5375+
return getAttrs().hasAttribute<NoImplicitCopyAttr>();
5376+
}
5377+
53745378
/// Whether this parameter has a default argument expression available.
53755379
///
53765380
/// Note that this will return false for deserialized declarations, which only

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6047,8 +6047,8 @@ ERROR(experimental_moveonly_feature_can_only_be_used_when_enabled,
60476047
none, "Can not use feature when experimental move only is disabled! Pass"
60486048
" the frontend flag -enable-experimental-move-only to swift to enable "
60496049
"the usage of this language feature", ())
6050-
ERROR(noimplicitcopy_attr_valid_only_on_local_let,
6051-
none, "'@_noImplicitCopy' attribute can only be applied to local lets", ())
6050+
ERROR(noimplicitcopy_attr_valid_only_on_local_let_params,
6051+
none, "'@_noImplicitCopy' attribute can only be applied to local lets and params", ())
60526052
ERROR(noimplicitcopy_attr_invalid_in_generic_context,
60536053
none, "'@_noImplicitCopy' attribute cannot be applied to entities in generic contexts", ())
60546054

include/swift/SIL/SILArgument.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ class SILArgument : public ValueBase {
111111
node->getKind() <= SILNodeKind::Last_SILArgument;
112112
}
113113

114+
bool isNoImplicitCopy() const;
115+
114116
unsigned getIndex() const;
115117

116118
/// Return true if this block argument is actually a phi argument as
@@ -311,11 +313,15 @@ class SILPhiArgument : public SILArgument {
311313
class SILFunctionArgument : public SILArgument {
312314
friend class SILBasicBlock;
313315

316+
bool noImplicitCopy = false;
317+
314318
SILFunctionArgument(SILBasicBlock *parentBlock, SILType type,
315319
ValueOwnershipKind ownershipKind,
316-
const ValueDecl *decl = nullptr)
320+
const ValueDecl *decl = nullptr,
321+
bool isNoImplicitCopy = false)
317322
: SILArgument(ValueKind::SILFunctionArgument, parentBlock, type,
318-
ownershipKind, decl) {}
323+
ownershipKind, decl),
324+
noImplicitCopy(isNoImplicitCopy) {}
319325
// A special constructor, only intended for use in
320326
// SILBasicBlock::replaceFunctionArg.
321327
explicit SILFunctionArgument(SILType type, ValueOwnershipKind ownershipKind,
@@ -324,6 +330,10 @@ class SILFunctionArgument : public SILArgument {
324330
}
325331

326332
public:
333+
bool isNoImplicitCopy() const { return noImplicitCopy; }
334+
335+
void setNoImplicitCopy(bool newValue) { noImplicitCopy = newValue; }
336+
327337
bool isIndirectResult() const;
328338

329339
SILArgumentConvention getArgumentConvention() const;
@@ -365,6 +375,12 @@ inline bool SILArgument::isPhiArgument() const {
365375
llvm_unreachable("Covered switch is not covered?!");
366376
}
367377

378+
inline bool SILArgument::isNoImplicitCopy() const {
379+
if (auto *fArg = dyn_cast<SILFunctionArgument>(this))
380+
return fArg->isNoImplicitCopy();
381+
return false;
382+
}
383+
368384
inline bool SILArgument::isTerminatorResult() const {
369385
switch (getKind()) {
370386
case SILArgumentKind::SILPhiArgument:

lib/AST/ASTDumper.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/ASTContext.h"
1818
#include "swift/AST/ASTPrinter.h"
1919
#include "swift/AST/ASTVisitor.h"
20+
#include "swift/AST/Attr.h"
2021
#include "swift/AST/ClangModuleLoader.h"
2122
#include "swift/AST/ForeignAsyncConvention.h"
2223
#include "swift/AST/ForeignErrorConvention.h"
@@ -928,6 +929,9 @@ namespace {
928929
if (P->getAttrs().hasAttribute<NonEphemeralAttr>())
929930
OS << " nonEphemeral";
930931

932+
if (P->getAttrs().hasAttribute<NoImplicitCopyAttr>())
933+
OS << " noImplicitCopy";
934+
931935
if (P->getDefaultArgumentKind() != DefaultArgumentKind::None) {
932936
printField("default_arg",
933937
getDefaultArgumentKindString(P->getDefaultArgumentKind()));

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,13 +1573,17 @@ class DestructureInputs {
15731573
SmallVectorImpl<SILParameterInfo> &Inputs;
15741574
SubstFunctionTypeCollector &Subst;
15751575
unsigned NextOrigParamIndex = 0;
1576+
Optional<SmallBitVector> NoImplicitCopyIndices;
1577+
15761578
public:
15771579
DestructureInputs(TypeExpansionContext expansion, TypeConverter &TC,
15781580
const Conventions &conventions, const ForeignInfo &foreign,
15791581
SmallVectorImpl<SILParameterInfo> &inputs,
1580-
SubstFunctionTypeCollector &subst)
1582+
SubstFunctionTypeCollector &subst,
1583+
Optional<SmallBitVector> noImplicitCopyIndices)
15811584
: expansion(expansion), TC(TC), Convs(conventions), Foreign(foreign),
1582-
Inputs(inputs), Subst(subst) {}
1585+
Inputs(inputs), Subst(subst),
1586+
NoImplicitCopyIndices(noImplicitCopyIndices) {}
15831587

15841588
void destructure(AbstractionPattern origType,
15851589
CanAnyFunctionType::CanParamArrayRef params,
@@ -1617,14 +1621,18 @@ class DestructureInputs {
16171621
// Add any foreign parameters that are positioned here.
16181622
maybeAddForeignParameters();
16191623

1624+
bool hasNoImplicitCopy =
1625+
NoImplicitCopyIndices.hasValue() && NoImplicitCopyIndices->any();
1626+
16201627
// Process all the non-self parameters.
16211628
for (unsigned i = 0; i != numNonSelfParams; ++i) {
16221629
auto ty = params[i].getParameterType();
16231630
auto eltPattern = origType.getFunctionParamType(i);
16241631
auto flags = params[i].getParameterFlags();
16251632

16261633
visit(flags.getValueOwnership(), /*forSelf=*/false, eltPattern, ty,
1627-
flags.isNoDerivative());
1634+
flags.isNoDerivative(),
1635+
hasNoImplicitCopy && (*NoImplicitCopyIndices)[i]);
16281636
}
16291637

16301638
// Process the self parameter. Note that we implicitly drop self
@@ -1635,8 +1643,8 @@ class DestructureInputs {
16351643
auto eltPattern = origType.getFunctionParamType(numNonSelfParams);
16361644
auto flags = selfParam.getParameterFlags();
16371645

1638-
visit(flags.getValueOwnership(), /*forSelf=*/true,
1639-
eltPattern, ty);
1646+
visit(flags.getValueOwnership(), /*forSelf=*/true, eltPattern, ty, false,
1647+
false);
16401648
}
16411649

16421650
TopLevelOrigType = AbstractionPattern::getInvalid();
@@ -1645,7 +1653,7 @@ class DestructureInputs {
16451653

16461654
void visit(ValueOwnership ownership, bool forSelf,
16471655
AbstractionPattern origType, CanType substType,
1648-
bool isNonDifferentiable = false) {
1656+
bool isNonDifferentiable, bool isNoImplicitCopy) {
16491657
assert(!isa<InOutType>(substType));
16501658

16511659
// Tuples get handled specially, in some cases:
@@ -1662,9 +1670,8 @@ class DestructureInputs {
16621670
auto ownership = elt.getParameterFlags().getValueOwnership();
16631671
assert(ownership == ValueOwnership::Default);
16641672
assert(!elt.isVararg());
1665-
visit(ownership, forSelf,
1666-
origType.getTupleElementType(i),
1667-
CanType(elt.getRawType()));
1673+
visit(ownership, forSelf, origType.getTupleElementType(i),
1674+
CanType(elt.getRawType()), false, false);
16681675
}
16691676
return;
16701677
case ValueOwnership::InOut:
@@ -1692,6 +1699,9 @@ class DestructureInputs {
16921699
} else if (substTL.isTrivial()) {
16931700
convention = ParameterConvention::Direct_Unowned;
16941701
} else {
1702+
// If we are no implicit copy, our ownership is always Owned.
1703+
if (isNoImplicitCopy)
1704+
ownership = ValueOwnership::Owned;
16951705
convention = Convs.getDirect(ownership, forSelf, origParamIndex, origType,
16961706
substTLConv);
16971707
assert(!isIndirectFormalParameter(convention));
@@ -1757,9 +1767,8 @@ class DestructureInputs {
17571767
if (ForeignSelf) {
17581768
// This is a "self", but it's not a Swift self, we handle it differently.
17591769
visit(ForeignSelf->SubstSelfParam.getValueOwnership(),
1760-
/*forSelf=*/false,
1761-
ForeignSelf->OrigSelfParam,
1762-
ForeignSelf->SubstSelfParam.getParameterType());
1770+
/*forSelf=*/false, ForeignSelf->OrigSelfParam,
1771+
ForeignSelf->SubstSelfParam.getParameterType(), false, false);
17631772
}
17641773
return true;
17651774
}
@@ -2107,7 +2116,8 @@ static CanSILFunctionType getSILFunctionType(
21072116
SILExtInfoBuilder extInfoBuilder, const Conventions &conventions,
21082117
const ForeignInfo &foreignInfo, Optional<SILDeclRef> origConstant,
21092118
Optional<SILDeclRef> constant, Optional<SubstitutionMap> reqtSubs,
2110-
ProtocolConformanceRef witnessMethodConformance) {
2119+
ProtocolConformanceRef witnessMethodConformance,
2120+
Optional<SmallBitVector> noImplicitCopyIndices) {
21112121
// Find the generic parameters.
21122122
CanGenericSignature genericSig =
21132123
substFnInterfaceType.getOptGenericSignature();
@@ -2197,7 +2207,8 @@ static CanSILFunctionType getSILFunctionType(
21972207
SmallVector<SILParameterInfo, 8> inputs;
21982208
{
21992209
DestructureInputs destructurer(expansionContext, TC, conventions,
2200-
foreignInfo, inputs, subst);
2210+
foreignInfo, inputs, subst,
2211+
noImplicitCopyIndices);
22012212
destructurer.destructure(origType, substFnInterfaceType.getParams(),
22022213
extInfoBuilder);
22032214
}
@@ -2498,14 +2509,15 @@ static CanSILFunctionType getNativeSILFunctionType(
24982509
AbstractionPattern origType, CanAnyFunctionType substInterfaceType,
24992510
SILExtInfoBuilder extInfoBuilder, Optional<SILDeclRef> origConstant,
25002511
Optional<SILDeclRef> constant, Optional<SubstitutionMap> reqtSubs,
2501-
ProtocolConformanceRef witnessMethodConformance) {
2512+
ProtocolConformanceRef witnessMethodConformance,
2513+
Optional<SmallBitVector> noImplicitCopyIndices) {
25022514
assert(bool(origConstant) == bool(constant));
25032515
auto getSILFunctionTypeForConventions =
25042516
[&](const Conventions &convs) -> CanSILFunctionType {
25052517
return getSILFunctionType(TC, context, origType, substInterfaceType,
25062518
extInfoBuilder, convs, ForeignInfo(),
25072519
origConstant, constant, reqtSubs,
2508-
witnessMethodConformance);
2520+
witnessMethodConformance, noImplicitCopyIndices);
25092521
};
25102522
switch (extInfoBuilder.getRepresentation()) {
25112523
case SILFunctionType::Representation::Block:
@@ -2568,7 +2580,7 @@ CanSILFunctionType swift::getNativeSILFunctionType(
25682580

25692581
return ::getNativeSILFunctionType(
25702582
TC, context, origType, substType, silExtInfo.intoBuilder(), origConstant,
2571-
substConstant, reqtSubs, witnessMethodConformance);
2583+
substConstant, reqtSubs, witnessMethodConformance, None);
25722584
}
25732585

25742586
//===----------------------------------------------------------------------===//
@@ -2947,7 +2959,7 @@ static CanSILFunctionType getSILFunctionTypeForClangDecl(
29472959
return getSILFunctionType(
29482960
TC, TypeExpansionContext::minimal(), origPattern, substInterfaceType,
29492961
extInfoBuilder, ObjCMethodConventions(method), foreignInfo, constant,
2950-
constant, None, ProtocolConformanceRef());
2962+
constant, None, ProtocolConformanceRef(), None);
29512963
}
29522964

29532965
if (auto method = dyn_cast<clang::CXXMethodDecl>(clangDecl)) {
@@ -2963,7 +2975,7 @@ static CanSILFunctionType getSILFunctionTypeForClangDecl(
29632975
return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern,
29642976
substInterfaceType, extInfoBuilder, conventions,
29652977
foreignInfo, constant, constant, None,
2966-
ProtocolConformanceRef());
2978+
ProtocolConformanceRef(), None);
29672979
}
29682980

29692981
if (auto func = dyn_cast<clang::FunctionDecl>(clangDecl)) {
@@ -2976,7 +2988,7 @@ static CanSILFunctionType getSILFunctionTypeForClangDecl(
29762988
return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern,
29772989
substInterfaceType, extInfoBuilder,
29782990
CFunctionConventions(func), foreignInfo, constant,
2979-
constant, None, ProtocolConformanceRef());
2991+
constant, None, ProtocolConformanceRef(), None);
29802992
}
29812993

29822994
llvm_unreachable("call to unknown kind of C function");
@@ -3004,15 +3016,15 @@ static CanSILFunctionType getSILFunctionTypeForAbstractCFunction(
30043016
return getSILFunctionType(
30053017
TC, TypeExpansionContext::minimal(), origType, substType,
30063018
extInfoBuilder, CFunctionTypeConventions(fnType), ForeignInfo(),
3007-
constant, constant, None, ProtocolConformanceRef());
3019+
constant, constant, None, ProtocolConformanceRef(), None);
30083020
}
30093021
}
30103022

30113023
// TODO: Ought to support captures in block funcs.
30123024
return getSILFunctionType(TC, TypeExpansionContext::minimal(), origType,
30133025
substType, extInfoBuilder,
30143026
DefaultBlockConventions(), ForeignInfo(), constant,
3015-
constant, None, ProtocolConformanceRef());
3027+
constant, None, ProtocolConformanceRef(), None);
30163028
}
30173029

30183030
/// Try to find a clang method declaration for the given function.
@@ -3180,7 +3192,7 @@ static CanSILFunctionType getSILFunctionTypeForObjCSelectorFamily(
31803192
TC, TypeExpansionContext::minimal(), AbstractionPattern(origType),
31813193
substInterfaceType, extInfoBuilder, ObjCSelectorFamilyConventions(family),
31823194
foreignInfo, constant, constant,
3183-
/*requirement subs*/ None, ProtocolConformanceRef());
3195+
/*requirement subs*/ None, ProtocolConformanceRef(), None);
31843196
}
31853197

31863198
static bool isImporterGeneratedAccessor(const clang::Decl *clangDecl,
@@ -3250,10 +3262,23 @@ static CanSILFunctionType getUncachedSILFunctionTypeForConstant(
32503262
}
32513263
}();
32523264

3265+
Optional<SmallBitVector> noImplicitCopyIndices;
3266+
if (constant.hasDecl()) {
3267+
auto decl = constant.getDecl();
3268+
if (auto *funcDecl = dyn_cast<AbstractFunctionDecl>(decl)) {
3269+
noImplicitCopyIndices.emplace(funcDecl->getParameters()->size());
3270+
for (auto p : llvm::enumerate(*funcDecl->getParameters())) {
3271+
if (p.value()->isNoImplicitCopy()) {
3272+
noImplicitCopyIndices->set(p.index());
3273+
}
3274+
}
3275+
}
3276+
}
3277+
32533278
return ::getNativeSILFunctionType(
3254-
TC, context, origType,
3255-
origLoweredInterfaceType, extInfoBuilder, constant, constant, None,
3256-
witnessMethodConformance);
3279+
TC, context, origType, origLoweredInterfaceType, extInfoBuilder,
3280+
constant, constant, None, witnessMethodConformance,
3281+
noImplicitCopyIndices);
32573282
}
32583283

32593284
ForeignInfo foreignInfo;

0 commit comments

Comments
 (0)