Skip to content

Commit fc3b3a1

Browse files
committed
[cxx-interop] Implement foreign reference types.
This is an expiremental feature to allow an attribute, `import_as_ref`, to import a C++ record as a non-reference-counted reference type in Swift.
1 parent 3f56ea8 commit fc3b3a1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1645
-146
lines changed

include/swift/AST/Decl.h

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "swift/AST/GenericParamKey.h"
2929
#include "swift/AST/IfConfigClause.h"
3030
#include "swift/AST/LayoutConstraint.h"
31+
#include "swift/AST/ReferenceCounting.h"
3132
#include "swift/AST/StorageImpl.h"
3233
#include "swift/AST/TypeAlignments.h"
3334
#include "swift/AST/TypeWalker.h"
@@ -37,10 +38,10 @@
3738
#include "swift/Basic/Compiler.h"
3839
#include "swift/Basic/Debug.h"
3940
#include "swift/Basic/InlineBitfield.h"
41+
#include "swift/Basic/Located.h"
4042
#include "swift/Basic/NullablePtr.h"
4143
#include "swift/Basic/OptionalEnum.h"
4244
#include "swift/Basic/Range.h"
43-
#include "swift/Basic/Located.h"
4445
#include "llvm/ADT/DenseSet.h"
4546
#include "llvm/Support/TrailingObjects.h"
4647
#include <type_traits>
@@ -3906,7 +3907,8 @@ class ClassDecl final : public NominalTypeDecl {
39063907
///
39073908
/// \see getForeignClassKind
39083909
bool isForeign() const {
3909-
return getForeignClassKind() != ForeignKind::Normal;
3910+
return getForeignClassKind() != ForeignKind::Normal ||
3911+
const_cast<ClassDecl *>(this)->isForeignReferenceType();
39103912
}
39113913

39123914
/// Whether the class is (known to be) a default actor.
@@ -3941,9 +3943,22 @@ class ClassDecl final : public NominalTypeDecl {
39413943
bool isNativeNSObjectSubclass() const;
39423944

39433945
/// Whether the class uses the ObjC object model (reference counting,
3944-
/// allocation, etc.) instead of the Swift model.
3945-
bool usesObjCObjectModel() const {
3946-
return checkAncestry(AncestryFlags::ObjCObjectModel);
3946+
/// allocation, etc.), the Swift model, or has no reference counting at all.
3947+
ReferenceCounting getObjectModel() {
3948+
if (isForeignReferenceType())
3949+
return ReferenceCounting::None;
3950+
3951+
if (checkAncestry(AncestryFlags::ObjCObjectModel))
3952+
return ReferenceCounting::ObjC;
3953+
3954+
return ReferenceCounting::Native;
3955+
}
3956+
3957+
LayoutConstraintKind getLayoutConstraintKind() {
3958+
if (getObjectModel() == ReferenceCounting::ObjC)
3959+
return LayoutConstraintKind::Class;
3960+
3961+
return LayoutConstraintKind::NativeClass;
39473962
}
39483963

39493964
/// Returns true if the class has designated initializers that are not listed
@@ -4065,6 +4080,11 @@ class ClassDecl final : public NominalTypeDecl {
40654080
bool hasKnownSwiftImplementation() const {
40664081
return !hasClangNode();
40674082
}
4083+
4084+
/// Used to determine if this class decl is a foriegn reference type. I.e., a
4085+
/// non-reference-counted swift reference type that was imported from a C++
4086+
/// record.
4087+
bool isForeignReferenceType();
40684088
};
40694089

40704090
/// A convenience wrapper around the \c SelfReferencePosition::Kind enum.

include/swift/AST/DiagnosticsIRGen.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,10 @@ 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+
6267
#define UNDEFINE_DIAGNOSTIC_MACROS
6368
#include "DefineDiagnosticMacros.h"

include/swift/AST/ReferenceCounting.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ enum class ReferenceCounting : uint8_t {
2929
/// Blocks are always ObjC reference counting compatible.
3030
ObjC,
3131

32+
/// The object has no reference counting. This is used by foreign reference
33+
/// types.
34+
None,
35+
3236
/// The object uses _Block_copy/_Block_release reference counting.
3337
///
3438
/// This is a strict subset of ObjC; all blocks are also ObjC reference

include/swift/AST/Type.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@ class CanType : public Type {
488488
NominalTypeDecl *getAnyNominal() const;
489489
GenericTypeDecl *getAnyGeneric() const;
490490

491+
bool isForeignReferenceType(); // in Types.h
492+
491493
CanType getOptionalObjectType() const {
492494
return getOptionalObjectTypeImpl(*this);
493495
}

include/swift/AST/Types.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -811,16 +811,19 @@ class alignas(1 << TypeAlignInBits) TypeBase
811811

812812
/// If this is a class type or a bound generic class type, returns the
813813
/// (possibly generic) class.
814-
ClassDecl *getClassOrBoundGenericClass();
815-
814+
ClassDecl *getClassOrBoundGenericClass() const;
815+
816816
/// If this is a struct type or a bound generic struct type, returns
817817
/// the (possibly generic) class.
818818
StructDecl *getStructOrBoundGenericStruct();
819819

820820
/// If this is an enum or a bound generic enum type, returns the
821821
/// (possibly generic) enum.
822822
EnumDecl *getEnumOrBoundGenericEnum();
823-
823+
824+
/// If this is a class, check if this class is a foreign reference type.
825+
bool isForeignReferenceType();
826+
824827
/// Determine whether this type may have a superclass, which holds for
825828
/// classes, bound generic classes, and archetypes that are only instantiable
826829
/// with a class type.
@@ -6198,7 +6201,7 @@ inline bool TypeBase::canDynamicallyBeOptionalType(bool includeExistential) {
61986201
return isArchetypeOrExistential && !T.isAnyClassReferenceType();
61996202
}
62006203

6201-
inline ClassDecl *TypeBase::getClassOrBoundGenericClass() {
6204+
inline ClassDecl *TypeBase::getClassOrBoundGenericClass() const {
62026205
return getCanonicalType().getClassOrBoundGenericClass();
62036206
}
62046207

@@ -6262,8 +6265,6 @@ inline GenericTypeDecl *TypeBase::getAnyGeneric() {
62626265
return getCanonicalType().getAnyGeneric();
62636266
}
62646267

6265-
6266-
62676268
inline bool TypeBase::isBuiltinIntegerType(unsigned n) {
62686269
if (auto intTy = dyn_cast<BuiltinIntegerType>(getCanonicalType()))
62696270
return intTy->getWidth().isFixedWidth()

include/swift/ClangImporter/ClangImporterRequests.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ class CXXNamespaceMemberLookup
132132

133133
/// The input type for a record member lookup request.
134134
struct ClangRecordMemberLookupDescriptor final {
135-
StructDecl *recordDecl;
135+
NominalTypeDecl *recordDecl;
136136
DeclName name;
137137

138-
ClangRecordMemberLookupDescriptor(StructDecl *recordDecl, DeclName name)
138+
ClangRecordMemberLookupDescriptor(NominalTypeDecl *recordDecl, DeclName name)
139139
: recordDecl(recordDecl), name(name) {
140140
assert(isa<clang::RecordDecl>(recordDecl->getClangDecl()));
141141
}

include/swift/SIL/SILType.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,13 @@ class SILType {
236236
NominalTypeDecl *getNominalOrBoundGenericNominal() const {
237237
return getASTType().getNominalOrBoundGenericNominal();
238238
}
239-
239+
240+
/// If this type maps to a Swift class, check if that class is a foreign
241+
/// reference type.
242+
bool isForeignReferenceType() const {
243+
return getASTType().isForeignReferenceType();
244+
}
245+
240246
/// True if the type is an address type.
241247
bool isAddress() const { return getCategory() == SILValueCategory::Address; }
242248

lib/AST/ClangTypeConverter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,8 @@ ClangTypeConverter::visitBoundGenericType(BoundGenericType *type) {
545545
auto args = type->getGenericArgs();
546546
assert((args.size() == 1) && "Optional should have 1 generic argument.");
547547
clang::QualType innerTy = convert(args[0]);
548-
if (swift::canImportAsOptional(innerTy.getTypePtrOrNull()))
548+
if (swift::canImportAsOptional(innerTy.getTypePtrOrNull()) ||
549+
args[0]->isForeignReferenceType())
549550
return innerTy;
550551
return clang::QualType();
551552
}

lib/AST/Decl.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1957,7 +1957,11 @@ static bool isPolymorphic(const AbstractStorageDecl *storage) {
19571957
return true;
19581958

19591959
if (auto *classDecl = dyn_cast<ClassDecl>(storage->getDeclContext())) {
1960-
if (storage->isFinal() || classDecl->isFinal())
1960+
// Accesses to members of foreign reference types should be made directly
1961+
// to storage as these are references to clang records which are not allowed
1962+
// to have dynamic dispatch.
1963+
if (storage->isFinal() || classDecl->isFinal() ||
1964+
classDecl->isForeignReferenceType())
19611965
return false;
19621966

19631967
return true;
@@ -4737,6 +4741,10 @@ bool ClassDecl::walkSuperclasses(
47374741
return false;
47384742
}
47394743

4744+
bool ClassDecl::isForeignReferenceType() {
4745+
return getClangDecl() && isa<clang::RecordDecl>(getClangDecl());
4746+
}
4747+
47404748
EnumCaseDecl *EnumCaseDecl::create(SourceLoc CaseLoc,
47414749
ArrayRef<EnumElementDecl *> Elements,
47424750
DeclContext *DC) {

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4443,11 +4443,8 @@ bool GenericSignatureBuilder::updateSuperclass(
44434443
auto layoutReqSource =
44444444
source.getSource(*this, type)->viaLayout(*this, superclass);
44454445

4446-
auto layout =
4447-
LayoutConstraint::getLayoutConstraint(
4448-
superclass->getClassOrBoundGenericClass()->usesObjCObjectModel()
4449-
? LayoutConstraintKind::Class
4450-
: LayoutConstraintKind::NativeClass,
4446+
auto layout = LayoutConstraint::getLayoutConstraint(
4447+
superclass->getClassOrBoundGenericClass()->getLayoutConstraintKind(),
44514448
getASTContext());
44524449
addLayoutRequirementDirect(type, layout, layoutReqSource);
44534450
return true;

lib/AST/NameLookup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1478,7 +1478,7 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
14781478
} else if (isa_and_nonnull<clang::RecordDecl>(decl->getClangDecl())) {
14791479
auto allFound = evaluateOrDefault(
14801480
ctx.evaluator,
1481-
ClangRecordMemberLookup({cast<StructDecl>(decl), name}), {});
1481+
ClangRecordMemberLookup({cast<NominalTypeDecl>(decl), name}), {});
14821482
// Add all the members we found, later we'll combine these with the
14831483
// existing members.
14841484
for (auto found : allFound)

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -924,9 +924,7 @@ void RuleBuilder::addRequirement(const Requirement &req,
924924
// Build the symbol [layout: L].
925925
auto layout =
926926
LayoutConstraint::getLayoutConstraint(
927-
otherType->getClassOrBoundGenericClass()->usesObjCObjectModel()
928-
? LayoutConstraintKind::Class
929-
: LayoutConstraintKind::NativeClass,
927+
otherType->getClassOrBoundGenericClass()->getLayoutConstraintKind(),
930928
Context.getASTContext());
931929
auto layoutSymbol = Symbol::forLayout(layout, Context);
932930

lib/AST/Type.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ Type TypeBase::stripConcurrency(bool recurse, bool dropGlobalActor) {
846846
bool TypeBase::isAnyObject() {
847847
auto canTy = getCanonicalType();
848848

849-
if (!canTy.isExistentialType())
849+
if (!canTy.isExistentialType() || canTy.isForeignReferenceType())
850850
return false;
851851

852852
return canTy.getExistentialLayout().isAnyObject();
@@ -5362,19 +5362,16 @@ bool UnownedStorageType::isLoadable(ResilienceExpansion resilience) const {
53625362
return ty->getReferenceCounting() == ReferenceCounting::Native;
53635363
}
53645364

5365-
static ReferenceCounting getClassReferenceCounting(ClassDecl *theClass) {
5366-
return (theClass->usesObjCObjectModel()
5367-
? ReferenceCounting::ObjC
5368-
: ReferenceCounting::Native);
5369-
}
5370-
53715365
ReferenceCounting TypeBase::getReferenceCounting() {
53725366
CanType type = getCanonicalType();
53735367
ASTContext &ctx = type->getASTContext();
53745368

53755369
// In the absence of Objective-C interoperability, everything uses native
53765370
// reference counting or is the builtin BridgeObject.
53775371
if (!ctx.LangOpts.EnableObjCInterop) {
5372+
if (isForeignReferenceType())
5373+
return ReferenceCounting::None;
5374+
53785375
return type->getKind() == TypeKind::BuiltinBridgeObject
53795376
? ReferenceCounting::Bridge
53805377
: ReferenceCounting::Native;
@@ -5394,13 +5391,12 @@ ReferenceCounting TypeBase::getReferenceCounting() {
53945391
return ReferenceCounting::Bridge;
53955392

53965393
case TypeKind::Class:
5397-
return getClassReferenceCounting(cast<ClassType>(type)->getDecl());
5394+
return cast<ClassType>(type)->getDecl()->getObjectModel();
53985395
case TypeKind::BoundGenericClass:
5399-
return getClassReferenceCounting(
5400-
cast<BoundGenericClassType>(type)->getDecl());
5396+
return cast<BoundGenericClassType>(type)->getDecl()->getObjectModel();
54015397
case TypeKind::UnboundGeneric:
5402-
return getClassReferenceCounting(
5403-
cast<ClassDecl>(cast<UnboundGenericType>(type)->getDecl()));
5398+
return cast<ClassDecl>(cast<UnboundGenericType>(type)->getDecl())
5399+
->getObjectModel();
54045400

54055401
case TypeKind::DynamicSelf:
54065402
return cast<DynamicSelfType>(type).getSelfType()
@@ -5612,6 +5608,18 @@ TypeBase::getAutoDiffTangentSpace(LookupConformanceFn lookupConformance) {
56125608
return cache(None);
56135609
}
56145610

5611+
bool TypeBase::isForeignReferenceType() {
5612+
if (auto *classDecl = lookThroughAllOptionalTypes()->getClassOrBoundGenericClass())
5613+
return classDecl->isForeignReferenceType();
5614+
return false;
5615+
}
5616+
5617+
bool CanType::isForeignReferenceType() {
5618+
if (auto *classDecl = getPointer()->lookThroughAllOptionalTypes()->getClassOrBoundGenericClass())
5619+
return classDecl->isForeignReferenceType();
5620+
return false;
5621+
}
5622+
56155623
// Creates an `AnyFunctionType` from the given parameters, result type,
56165624
// generic signature, and `ExtInfo`.
56175625
static AnyFunctionType *

lib/ClangImporter/ClangImporter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4141,7 +4141,7 @@ TinyPtrVector<ValueDecl *> CXXNamespaceMemberLookup::evaluate(
41414141

41424142
TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
41434143
Evaluator &evaluator, ClangRecordMemberLookupDescriptor desc) const {
4144-
StructDecl *recordDecl = desc.recordDecl;
4144+
NominalTypeDecl *recordDecl = desc.recordDecl;
41454145
DeclName name = desc.name;
41464146

41474147
auto &ctx = recordDecl->getASTContext();

0 commit comments

Comments
 (0)