3030#include " swift/ClangImporter/ClangImporter.h"
3131#include " swift/IRGen/IRABIDetailsProvider.h"
3232#include " clang/AST/ASTContext.h"
33+ #include " clang/AST/Attr.h"
3334#include " clang/AST/DeclObjC.h"
3435#include " llvm/ADT/STLExtras.h"
3536
@@ -281,6 +282,25 @@ class CFunctionSignatureTypePrinter
281282 os << " __strong" ;
282283 printInoutTypeModifier ();
283284 }
285+ if (isa<clang::CXXRecordDecl>(cd->getClangDecl ())) {
286+ if (std::find_if (
287+ cd->getClangDecl ()->getAttrs ().begin (),
288+ cd->getClangDecl ()->getAttrs ().end (), [](clang::Attr *attr) {
289+ if (auto *sa = dyn_cast<clang::SwiftAttrAttr>(attr)) {
290+ llvm::StringRef value = sa->getAttribute ();
291+ if ((value.startswith (" retain:" ) ||
292+ value.startswith (" release:" )) &&
293+ !value.endswith (" :immortal" ))
294+ return true ;
295+ }
296+ return false ;
297+ }) != cd->getClangDecl ()->getAttrs ().end ()) {
298+ // This is a shared FRT. Do not bridge it back to
299+ // C++ as its ownership is not managed automatically
300+ // in C++ yet.
301+ return ClangRepresentation::unsupported;
302+ }
303+ }
284304 // FIXME: Mark that this is only ObjC representable.
285305 return ClangRepresentation::representable;
286306 }
@@ -966,7 +986,7 @@ void DeclAndTypeClangFunctionPrinter::printTypeImplTypeSpecifier(
966986
967987void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse (
968988 Type type, StringRef name, const ModuleDecl *moduleContext, bool isInOut,
969- bool isIndirect, std::string directTypeEncoding, bool isSelf ) {
989+ bool isIndirect, std::string directTypeEncoding, bool forceSelf ) {
970990 auto namePrinter = [&]() { ClangSyntaxPrinter (os).printIdentifier (name); };
971991 if (!isKnownCxxType (type, typeMapping) &&
972992 !hasKnownOptionalNullableCxxMapping (type)) {
@@ -1007,9 +1027,9 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
10071027 } else {
10081028 ClangValueTypePrinter (os, cPrologueOS, interopContext)
10091029 .printParameterCxxToCUseScaffold (
1010- moduleContext,
1011- [&]() { printTypeImplTypeSpecifier (type, moduleContext); },
1012- namePrinter, isSelf );
1030+ moduleContext,
1031+ [&]() { printTypeImplTypeSpecifier (type, moduleContext); },
1032+ namePrinter, forceSelf );
10131033 }
10141034 if (!directTypeEncoding.empty ())
10151035 os << ' )' ;
@@ -1153,6 +1173,82 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
11531173 break ;
11541174 }
11551175 }
1176+
1177+ auto getParamName = [&](const ParamDecl ¶m, size_t paramIndex,
1178+ bool isConsumed) {
1179+ std::string paramName;
1180+ if (isConsumed)
1181+ paramName = " consumedParamCopy_" ;
1182+ if (param.isSelfParameter ()) {
1183+ if (isConsumed)
1184+ paramName += " this" ;
1185+ else
1186+ paramName = " *this" ;
1187+ } else if (param.getName ().empty ()) {
1188+ llvm::raw_string_ostream paramOS (paramName);
1189+ if (!isConsumed)
1190+ paramOS << " _" ;
1191+ paramOS << paramIndex;
1192+ } else {
1193+ StringRef nameStr = param.getName ().str ();
1194+ if (isConsumed)
1195+ paramName += nameStr.str ();
1196+ else
1197+ paramName = nameStr;
1198+ renameCxxParameterIfNeeded (FD, paramName);
1199+ }
1200+ return paramName;
1201+ };
1202+
1203+ // Check if we need to copy any parameters that are consumed by Swift,
1204+ // to ensure that Swift does not destroy the value that's owned by C++.
1205+ // FIXME: Support non-copyable types here as well between C++ -> Swift.
1206+ // FIXME: class types can be optimized down to an additional retain right
1207+ // here.
1208+ size_t paramIndex = 1 ;
1209+ auto emitParamCopyForConsume = [&](const ParamDecl ¶m) {
1210+ auto name = getParamName (param, paramIndex, /* isConsumed=*/ false );
1211+ auto consumedName = getParamName (param, paramIndex, /* isConsumed=*/ true );
1212+ std::string paramType;
1213+
1214+ llvm::raw_string_ostream typeOS (paramType);
1215+
1216+ CFunctionSignatureTypePrinter typePrinter (
1217+ typeOS, cPrologueOS, typeMapping, OutputLanguageMode::Cxx,
1218+ interopContext, CFunctionSignatureTypePrinterModifierDelegate (),
1219+ moduleContext, declPrinter, FunctionSignatureTypeUse::TypeReference);
1220+ auto result = typePrinter.visit (param.getInterfaceType (), OTK_None,
1221+ /* isInOutParam=*/ false );
1222+ assert (!result.isUnsupported ());
1223+ typeOS.flush ();
1224+
1225+ os << " alignas(alignof(" << paramType << " )) char copyBuffer_"
1226+ << consumedName << " [sizeof(" << paramType << " )];\n " ;
1227+ os << " auto &" << consumedName << " = *(new(copyBuffer_" << consumedName
1228+ << " ) " << paramType << " (" << name << " ));\n " ;
1229+ os << " swift::" << cxx_synthesis::getCxxImplNamespaceName ()
1230+ << " ::ConsumedValueStorageDestroyer<" << paramType << " > storageGuard_"
1231+ << consumedName << " (" << consumedName << " );\n " ;
1232+ };
1233+ signature.visitParameterList (
1234+ [&](const LoweredFunctionSignature::IndirectResultValue &) {},
1235+ [&](const LoweredFunctionSignature::DirectParameter ¶m) {
1236+ if (isConsumedParameter (param.getConvention ()))
1237+ emitParamCopyForConsume (param.getParamDecl ());
1238+ ++paramIndex;
1239+ },
1240+ [&](const LoweredFunctionSignature::IndirectParameter ¶m) {
1241+ if (isConsumedParameter (param.getConvention ()))
1242+ emitParamCopyForConsume (param.getParamDecl ());
1243+ ++paramIndex;
1244+ },
1245+ [&](const LoweredFunctionSignature::GenericRequirementParameter
1246+ &genericRequirementParam) {},
1247+ [&](const LoweredFunctionSignature::MetadataSourceParameter
1248+ &metadataSrcParam) {},
1249+ [&](const LoweredFunctionSignature::ContextParameter &) {},
1250+ [&](const LoweredFunctionSignature::ErrorResultValue &) {});
1251+
11561252 auto printCallToCFunc = [&](llvm::Optional<StringRef> additionalParam) {
11571253 if (indirectFunctionVar)
11581254 os << " (* " << *indirectFunctionVar << ' )' ;
@@ -1168,13 +1264,14 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
11681264 needsComma = true ;
11691265 };
11701266 auto printParamUse = [&](const ParamDecl ¶m, bool isIndirect,
1267+ bool isConsumed,
11711268
11721269 std::string directTypeEncoding) {
11731270 emitNewParam ();
1174- std::string paramName;
11751271 if (param.isSelfParameter ()) {
11761272 bool needsStaticSelf = isa<ConstructorDecl>(FD) || isStaticMethod;
11771273 if (needsStaticSelf) {
1274+ // Static self value is just the type's metadata value.
11781275 os << " swift::TypeMetadataTrait<" ;
11791276 CFunctionSignatureTypePrinter typePrinter (
11801277 os, cPrologueOS, typeMapping, OutputLanguageMode::Cxx,
@@ -1187,19 +1284,13 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
11871284 os << " >::getTypeMetadata()" ;
11881285 return ;
11891286 }
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);
11971287 }
1288+ auto paramName = getParamName (param, paramIndex, isConsumed);
11981289 ++paramIndex;
11991290 printCxxToCFunctionParameterUse (param.getInterfaceType (), paramName,
12001291 param.getModuleContext (), param.isInOut (),
12011292 isIndirect, directTypeEncoding,
1202- param.isSelfParameter ());
1293+ !isConsumed && param.isSelfParameter ());
12031294 };
12041295
12051296 signature.visitParameterList (
@@ -1211,10 +1302,12 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
12111302 },
12121303 [&](const LoweredFunctionSignature::DirectParameter ¶m) {
12131304 printParamUse (param.getParamDecl (), /* isIndirect=*/ false ,
1305+ isConsumedParameter (param.getConvention ()),
12141306 encodeTypeInfo (param, moduleContext, typeMapping));
12151307 },
12161308 [&](const LoweredFunctionSignature::IndirectParameter ¶m) {
12171309 printParamUse (param.getParamDecl (), /* isIndirect=*/ true ,
1310+ isConsumedParameter (param.getConvention ()),
12181311 /* directTypeEncoding=*/ " " );
12191312 },
12201313 [&](const LoweredFunctionSignature::GenericRequirementParameter
0 commit comments