Skip to content

Commit bd003bc

Browse files
authored
Merge pull request #59509 from zoecarver/frt-with-ref-counting
[cxx-interop] Add support for reference counting operations on foreign reference types.
2 parents 3784f4a + 8134567 commit bd003bc

36 files changed

+703
-88
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4241,15 +4241,7 @@ class ClassDecl final : public NominalTypeDecl {
42414241

42424242
/// Whether the class uses the ObjC object model (reference counting,
42434243
/// allocation, etc.), the Swift model, or has no reference counting at all.
4244-
ReferenceCounting getObjectModel() const {
4245-
if (isForeignReferenceType())
4246-
return ReferenceCounting::None;
4247-
4248-
if (checkAncestry(AncestryFlags::ObjCObjectModel))
4249-
return ReferenceCounting::ObjC;
4250-
4251-
return ReferenceCounting::Native;
4252-
}
4244+
ReferenceCounting getObjectModel() const;
42534245

42544246
LayoutConstraintKind getLayoutConstraintKind() const {
42554247
if (getObjectModel() == ReferenceCounting::ObjC)
@@ -4363,6 +4355,8 @@ class ClassDecl final : public NominalTypeDecl {
43634355
/// non-reference-counted swift reference type that was imported from a C++
43644356
/// record.
43654357
bool isForeignReferenceType() const;
4358+
4359+
bool hasRefCountingAnnotations() const;
43664360
};
43674361

43684362
/// The set of known protocols for which derived conformances are supported.

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,27 @@ NOTE(dont_use_iterator_api, none, "C++ method '%0' that returns an unsafe "
170170
"APIs instead",
171171
(StringRef))
172172

173+
ERROR(reference_type_must_have_retain_attr,none,
174+
"reference type '%0' must have 'retain:' swift attribute.", (StringRef))
175+
ERROR(reference_type_must_have_release_attr,none,
176+
"reference type '%0' must have 'release:' swift attribute.", (StringRef))
177+
ERROR(foreign_reference_types_cannot_find_retain,none,
178+
"cannot find retain function '%0' for reference type '%1'.", (StringRef, StringRef))
179+
ERROR(foreign_reference_types_cannot_find_release,none,
180+
"cannot find release function '%0' for reference type '%1'.", (StringRef, StringRef))
181+
ERROR(too_many_reference_type_retain_operations,none,
182+
"too many functions with name '%0'. There must be exactly one retain "
183+
"function for reference type '%1'.", (StringRef, StringRef))
184+
ERROR(too_many_reference_type_release_operations,none,
185+
"too many functions with name '%0'. There must be exactly one release "
186+
"function for reference type '%1'.", (StringRef, StringRef))
187+
ERROR(foreign_reference_types_invalid_retain,none,
188+
"specified retain function '%0' is invalid. Retain must have exactly one "
189+
"argument of type '%1'", (StringRef, StringRef))
190+
ERROR(foreign_reference_types_invalid_release,none,
191+
"specified release function '%0' is invalid. Release must have exactly "
192+
"one argument of type '%1'", (StringRef, StringRef))
193+
173194
NOTE(unsupported_builtin_type, none, "built-in type '%0' not supported", (StringRef))
174195
NOTE(record_field_not_imported, none, "field %0 not imported", (const clang::NamedDecl*))
175196
NOTE(invoked_func_not_imported, none, "function %0 not imported", (const clang::NamedDecl*))

include/swift/AST/DiagnosticsIRGen.def

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,5 @@ ERROR(temporary_allocation_alignment_not_positive,none,
5959
ERROR(temporary_allocation_alignment_not_power_of_2,none,
6060
"alignment value must be a power of two", ())
6161

62-
ERROR(foreign_reference_types_unsupported,none,
63-
"attempt to use a foreign reference type in a generic context. "
64-
"Foreign reference types are currently not supported. Using foreign "
65-
"reference types in a generic context is not yet implemented.", ())
66-
6762
#define UNDEFINE_DIAGNOSTIC_MACROS
6863
#include "DefineDiagnosticMacros.h"

include/swift/AST/ReferenceCounting.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ enum class ReferenceCounting : uint8_t {
3333
/// types.
3434
None,
3535

36+
/// The object uses swift_attr("retain:XXX") and "release:XXX" to implement
37+
/// reference counting.
38+
Custom,
39+
3640
/// The object uses _Block_copy/_Block_release reference counting.
3741
///
3842
/// This is a strict subset of ObjC; all blocks are also ObjC reference

include/swift/Basic/Compiler.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,9 @@
180180

181181
// Tells Swift's ClangImporter to import a C++ type as a foreign reference type.
182182
#if __has_attribute(swift_attr)
183-
#define SWIFT_IMPORT_REFERENCE __attribute__((swift_attr("import_reference")))
183+
#define SWIFT_IMPORT_REFERENCE __attribute__((swift_attr("import_reference"))) \
184+
__attribute__((swift_attr("retain:immortal"))) \
185+
__attribute__((swift_attr("release:immortal")))
184186
#else
185187
#define SWIFT_IMPORT_REFERENCE
186188
#endif

include/swift/ClangImporter/ClangImporterRequests.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,73 @@ class IsSafeUseOfCxxDecl
285285
bool evaluate(Evaluator &evaluator, SafeUseOfCxxDeclDescriptor desc) const;
286286
};
287287

288+
enum class CustomRefCountingOperationKind { retain, release };
289+
290+
struct CustomRefCountingOperationDescriptor final {
291+
const ClassDecl *decl;
292+
CustomRefCountingOperationKind kind;
293+
294+
CustomRefCountingOperationDescriptor(const ClassDecl *decl,
295+
CustomRefCountingOperationKind kind)
296+
: decl(decl), kind(kind) {}
297+
298+
friend llvm::hash_code
299+
hash_value(const CustomRefCountingOperationDescriptor &desc) {
300+
return llvm::hash_combine(desc.decl, desc.kind);
301+
}
302+
303+
friend bool operator==(const CustomRefCountingOperationDescriptor &lhs,
304+
const CustomRefCountingOperationDescriptor &rhs) {
305+
return lhs.decl == rhs.decl && lhs.kind == rhs.kind;
306+
}
307+
308+
friend bool operator!=(const CustomRefCountingOperationDescriptor &lhs,
309+
const CustomRefCountingOperationDescriptor &rhs) {
310+
return !(lhs == rhs);
311+
}
312+
};
313+
314+
void simple_display(llvm::raw_ostream &out,
315+
CustomRefCountingOperationDescriptor desc);
316+
SourceLoc extractNearestSourceLoc(CustomRefCountingOperationDescriptor desc);
317+
318+
struct CustomRefCountingOperationResult {
319+
enum CustomRefCountingOperationResultKind {
320+
noAttribute,
321+
immortal,
322+
notFound,
323+
tooManyFound,
324+
foundOperation
325+
};
326+
327+
CustomRefCountingOperationResultKind kind;
328+
ValueDecl *operation;
329+
std::string name;
330+
};
331+
332+
class CustomRefCountingOperation
333+
: public SimpleRequest<CustomRefCountingOperation,
334+
CustomRefCountingOperationResult(
335+
CustomRefCountingOperationDescriptor),
336+
RequestFlags::Cached> {
337+
public:
338+
using SimpleRequest::SimpleRequest;
339+
340+
// Caching
341+
bool isCached() const { return true; }
342+
343+
// Source location
344+
SourceLoc getNearestLoc() const { return SourceLoc(); };
345+
346+
private:
347+
friend SimpleRequest;
348+
349+
// Evaluation.
350+
CustomRefCountingOperationResult
351+
evaluate(Evaluator &evaluator,
352+
CustomRefCountingOperationDescriptor desc) const;
353+
};
354+
288355
#define SWIFT_TYPEID_ZONE ClangImporter
289356
#define SWIFT_TYPEID_HEADER "swift/ClangImporter/ClangImporterTypeIDZone.def"
290357
#include "swift/Basic/DefineTypeIDZone.h"

include/swift/ClangImporter/ClangImporterTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@ SWIFT_REQUEST(ClangImporter, CxxRecordSemantics,
3030
SWIFT_REQUEST(ClangImporter, IsSafeUseOfCxxDecl,
3131
bool(SafeUseOfCxxRecordDescriptor), Cached,
3232
NoLocationInfo)
33+
SWIFT_REQUEST(ClangImporter, CustomRefCountingOperation,
34+
CustomRefCountingOperationResult(CustomRefCountingOperationDescriptor), Cached,
35+
NoLocationInfo)

lib/AST/Decl.cpp

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "swift/AST/Decl.h"
18-
#include "swift/AST/AccessRequests.h"
19-
#include "swift/AST/AccessScope.h"
2018
#include "swift/AST/ASTContext.h"
21-
#include "swift/AST/ASTWalker.h"
2219
#include "swift/AST/ASTMangler.h"
20+
#include "swift/AST/ASTWalker.h"
21+
#include "swift/AST/AccessRequests.h"
22+
#include "swift/AST/AccessScope.h"
2323
#include "swift/AST/Attr.h"
2424
#include "swift/AST/CaptureInfo.h"
2525
#include "swift/AST/DiagnosticEngine.h"
@@ -32,7 +32,6 @@
3232
#include "swift/AST/GenericSignature.h"
3333
#include "swift/AST/Initializer.h"
3434
#include "swift/AST/LazyResolver.h"
35-
#include "swift/AST/ASTMangler.h"
3635
#include "swift/AST/Module.h"
3736
#include "swift/AST/NameLookup.h"
3837
#include "swift/AST/NameLookupRequests.h"
@@ -44,11 +43,17 @@
4443
#include "swift/AST/ResilienceExpansion.h"
4544
#include "swift/AST/SourceFile.h"
4645
#include "swift/AST/Stmt.h"
46+
#include "swift/AST/SwiftNameTranslation.h"
4747
#include "swift/AST/TypeCheckRequests.h"
4848
#include "swift/AST/TypeLoc.h"
49-
#include "swift/AST/SwiftNameTranslation.h"
5049
#include "swift/Basic/Defer.h"
50+
#include "swift/Basic/Range.h"
51+
#include "swift/Basic/Statistic.h"
52+
#include "swift/Basic/StringExtras.h"
53+
#include "swift/Basic/TypeID.h"
54+
#include "swift/ClangImporter/ClangImporterRequests.h"
5155
#include "swift/ClangImporter/ClangModule.h"
56+
#include "swift/Demangling/ManglingMacros.h"
5257
#include "swift/Parse/Lexer.h" // FIXME: Bad dependency
5358
#include "clang/Lex/MacroInfo.h"
5459
#include "llvm/ADT/SmallPtrSet.h"
@@ -57,11 +62,6 @@
5762
#include "llvm/ADT/Statistic.h"
5863
#include "llvm/Support/Compiler.h"
5964
#include "llvm/Support/raw_ostream.h"
60-
#include "swift/Basic/Range.h"
61-
#include "swift/Basic/StringExtras.h"
62-
#include "swift/Basic/Statistic.h"
63-
#include "swift/Basic/TypeID.h"
64-
#include "swift/Demangling/ManglingMacros.h"
6565

6666
#include "clang/Basic/CharInfo.h"
6767
#include "clang/Basic/Module.h"
@@ -5233,6 +5233,25 @@ bool ClassDecl::isForeignReferenceType() const {
52335233
return getClangDecl() && isa<clang::RecordDecl>(getClangDecl());
52345234
}
52355235

5236+
bool ClassDecl::hasRefCountingAnnotations() const {
5237+
return evaluateOrDefault(getASTContext().evaluator,
5238+
CustomRefCountingOperation(
5239+
{this, CustomRefCountingOperationKind::release}),
5240+
{})
5241+
.kind != CustomRefCountingOperationResult::immortal;
5242+
}
5243+
5244+
ReferenceCounting ClassDecl::getObjectModel() const {
5245+
if (isForeignReferenceType())
5246+
return hasRefCountingAnnotations() ? ReferenceCounting::Custom
5247+
: ReferenceCounting::None;
5248+
5249+
if (checkAncestry(AncestryFlags::ObjCObjectModel))
5250+
return ReferenceCounting::ObjC;
5251+
5252+
return ReferenceCounting::Native;
5253+
}
5254+
52365255
EnumCaseDecl *EnumCaseDecl::create(SourceLoc CaseLoc,
52375256
ArrayRef<EnumElementDecl *> Elements,
52385257
DeclContext *DC) {

lib/AST/NameLookupRequests.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,23 @@ swift::extractNearestSourceLoc(const ClangRecordMemberLookupDescriptor &desc) {
476476
return extractNearestSourceLoc(desc.recordDecl);
477477
}
478478

479+
//----------------------------------------------------------------------------//
480+
// CustomRefCountingOperation computation.
481+
//----------------------------------------------------------------------------//
482+
483+
void swift::simple_display(llvm::raw_ostream &out,
484+
CustomRefCountingOperationDescriptor desc) {
485+
out << "Finding custom (foreign reference) reference counting operation '"
486+
<< (desc.kind == CustomRefCountingOperationKind::retain ? "retain"
487+
: "release")
488+
<< "for '" << desc.decl->getNameStr() << "'.\n";
489+
}
490+
491+
SourceLoc
492+
swift::extractNearestSourceLoc(CustomRefCountingOperationDescriptor desc) {
493+
return SourceLoc();
494+
}
495+
479496
// Implement the clang importer type zone.
480497
#define SWIFT_TYPEID_ZONE ClangImporter
481498
#define SWIFT_TYPEID_HEADER "swift/ClangImporter/ClangImporterTypeIDZone.def"

lib/AST/Type.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6037,12 +6037,16 @@ ReferenceCounting TypeBase::getReferenceCounting() {
60376037
CanType type = getCanonicalType();
60386038
ASTContext &ctx = type->getASTContext();
60396039

6040+
if (isForeignReferenceType())
6041+
return lookThroughAllOptionalTypes()
6042+
->getClassOrBoundGenericClass()
6043+
->hasRefCountingAnnotations()
6044+
? ReferenceCounting::Custom
6045+
: ReferenceCounting::None;
6046+
60406047
// In the absence of Objective-C interoperability, everything uses native
60416048
// reference counting or is the builtin BridgeObject.
60426049
if (!ctx.LangOpts.EnableObjCInterop) {
6043-
if (isForeignReferenceType())
6044-
return ReferenceCounting::None;
6045-
60466050
return type->getKind() == TypeKind::BuiltinBridgeObject
60476051
? ReferenceCounting::Bridge
60486052
: ReferenceCounting::Native;

lib/ClangImporter/ClangImporter.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6073,4 +6073,49 @@ void swift::simple_display(llvm::raw_ostream &out,
60736073

60746074
SourceLoc swift::extractNearestSourceLoc(SafeUseOfCxxDeclDescriptor desc) {
60756075
return SourceLoc();
6076-
}
6076+
}
6077+
6078+
CustomRefCountingOperationResult CustomRefCountingOperation::evaluate(
6079+
Evaluator &evaluator, CustomRefCountingOperationDescriptor desc) const {
6080+
auto swiftDecl = desc.decl;
6081+
auto operation = desc.kind;
6082+
auto &ctx = swiftDecl->getASTContext();
6083+
6084+
std::string operationStr = operation == CustomRefCountingOperationKind::retain
6085+
? "retain:"
6086+
: "release:";
6087+
6088+
auto decl = cast<clang::RecordDecl>(swiftDecl->getClangDecl());
6089+
if (!decl->hasAttrs())
6090+
return {CustomRefCountingOperationResult::noAttribute, nullptr, ""};
6091+
6092+
auto retainFnAttr =
6093+
llvm::find_if(decl->getAttrs(), [&operationStr](auto *attr) {
6094+
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
6095+
return swiftAttr->getAttribute().startswith(operationStr);
6096+
return false;
6097+
});
6098+
if (retainFnAttr == decl->getAttrs().end()) {
6099+
return {CustomRefCountingOperationResult::noAttribute, nullptr, ""};
6100+
}
6101+
6102+
auto name = cast<clang::SwiftAttrAttr>(*retainFnAttr)
6103+
->getAttribute()
6104+
.drop_front(StringRef(operationStr).size())
6105+
.str();
6106+
6107+
if (name == "immortal")
6108+
return {CustomRefCountingOperationResult::immortal, nullptr, name};
6109+
6110+
llvm::SmallVector<ValueDecl *, 1> results;
6111+
ctx.lookupInModule(swiftDecl->getParentModule(), name, results);
6112+
6113+
if (results.size() == 1)
6114+
return {CustomRefCountingOperationResult::foundOperation, results.front(),
6115+
name};
6116+
6117+
if (results.empty())
6118+
return {CustomRefCountingOperationResult::notFound, nullptr, name};
6119+
6120+
return {CustomRefCountingOperationResult::tooManyFound, nullptr, name};
6121+
}

0 commit comments

Comments
 (0)