Skip to content

Commit

Permalink
Add a new parameter convention @in_cxx for non-trivial C++ classes
Browse files Browse the repository at this point in the history
that are passed indirectly and destructed by the caller

Fix a bug where `@in`, which indicates the callee is responsible for
destroying the passed object, was being used to pass such classes.

rdar://122707697
  • Loading branch information
ahatanaka committed Apr 23, 2024
1 parent ed45c9c commit 4c26cbb
Show file tree
Hide file tree
Showing 60 changed files with 674 additions and 56 deletions.
25 changes: 19 additions & 6 deletions SwiftCompilerSources/Sources/SIL/Argument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,11 @@ public enum ArgumentConvention : CustomStringConvertible {
/// convention used by mutable captures in @noescape closures.
case indirectInoutAliasable

/// This argument is passed indirectly, i.e. by directly passing the address
/// of an object in memory. The callee may modify, but does not destroy the
/// object.
case indirectInCXX

/// This argument represents an indirect return value address. The callee stores
/// the returned value to this argument. At the time when the function is called,
/// the memory location referenced by the argument is uninitialized.
Expand Down Expand Up @@ -402,8 +407,9 @@ public enum ArgumentConvention : CustomStringConvertible {
public var isIndirect: Bool {
switch self {
case .indirectIn, .indirectInGuaranteed,
.indirectInout, .indirectInoutAliasable, .indirectOut,
.packOut, .packInout, .packOwned, .packGuaranteed:
.indirectInout, .indirectInoutAliasable, .indirectInCXX,
.indirectOut, .packOut, .packInout, .packOwned,
.packGuaranteed:
return true
case .directOwned, .directUnowned, .directGuaranteed:
return false
Expand All @@ -416,7 +422,8 @@ public enum ArgumentConvention : CustomStringConvertible {
.packOwned, .packGuaranteed:
return true
case .directOwned, .directUnowned, .directGuaranteed,
.indirectInout, .indirectInoutAliasable, .indirectOut,
.indirectInout, .indirectInoutAliasable, .indirectInCXX,
.indirectOut,
.packOut, .packInout:
return false
}
Expand All @@ -428,7 +435,7 @@ public enum ArgumentConvention : CustomStringConvertible {
return true
case .indirectInGuaranteed, .directGuaranteed, .packGuaranteed,
.indirectIn, .directOwned, .directUnowned,
.indirectInout, .indirectInoutAliasable,
.indirectInout, .indirectInoutAliasable, .indirectInCXX,
.packInout, .packOwned:
return false
}
Expand All @@ -439,8 +446,8 @@ public enum ArgumentConvention : CustomStringConvertible {
case .indirectInGuaranteed, .directGuaranteed, .packGuaranteed:
return true
case .indirectIn, .directOwned, .directUnowned,
.indirectInout, .indirectInoutAliasable, .indirectOut,
.packOut, .packInout, .packOwned:
.indirectInout, .indirectInoutAliasable, .indirectInCXX,
.indirectOut, .packOut, .packInout, .packOwned:
return false
}
}
Expand All @@ -451,6 +458,7 @@ public enum ArgumentConvention : CustomStringConvertible {
.indirectOut,
.indirectInGuaranteed,
.indirectInout,
.indirectInCXX,
.packOut,
.packInout,
.packOwned,
Expand All @@ -475,6 +483,7 @@ public enum ArgumentConvention : CustomStringConvertible {
case .indirectIn,
.indirectOut,
.indirectInGuaranteed,
.indirectInCXX,
.directUnowned,
.directGuaranteed,
.directOwned,
Expand All @@ -495,6 +504,8 @@ public enum ArgumentConvention : CustomStringConvertible {
return "indirectInout"
case .indirectInoutAliasable:
return "indirectInoutAliasable"
case .indirectInCXX:
return "indirectInCXX"
case .indirectOut:
return "indirectOut"
case .directOwned:
Expand Down Expand Up @@ -529,6 +540,7 @@ extension BridgedArgumentConvention {
case .Indirect_In_Guaranteed: return .indirectInGuaranteed
case .Indirect_Inout: return .indirectInout
case .Indirect_InoutAliasable: return .indirectInoutAliasable
case .Indirect_In_CXX: return .indirectInCXX
case .Indirect_Out: return .indirectOut
case .Direct_Owned: return .directOwned
case .Direct_Unowned: return .directUnowned
Expand All @@ -550,6 +562,7 @@ extension ArgumentConvention {
case .indirectInGuaranteed: return .Indirect_In_Guaranteed
case .indirectInout: return .Indirect_Inout
case .indirectInoutAliasable: return .Indirect_InoutAliasable
case .indirectInCXX: return .Indirect_In_CXX
case .indirectOut: return .Indirect_Out
case .directOwned: return .Direct_Owned
case .directUnowned: return .Direct_Unowned
Expand Down
2 changes: 1 addition & 1 deletion SwiftCompilerSources/Sources/SIL/Effects.swift
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ public struct SideEffects : CustomStringConvertible, NoReflectionChildren {
result.memory = SideEffects.Memory()
}

case .indirectInout, .indirectInoutAliasable:
case .indirectInout, .indirectInoutAliasable, .indirectInCXX:
break
}
return result
Expand Down
2 changes: 1 addition & 1 deletion SwiftCompilerSources/Sources/SIL/FunctionConvention.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public struct ParameterInfo : CustomStringConvertible {
switch convention {
case .indirectIn, .indirectInGuaranteed:
return hasLoweredAddresses || type.isOpenedExistentialWithError()
case .indirectInout, .indirectInoutAliasable:
case .indirectInout, .indirectInoutAliasable, .indirectInCXX:
return true
case .directOwned, .directUnowned, .directGuaranteed:
return false
Expand Down
10 changes: 10 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -4059,6 +4059,11 @@ enum class ParameterConvention : uint8_t {
/// convention used by mutable captures in @noescape closures.
Indirect_InoutAliasable,

/// This argument is passed indirectly, i.e. by directly passing the address
/// of an object in memory. The callee may modify, but does not destroy the
/// object.
Indirect_In_CXX,

/// This argument is passed directly. Its type is non-trivial, and the callee
/// is responsible for destroying it.
Direct_Owned,
Expand Down Expand Up @@ -4099,6 +4104,7 @@ inline bool isIndirectFormalParameter(ParameterConvention conv) {
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In_Guaranteed:
return true;

Expand All @@ -4121,6 +4127,7 @@ inline bool isConsumedParameter(ParameterConvention conv) {

case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Direct_Unowned:
case ParameterConvention::Direct_Guaranteed:
case ParameterConvention::Indirect_In_Guaranteed:
Expand All @@ -4143,6 +4150,7 @@ inline bool isGuaranteedParameter(ParameterConvention conv) {

case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In:
case ParameterConvention::Direct_Unowned:
case ParameterConvention::Direct_Owned:
Expand All @@ -4157,6 +4165,7 @@ inline bool isMutatingParameter(ParameterConvention conv) {
switch (conv) {
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Pack_Inout:
return true;

Expand All @@ -4183,6 +4192,7 @@ inline bool isPackParameter(ParameterConvention conv) {
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In:
case ParameterConvention::Direct_Guaranteed:
case ParameterConvention::Direct_Unowned:
Expand Down
1 change: 1 addition & 0 deletions include/swift/SIL/ApplySite.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ class ApplySite {
: SILArgumentConvention::Direct_Owned;
case SILArgumentConvention::Indirect_In:
case SILArgumentConvention::Indirect_In_Guaranteed:
case SILArgumentConvention::Indirect_In_CXX:
return pai->isOnStack() ? SILArgumentConvention::Indirect_In_Guaranteed
: SILArgumentConvention::Indirect_In;
case SILArgumentConvention::Pack_Guaranteed:
Expand Down
9 changes: 9 additions & 0 deletions include/swift/SIL/SILArgumentConvention.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct SILArgumentConvention {
Indirect_In_Guaranteed,
Indirect_Inout,
Indirect_InoutAliasable,
Indirect_In_CXX,
Indirect_Out,
Direct_Owned,
Direct_Unowned,
Expand Down Expand Up @@ -55,6 +56,9 @@ struct SILArgumentConvention {
case ParameterConvention::Indirect_In_Guaranteed:
Value = SILArgumentConvention::Indirect_In_Guaranteed;
return;
case ParameterConvention::Indirect_In_CXX:
Value = SILArgumentConvention::Indirect_In_CXX;
return;
case ParameterConvention::Direct_Unowned:
Value = SILArgumentConvention::Direct_Unowned;
return;
Expand Down Expand Up @@ -92,6 +96,7 @@ struct SILArgumentConvention {
case SILArgumentConvention::Indirect_In_Guaranteed:
case SILArgumentConvention::Indirect_In:
case SILArgumentConvention::Indirect_Out:
case SILArgumentConvention::Indirect_In_CXX:
case SILArgumentConvention::Direct_Unowned:
case SILArgumentConvention::Direct_Owned:
case SILArgumentConvention::Direct_Guaranteed:
Expand All @@ -114,6 +119,7 @@ struct SILArgumentConvention {
case SILArgumentConvention::Indirect_Inout:
case SILArgumentConvention::Indirect_Out:
case SILArgumentConvention::Indirect_InoutAliasable:
case SILArgumentConvention::Indirect_In_CXX:
case SILArgumentConvention::Direct_Unowned:
case SILArgumentConvention::Pack_Inout:
case SILArgumentConvention::Pack_Guaranteed:
Expand All @@ -133,6 +139,7 @@ struct SILArgumentConvention {
case SILArgumentConvention::Indirect_In:
case SILArgumentConvention::Indirect_Out:
case SILArgumentConvention::Indirect_InoutAliasable:
case SILArgumentConvention::Indirect_In_CXX:
case SILArgumentConvention::Direct_Unowned:
case SILArgumentConvention::Direct_Owned:
case SILArgumentConvention::Pack_Inout:
Expand All @@ -150,6 +157,7 @@ struct SILArgumentConvention {
case SILArgumentConvention::Indirect_Out:
case SILArgumentConvention::Indirect_In_Guaranteed:
case SILArgumentConvention::Indirect_Inout:
case SILArgumentConvention::Indirect_In_CXX:
return true;

case SILArgumentConvention::Indirect_InoutAliasable:
Expand All @@ -176,6 +184,7 @@ struct SILArgumentConvention {
case SILArgumentConvention::Indirect_In_Guaranteed:
case SILArgumentConvention::Indirect_Inout:
case SILArgumentConvention::Indirect_InoutAliasable:
case SILArgumentConvention::Indirect_In_CXX:
case SILArgumentConvention::Direct_Unowned:
case SILArgumentConvention::Direct_Guaranteed:
case SILArgumentConvention::Direct_Owned:
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ enum class BridgedArgumentConvention {
Indirect_In_Guaranteed,
Indirect_Inout,
Indirect_InoutAliasable,
Indirect_In_CXX,
Indirect_Out,
Direct_Owned,
Direct_Unowned,
Expand Down Expand Up @@ -167,6 +168,7 @@ struct BridgedParameterInfo {
case BridgedArgumentConvention::Indirect_In_Guaranteed: return swift::ParameterConvention::Indirect_In_Guaranteed;
case BridgedArgumentConvention::Indirect_Inout: return swift::ParameterConvention::Indirect_Inout;
case BridgedArgumentConvention::Indirect_InoutAliasable: return swift::ParameterConvention::Indirect_InoutAliasable;
case BridgedArgumentConvention::Indirect_In_CXX: return swift::ParameterConvention::Indirect_In_CXX;
case BridgedArgumentConvention::Indirect_Out: break;
case BridgedArgumentConvention::Direct_Owned: return swift::ParameterConvention::Direct_Owned;
case BridgedArgumentConvention::Direct_Unowned: return swift::ParameterConvention::Direct_Unowned;
Expand Down
15 changes: 9 additions & 6 deletions include/swift/SIL/SILDeclRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ struct SILDeclRef {
/// Set if this is for an async let closure.
unsigned isAsyncLetClosure : 1;

unsigned CFunctionPointer : 1;

PointerUnion<AutoDiffDerivativeFunctionIdentifier *,
const GenericSignatureImpl *, CustomAttr *>
pointer;
Expand Down Expand Up @@ -234,7 +236,7 @@ struct SILDeclRef {
: loc(), kind(Kind::Func), isForeign(0), isDistributed(0),
isKnownToBeLocal(0), isRuntimeAccessible(0),
backDeploymentKind(BackDeploymentKind::None), defaultArgIndex(0),
isAsyncLetClosure(0) {}
isAsyncLetClosure(0), CFunctionPointer(0) {}

/// Produces a SILDeclRef of the given kind for the given decl.
explicit SILDeclRef(
Expand All @@ -257,11 +259,10 @@ struct SILDeclRef {
/// for the containing ClassDecl.
/// - If 'loc' is a global VarDecl, this returns its GlobalAccessor
/// SILDeclRef.
explicit SILDeclRef(
Loc loc,
bool isForeign = false,
bool isDistributed = false,
bool isDistributedLocal = false);
explicit SILDeclRef(Loc loc, bool isForeign = false,
bool isDistributed = false,
bool isDistributedLocal = false,
bool isCFunctionPointer = false);

/// See above put produces a prespecialization according to the signature.
explicit SILDeclRef(Loc loc, GenericSignature prespecializationSig);
Expand Down Expand Up @@ -290,6 +291,8 @@ struct SILDeclRef {
bool hasAutoClosureExpr() const;
bool hasFuncDecl() const;

bool hasCFunctionPointer() const { return CFunctionPointer; }

ValueDecl *getDecl() const { return loc.dyn_cast<ValueDecl *>(); }
AbstractClosureExpr *getAbstractClosureExpr() const {
return loc.dyn_cast<AbstractClosureExpr *>();
Expand Down
1 change: 1 addition & 0 deletions include/swift/SIL/SILFunctionConventions.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ inline bool SILModuleConventions::isIndirectSILParam(SILParameterInfo param,

case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Indirect_In_CXX:
return isTypeIndirectForIndirectParamConvention(param.getInterfaceType(),
loweredAddresses);
case ParameterConvention::Indirect_Inout:
Expand Down
1 change: 1 addition & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,7 @@ static char getParamConvention(ParameterConvention conv) {
case ParameterConvention::Indirect_Inout: return 'l';
case ParameterConvention::Indirect_InoutAliasable: return 'b';
case ParameterConvention::Indirect_In_Guaranteed: return 'n';
case ParameterConvention::Indirect_In_CXX: return 'C';
case ParameterConvention::Direct_Owned: return 'x';
case ParameterConvention::Direct_Unowned: return 'y';
case ParameterConvention::Direct_Guaranteed: return 'g';
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6731,6 +6731,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In_Guaranteed:
llvm_unreachable("callee convention cannot be indirect");
case ParameterConvention::Pack_Guaranteed:
Expand Down Expand Up @@ -7500,6 +7501,7 @@ StringRef swift::getStringForParameterConvention(ParameterConvention conv) {
case ParameterConvention::Indirect_In_Guaranteed: return "@in_guaranteed ";
case ParameterConvention::Indirect_Inout: return "@inout ";
case ParameterConvention::Indirect_InoutAliasable: return "@inout_aliasable ";
case ParameterConvention::Indirect_In_CXX: return "@in_cxx ";
case ParameterConvention::Direct_Owned: return "@owned ";
case ParameterConvention::Direct_Unowned: return "";
case ParameterConvention::Direct_Guaranteed: return "@guaranteed ";
Expand Down
1 change: 1 addition & 0 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2160,6 +2160,7 @@ NodePointer Demangler::demangleImplParamConvention(Node::Kind ConvKind) {
case 'l': attr = "@inout"; break;
case 'b': attr = "@inout_aliasable"; break;
case 'n': attr = "@in_guaranteed"; break;
case 'C': attr = "@in_cxx"; break;
case 'x': attr = "@owned"; break;
case 'g': attr = "@guaranteed"; break;
case 'e': attr = "@deallocating"; break;
Expand Down
1 change: 1 addition & 0 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2109,6 +2109,7 @@ ManglingError Remangler::mangleImplFunctionType(Node *node, unsigned depth) {
.Case("@inout", 'l')
.Case("@inout_aliasable", 'b')
.Case("@in_guaranteed", 'n')
.Case("@in_cxx", 'C')
.Case("@in_constant", 'c')
.Case("@owned", 'x')
.Case("@guaranteed", 'g')
Expand Down
1 change: 1 addition & 0 deletions lib/IRGen/GenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1638,6 +1638,7 @@ const TypeInfo &SignatureExpansion::expand(SILParameterInfo param) {
switch (auto conv = param.getConvention()) {
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Indirect_In_CXX:
addIndirectValueParameterAttributes(IGM, Attrs, ti, ParamIRTypes.size());
addPointerParameter(IGM.getStorageType(getSILFuncConventions().getSILType(
param, IGM.getMaximalTypeExpansionContext())));
Expand Down
1 change: 1 addition & 0 deletions lib/IRGen/GenDistributed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ void DistributedAccessor::decodeArgument(unsigned argumentIdx,
break;
}

case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In_Guaranteed: {
// The argument is +0, so we can use the address of the param in
// the context directly.
Expand Down
5 changes: 5 additions & 0 deletions lib/IRGen/GenFunc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,7 @@ CanType irgen::getArgumentLoweringType(CanType type, SILParameterInfo paramInfo,
// address.
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Indirect_In_CXX:
if (isNoEscape)
return CanInOutType::get(type);
else
Expand Down Expand Up @@ -1508,6 +1509,7 @@ static llvm::Value *emitPartialApplicationForwarder(
break;
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Pack_Guaranteed:
Expand Down Expand Up @@ -1625,6 +1627,7 @@ static llvm::Value *emitPartialApplicationForwarder(
break;

case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Direct_Guaranteed:
dependsOnContextLifetime = true;
if (outType->getCalleeConvention() ==
Expand Down Expand Up @@ -1750,6 +1753,7 @@ static llvm::Value *emitPartialApplicationForwarder(
}
break;
}
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In_Guaranteed:
if (outType->isNoEscape()) {
cast<LoadableTypeInfo>(fieldTI).loadAsCopy(subIGF, fieldAddr, param);
Expand Down Expand Up @@ -2301,6 +2305,7 @@ std::optional<StackAddress> irgen::emitFunctionPartialApplication(
switch (argConventions[i]) {
// Take indirect value arguments out of memory.
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In_Guaranteed: {
if (outType->isNoEscape()) {
cast<LoadableTypeInfo>(fieldLayout.getType())
Expand Down
Loading

0 comments on commit 4c26cbb

Please sign in to comment.