Skip to content

Commit ed9dad3

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 17f1cf9 commit ed9dad3

Some content is hidden

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

59 files changed

+1502
-148
lines changed

include/swift/ABI/Metadata.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,11 @@ struct TargetStructMetadata : public TargetValueMetadata<Runtime> {
15181518
}
15191519

15201520
bool isCanonicalStaticallySpecializedGenericMetadata() const {
1521+
// Struct metadata is used for foreign reference types, in which case the
1522+
// descriptor is not a struct descriptor.
1523+
if (!llvm::isa<TargetStructDescriptor<Runtime>>(this->Description))
1524+
return false;
1525+
15211526
auto *description = getDescription();
15221527
if (!description->isGeneric())
15231528
return false;

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>
@@ -3900,7 +3901,8 @@ class ClassDecl final : public NominalTypeDecl {
39003901
///
39013902
/// \see getForeignClassKind
39023903
bool isForeign() const {
3903-
return getForeignClassKind() != ForeignKind::Normal;
3904+
return getForeignClassKind() != ForeignKind::Normal ||
3905+
const_cast<ClassDecl *>(this)->isForeignReferenceType();
39043906
}
39053907

39063908
/// Whether the class is (known to be) a default actor.
@@ -3935,9 +3937,22 @@ class ClassDecl final : public NominalTypeDecl {
39353937
bool isNativeNSObjectSubclass() const;
39363938

39373939
/// Whether the class uses the ObjC object model (reference counting,
3938-
/// allocation, etc.) instead of the Swift model.
3939-
bool usesObjCObjectModel() const {
3940-
return checkAncestry(AncestryFlags::ObjCObjectModel);
3940+
/// allocation, etc.), the Swift model, or has no reference counting at all.
3941+
ReferenceCounting getObjectModel() {
3942+
if (isForeignReferenceType())
3943+
return ReferenceCounting::None;
3944+
3945+
if (checkAncestry(AncestryFlags::ObjCObjectModel))
3946+
return ReferenceCounting::ObjC;
3947+
3948+
return ReferenceCounting::Native;
3949+
}
3950+
3951+
LayoutConstraintKind getLayoutConstraintKind() {
3952+
if (getObjectModel() == ReferenceCounting::ObjC)
3953+
return LayoutConstraintKind::Class;
3954+
3955+
return LayoutConstraintKind::NativeClass;
39413956
}
39423957

39433958
/// Returns true if the class has designated initializers that are not listed
@@ -4059,6 +4074,11 @@ class ClassDecl final : public NominalTypeDecl {
40594074
bool hasKnownSwiftImplementation() const {
40604075
return !hasClangNode();
40614076
}
4077+
4078+
/// Used to determine if this class decl is a foriegn reference type. I.e., a
4079+
/// non-reference-counted swift reference type that was imported from a C++
4080+
/// record.
4081+
bool isForeignReferenceType();
40624082
};
40634083

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

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.
@@ -6175,7 +6178,7 @@ inline bool TypeBase::canDynamicallyBeOptionalType(bool includeExistential) {
61756178
return isArchetypeOrExistential && !T.isAnyClassReferenceType();
61766179
}
61776180

6178-
inline ClassDecl *TypeBase::getClassOrBoundGenericClass() {
6181+
inline ClassDecl *TypeBase::getClassOrBoundGenericClass() const {
61796182
return getCanonicalType().getClassOrBoundGenericClass();
61806183
}
61816184

@@ -6239,8 +6242,6 @@ inline GenericTypeDecl *TypeBase::getAnyGeneric() {
62396242
return getCanonicalType().getAnyGeneric();
62406243
}
62416244

6242-
6243-
62446245
inline bool TypeBase::isBuiltinIntegerType(unsigned n) {
62456246
if (auto intTy = dyn_cast<BuiltinIntegerType>(getCanonicalType()))
62466247
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
@@ -1940,7 +1940,11 @@ static bool isPolymorphic(const AbstractStorageDecl *storage) {
19401940
return true;
19411941

19421942
if (auto *classDecl = dyn_cast<ClassDecl>(storage->getDeclContext())) {
1943-
if (storage->isFinal() || classDecl->isFinal())
1943+
// Accesses to members of foreign reference types should be made directly
1944+
// to storage as these are references to clang records which are not allowed
1945+
// to have dynamic dispatch.
1946+
if (storage->isFinal() || classDecl->isFinal() ||
1947+
classDecl->isForeignReferenceType())
19441948
return false;
19451949

19461950
return true;
@@ -4720,6 +4724,10 @@ bool ClassDecl::walkSuperclasses(
47204724
return false;
47214725
}
47224726

4727+
bool ClassDecl::isForeignReferenceType() {
4728+
return getClangDecl() && isa<clang::RecordDecl>(getClangDecl());
4729+
}
4730+
47234731
EnumCaseDecl *EnumCaseDecl::create(SourceLoc CaseLoc,
47244732
ArrayRef<EnumElementDecl *> Elements,
47254733
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
@@ -523,9 +523,7 @@ void RuleBuilder::addRequirement(const Requirement &req,
523523
// Build the symbol [layout: L].
524524
auto layout =
525525
LayoutConstraint::getLayoutConstraint(
526-
otherType->getClassOrBoundGenericClass()->usesObjCObjectModel()
527-
? LayoutConstraintKind::Class
528-
: LayoutConstraintKind::NativeClass,
526+
otherType->getClassOrBoundGenericClass()->getLayoutConstraintKind(),
529527
Context.getASTContext());
530528
auto layoutSymbol = Symbol::forLayout(layout, Context);
531529

lib/AST/Type.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ Type TypeBase::lookThroughAllOptionalTypes(SmallVectorImpl<Type> &optionals){
758758
bool TypeBase::isAnyObject() {
759759
auto canTy = getCanonicalType();
760760

761-
if (!canTy.isExistentialType())
761+
if (!canTy.isExistentialType() || canTy.isForeignReferenceType())
762762
return false;
763763

764764
return canTy.getExistentialLayout().isAnyObject();
@@ -5274,12 +5274,6 @@ bool UnownedStorageType::isLoadable(ResilienceExpansion resilience) const {
52745274
return ty->getReferenceCounting() == ReferenceCounting::Native;
52755275
}
52765276

5277-
static ReferenceCounting getClassReferenceCounting(ClassDecl *theClass) {
5278-
return (theClass->usesObjCObjectModel()
5279-
? ReferenceCounting::ObjC
5280-
: ReferenceCounting::Native);
5281-
}
5282-
52835277
ReferenceCounting TypeBase::getReferenceCounting() {
52845278
CanType type = getCanonicalType();
52855279
ASTContext &ctx = type->getASTContext();
@@ -5306,13 +5300,12 @@ ReferenceCounting TypeBase::getReferenceCounting() {
53065300
return ReferenceCounting::Bridge;
53075301

53085302
case TypeKind::Class:
5309-
return getClassReferenceCounting(cast<ClassType>(type)->getDecl());
5303+
return cast<ClassType>(type)->getDecl()->getObjectModel();
53105304
case TypeKind::BoundGenericClass:
5311-
return getClassReferenceCounting(
5312-
cast<BoundGenericClassType>(type)->getDecl());
5305+
return cast<BoundGenericClassType>(type)->getDecl()->getObjectModel();
53135306
case TypeKind::UnboundGeneric:
5314-
return getClassReferenceCounting(
5315-
cast<ClassDecl>(cast<UnboundGenericType>(type)->getDecl()));
5307+
return cast<ClassDecl>(cast<UnboundGenericType>(type)->getDecl())
5308+
->getObjectModel();
53165309

53175310
case TypeKind::DynamicSelf:
53185311
return cast<DynamicSelfType>(type).getSelfType()
@@ -5524,6 +5517,18 @@ TypeBase::getAutoDiffTangentSpace(LookupConformanceFn lookupConformance) {
55245517
return cache(None);
55255518
}
55265519

5520+
bool TypeBase::isForeignReferenceType() {
5521+
if (auto *classDecl = lookThroughAllOptionalTypes()->getClassOrBoundGenericClass())
5522+
return classDecl->isForeignReferenceType();
5523+
return false;
5524+
}
5525+
5526+
bool CanType::isForeignReferenceType() {
5527+
if (auto *classDecl = getPointer()->lookThroughAllOptionalTypes()->getClassOrBoundGenericClass())
5528+
return classDecl->isForeignReferenceType();
5529+
return false;
5530+
}
5531+
55275532
// Creates an `AnyFunctionType` from the given parameters, result type,
55285533
// generic signature, and `ExtInfo`.
55295534
static AnyFunctionType *

lib/ClangImporter/ClangImporter.cpp

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

41224122
TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
41234123
Evaluator &evaluator, ClangRecordMemberLookupDescriptor desc) const {
4124-
StructDecl *recordDecl = desc.recordDecl;
4124+
NominalTypeDecl *recordDecl = desc.recordDecl;
41254125
DeclName name = desc.name;
41264126

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

0 commit comments

Comments
 (0)