@@ -966,7 +966,7 @@ void DeclAndTypeClangFunctionPrinter::printTypeImplTypeSpecifier(
966966
967967void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse (
968968 Type type, StringRef name, const ModuleDecl *moduleContext, bool isInOut,
969- bool isIndirect, std::string directTypeEncoding, bool isSelf ) {
969+ bool isIndirect, std::string directTypeEncoding, bool forceSelf ) {
970970 auto namePrinter = [&]() { ClangSyntaxPrinter (os).printIdentifier (name); };
971971 if (!isKnownCxxType (type, typeMapping) &&
972972 !hasKnownOptionalNullableCxxMapping (type)) {
@@ -1007,9 +1007,9 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
10071007 } else {
10081008 ClangValueTypePrinter (os, cPrologueOS, interopContext)
10091009 .printParameterCxxToCUseScaffold (
1010- moduleContext,
1011- [&]() { printTypeImplTypeSpecifier (type, moduleContext); },
1012- namePrinter, isSelf );
1010+ moduleContext,
1011+ [&]() { printTypeImplTypeSpecifier (type, moduleContext); },
1012+ namePrinter, forceSelf );
10131013 }
10141014 if (!directTypeEncoding.empty ())
10151015 os << ' )' ;
@@ -1153,6 +1153,82 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
11531153 break ;
11541154 }
11551155 }
1156+
1157+ auto getParamName = [&](const ParamDecl ¶m, size_t paramIndex,
1158+ bool isConsumed) {
1159+ std::string paramName;
1160+ if (isConsumed)
1161+ paramName = " consumedParamCopy_" ;
1162+ if (param.isSelfParameter ()) {
1163+ if (isConsumed)
1164+ paramName += " this" ;
1165+ else
1166+ paramName = " *this" ;
1167+ } else if (param.getName ().empty ()) {
1168+ llvm::raw_string_ostream paramOS (paramName);
1169+ if (!isConsumed)
1170+ paramOS << " _" ;
1171+ paramOS << paramIndex;
1172+ } else {
1173+ StringRef nameStr = param.getName ().str ();
1174+ if (isConsumed)
1175+ paramName += nameStr.str ();
1176+ else
1177+ paramName = nameStr;
1178+ renameCxxParameterIfNeeded (FD, paramName);
1179+ }
1180+ return paramName;
1181+ };
1182+
1183+ // Check if we need to copy any parameters that are consumed by Swift,
1184+ // to ensure that Swift does not destroy the value that's owned by C++.
1185+ // FIXME: Support non-copyable types here as well between C++ -> Swift.
1186+ // FIXME: class types can be optimized down to an additional retain right
1187+ // here.
1188+ size_t paramIndex = 1 ;
1189+ auto emitParamCopyForConsume = [&](const ParamDecl ¶m) {
1190+ auto name = getParamName (param, paramIndex, /* isConsumed=*/ false );
1191+ auto consumedName = getParamName (param, paramIndex, /* isConsumed=*/ true );
1192+ std::string paramType;
1193+
1194+ llvm::raw_string_ostream typeOS (paramType);
1195+
1196+ CFunctionSignatureTypePrinter typePrinter (
1197+ typeOS, cPrologueOS, typeMapping, OutputLanguageMode::Cxx,
1198+ interopContext, CFunctionSignatureTypePrinterModifierDelegate (),
1199+ moduleContext, declPrinter, FunctionSignatureTypeUse::TypeReference);
1200+ auto result = typePrinter.visit (param.getInterfaceType (), OTK_None,
1201+ /* isInOutParam=*/ false );
1202+ assert (!result.isUnsupported ());
1203+ typeOS.flush ();
1204+
1205+ os << " alignas(alignof(" << paramType << " )) char copyBuffer_"
1206+ << consumedName << " [sizeof(" << paramType << " )];\n " ;
1207+ os << " auto &" << consumedName << " = *(new(copyBuffer_" << consumedName
1208+ << " ) " << paramType << " (" << name << " ));\n " ;
1209+ os << " swift::" << cxx_synthesis::getCxxImplNamespaceName ()
1210+ << " ::ConsumedValueStorageDestroyer<" << paramType << " > storageGuard_"
1211+ << consumedName << " (" << consumedName << " );\n " ;
1212+ };
1213+ signature.visitParameterList (
1214+ [&](const LoweredFunctionSignature::IndirectResultValue &) {},
1215+ [&](const LoweredFunctionSignature::DirectParameter ¶m) {
1216+ if (isConsumedParameter (param.getConvention ()))
1217+ emitParamCopyForConsume (param.getParamDecl ());
1218+ ++paramIndex;
1219+ },
1220+ [&](const LoweredFunctionSignature::IndirectParameter ¶m) {
1221+ if (isConsumedParameter (param.getConvention ()))
1222+ emitParamCopyForConsume (param.getParamDecl ());
1223+ ++paramIndex;
1224+ },
1225+ [&](const LoweredFunctionSignature::GenericRequirementParameter
1226+ &genericRequirementParam) {},
1227+ [&](const LoweredFunctionSignature::MetadataSourceParameter
1228+ &metadataSrcParam) {},
1229+ [&](const LoweredFunctionSignature::ContextParameter &) {},
1230+ [&](const LoweredFunctionSignature::ErrorResultValue &) {});
1231+
11561232 auto printCallToCFunc = [&](llvm::Optional<StringRef> additionalParam) {
11571233 if (indirectFunctionVar)
11581234 os << " (* " << *indirectFunctionVar << ' )' ;
@@ -1168,13 +1244,14 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
11681244 needsComma = true ;
11691245 };
11701246 auto printParamUse = [&](const ParamDecl ¶m, bool isIndirect,
1247+ bool isConsumed,
11711248
11721249 std::string directTypeEncoding) {
11731250 emitNewParam ();
1174- std::string paramName;
11751251 if (param.isSelfParameter ()) {
11761252 bool needsStaticSelf = isa<ConstructorDecl>(FD) || isStaticMethod;
11771253 if (needsStaticSelf) {
1254+ // Static self value is just the type's metadata value.
11781255 os << " swift::TypeMetadataTrait<" ;
11791256 CFunctionSignatureTypePrinter typePrinter (
11801257 os, cPrologueOS, typeMapping, OutputLanguageMode::Cxx,
@@ -1187,19 +1264,13 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
11871264 os << " >::getTypeMetadata()" ;
11881265 return ;
11891266 }
1190- paramName = " *this" ;
1191- } else if (param.getName ().empty ()) {
1192- llvm::raw_string_ostream paramOS (paramName);
1193- paramOS << " _" << paramIndex;
1194- } else {
1195- paramName = param.getName ().str ().str ();
1196- renameCxxParameterIfNeeded (FD, paramName);
11971267 }
1268+ auto paramName = getParamName (param, paramIndex, isConsumed);
11981269 ++paramIndex;
11991270 printCxxToCFunctionParameterUse (param.getInterfaceType (), paramName,
12001271 param.getModuleContext (), param.isInOut (),
12011272 isIndirect, directTypeEncoding,
1202- param.isSelfParameter ());
1273+ !isConsumed && param.isSelfParameter ());
12031274 };
12041275
12051276 signature.visitParameterList (
@@ -1211,10 +1282,12 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
12111282 },
12121283 [&](const LoweredFunctionSignature::DirectParameter ¶m) {
12131284 printParamUse (param.getParamDecl (), /* isIndirect=*/ false ,
1285+ isConsumedParameter (param.getConvention ()),
12141286 encodeTypeInfo (param, moduleContext, typeMapping));
12151287 },
12161288 [&](const LoweredFunctionSignature::IndirectParameter ¶m) {
12171289 printParamUse (param.getParamDecl (), /* isIndirect=*/ true ,
1290+ isConsumedParameter (param.getConvention ()),
12181291 /* directTypeEncoding=*/ " " );
12191292 },
12201293 [&](const LoweredFunctionSignature::GenericRequirementParameter
0 commit comments