@@ -2041,6 +2041,101 @@ namespace {
2041
2041
fd->getAttrs ().add (new (Impl.SwiftContext ) UnsafeAttr (/* Implicit=*/ true ));
2042
2042
}
2043
2043
2044
+ void
2045
+ generateStaticFactoryForCXXForeignRef (clang::ASTContext &clangCtx,
2046
+ ClassDecl *result,
2047
+ clang::CXXRecordDecl *cxxRecordDecl,
2048
+ ClangImporter::Implementation &Impl) {
2049
+
2050
+ // Creating a name for the new synthesized function
2051
+ clang::IdentifierTable &idents = clangCtx.Idents ;
2052
+ clang::IdentifierInfo *generatedFuncName =
2053
+ &idents.get ((" __returns" + cxxRecordDecl->getNameAsString ()).c_str ());
2054
+
2055
+ // Creating the return type for the synthesized function to be the
2056
+ // pointe to cxxRecordDecl
2057
+ const clang::Type *cxxRecordDeclTypePtr = cxxRecordDecl->getTypeForDecl ();
2058
+ clang::QualType cxxRecordTy (cxxRecordDeclTypePtr, 0 );
2059
+ clang::QualType cxxRecordPtrTy = clangCtx.getPointerType (cxxRecordTy);
2060
+ // TODO/DOUBT: How to add `_Nonnull` as a qualifier on cxxRecordPtrTy
2061
+ // return type ??
2062
+
2063
+ // Creating the type for the synthesized function
2064
+ clang::FunctionProtoType::ExtProtoInfo EPI;
2065
+ clang::QualType generatedFuncTy =
2066
+ clangCtx.getFunctionType (cxxRecordPtrTy, {}, EPI);
2067
+
2068
+ clang::CXXMethodDecl *generatedCxxMethodDecl =
2069
+ clang::CXXMethodDecl::Create (
2070
+ clangCtx, cxxRecordDecl, cxxRecordDecl->getLocation (),
2071
+ clang::DeclarationNameInfo (generatedFuncName,
2072
+ clang::SourceLocation ()),
2073
+ generatedFuncTy, nullptr , clang::SC_Static, false , true ,
2074
+ clang::ConstexprSpecKind::Unspecified, clang::SourceLocation ());
2075
+
2076
+ // Create and attach "returns_retained" attribute to synthesized method
2077
+ clang::SwiftAttrAttr *returnsRetainedAttr =
2078
+ clang::SwiftAttrAttr::Create (clangCtx, " returns_retained" );
2079
+ generatedCxxMethodDecl->addAttr (returnsRetainedAttr);
2080
+
2081
+ // Create and attach "swift_name("init()")" attribute to synthesized
2082
+ // method
2083
+ clang::SwiftNameAttr *swiftNameInitAttr =
2084
+ clang::SwiftNameAttr::Create (clangCtx, " init()" );
2085
+ generatedCxxMethodDecl->addAttr (swiftNameInitAttr);
2086
+
2087
+ // Set the access specifier of the generated factory method to public
2088
+ generatedCxxMethodDecl->setAccess (clang::AccessSpecifier::AS_public);
2089
+
2090
+ // Getting the default constructor
2091
+ clang::CXXConstructorDecl *ctorDecl = nullptr ;
2092
+ for (clang::CXXConstructorDecl *ctor : cxxRecordDecl->ctors ()) {
2093
+ if (ctor->isDefaultConstructor () && !ctor->isDeleted ()) {
2094
+ ctorDecl = ctor;
2095
+ break ;
2096
+ }
2097
+ }
2098
+
2099
+ if (ctorDecl) {
2100
+ // Build the constructor expression using the default constructor decl
2101
+ clang::ExprResult generatedConstructExpr =
2102
+ Impl.getClangSema ().BuildCXXConstructExpr (
2103
+ clang::SourceLocation (), cxxRecordTy, ctorDecl, false ,
2104
+ clang::MultiExprArg (), false , false , false ,
2105
+ true , // TODO: fix the propagation of this zeroinit flag to
2106
+ // BuildCXXNew
2107
+ clang::CXXConstructionKind::Complete, clang::SourceRange ());
2108
+
2109
+ if (!generatedConstructExpr.isInvalid ()) {
2110
+ // Build the new expr by passing the constructor expression as an
2111
+ // initializer
2112
+ clang::ExprResult generatedNewExprResult =
2113
+ Impl.getClangSema ().BuildCXXNew (
2114
+ clang::SourceRange (), false , clang::SourceLocation (), {},
2115
+ clang::SourceLocation (), clang::SourceRange (), cxxRecordTy,
2116
+ clangCtx.getTrivialTypeSourceInfo (cxxRecordTy), std::nullopt,
2117
+ clang::SourceRange (), generatedConstructExpr.get ());
2118
+
2119
+ if (!generatedNewExprResult.isInvalid ()) {
2120
+ // synthesizing the body of the generatedCxxMethodDecl
2121
+ clang::CXXNewExpr *generatedNewExpr =
2122
+ cast<clang::CXXNewExpr>(generatedNewExprResult.get ());
2123
+ clang::ReturnStmt *generatedRetStmt = clang::ReturnStmt::Create (
2124
+ clangCtx, clang::SourceLocation (), generatedNewExpr, nullptr );
2125
+ clang::CompoundStmt *generatedFuncBody =
2126
+ clang::CompoundStmt::Create (
2127
+ clangCtx, {generatedRetStmt}, clang::FPOptionsOverride (),
2128
+ clang::SourceLocation (), clang::SourceLocation ());
2129
+ generatedCxxMethodDecl->setBody (generatedFuncBody);
2130
+ // generatedCxxMethodDecl->dump();
2131
+ if (Decl *importedInitDecl =
2132
+ VisitCXXMethodDecl (generatedCxxMethodDecl))
2133
+ result->addMember (importedInitDecl);
2134
+ }
2135
+ }
2136
+ }
2137
+ }
2138
+
2044
2139
Decl *VisitRecordDecl (const clang::RecordDecl *decl) {
2045
2140
// Track whether this record contains fields we can't reference in Swift
2046
2141
// as stored properties.
@@ -2472,14 +2567,25 @@ namespace {
2472
2567
ctors.push_back (valueCtor);
2473
2568
}
2474
2569
2475
- // Do not allow Swift to construct foreign reference types (at least, not
2476
- // yet).
2477
2570
if (isa<StructDecl>(result)) {
2478
2571
for (auto ctor : ctors) {
2479
2572
// Add ctors directly as they cannot always be looked up from the
2480
2573
// clang decl (some are synthesized by Swift).
2481
2574
result->addMember (ctor);
2482
2575
}
2576
+ } else {
2577
+ assert (isa<ClassDecl>(result) && " Expected result to be a ClassDecl "
2578
+ " for C/C++ foreign reference types" );
2579
+ if (auto *cxxRecordDecl = const_cast <clang::CXXRecordDecl *>(
2580
+ dyn_cast<clang::CXXRecordDecl>(decl))) {
2581
+ // For C++ foreign reference types, generate a static factory method
2582
+ // to construct the object and import it as a Swift initializer.
2583
+ generateStaticFactoryForCXXForeignRef (cxxRecordDecl->getASTContext (),
2584
+ cast<ClassDecl>(result), cxxRecordDecl, Impl);
2585
+ } else {
2586
+ // TODO: Should we synthesize the factories for C foreign reference
2587
+ // types as well?
2588
+ }
2483
2589
}
2484
2590
2485
2591
if (auto structResult = dyn_cast<StructDecl>(result)) {
0 commit comments