Skip to content

Commit b1e5a64

Browse files
committed
[cxx-interop] Prohibit weak references to foreign reference types
This fixes a runtime crash when a `weak` reference to a C++ foreign reference type is used. Instead of a runtime crash, Swift would now emit a compiler error saying that `weak` keyword is incompatible with foreign reference types. rdar://124040825 / resolves #83080
1 parent d8edd86 commit b1e5a64

File tree

5 files changed

+49
-6
lines changed

5 files changed

+49
-6
lines changed

include/swift/AST/Decl.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
707707
KnownProtocol : 8 // '8' for speed. This only needs 6.
708708
);
709709

710-
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+1+2+1+1+1+1+1+1,
710+
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+1+2+1+1+1+1+1+1+1,
711711
/// Whether this class inherits its superclass's convenience initializers.
712712
InheritsSuperclassInits : 1,
713713
ComputedInheritsSuperclassInits : 1,
@@ -721,9 +721,9 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
721721
HasMissingVTableEntries : 1,
722722
ComputedHasMissingVTableEntries : 1,
723723

724-
/// Whether instances of this class are incompatible
725-
/// with weak and unowned references.
724+
/// Whether instances of this class are incompatible with weak references.
726725
IsIncompatibleWithWeakReferences : 1,
726+
IsIncompatibleWithUnownedReferences : 1,
727727

728728
/// Set when the class represents an actor
729729
IsActor : 1
@@ -5272,8 +5272,7 @@ class ClassDecl final : public NominalTypeDecl {
52725272
Bits.ClassDecl.HasMissingVTableEntries = newValue;
52735273
}
52745274

5275-
/// Returns true if this class cannot be used with weak or unowned
5276-
/// references.
5275+
/// Returns true if this class cannot be used with weak references.
52775276
///
52785277
/// Note that this is true if this class or any of its ancestor classes
52795278
/// are marked incompatible.
@@ -5283,6 +5282,16 @@ class ClassDecl final : public NominalTypeDecl {
52835282
Bits.ClassDecl.IsIncompatibleWithWeakReferences = newValue;
52845283
}
52855284

5285+
/// Returns true if this class cannot be used with unowned references.
5286+
///
5287+
/// Note that this is true if this class or any of its ancestor classes
5288+
/// are marked incompatible.
5289+
bool isIncompatibleWithUnownedReferences() const;
5290+
5291+
void setIsIncompatibleWithUnownedReferences(bool newValue = true) {
5292+
Bits.ClassDecl.IsIncompatibleWithUnownedReferences = newValue;
5293+
}
5294+
52865295
/// Find a method of a class that overrides a given method.
52875296
/// Return nullptr, if no such method exists.
52885297
AbstractFunctionDecl *findOverridingDecl(

lib/AST/Decl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6594,6 +6594,7 @@ ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
65946594
Bits.ClassDecl.HasMissingVTableEntries = 0;
65956595
Bits.ClassDecl.ComputedHasMissingVTableEntries = 0;
65966596
Bits.ClassDecl.IsIncompatibleWithWeakReferences = 0;
6597+
Bits.ClassDecl.IsIncompatibleWithUnownedReferences = 0;
65976598
Bits.ClassDecl.IsActor = isActor;
65986599
}
65996600

@@ -6719,6 +6720,16 @@ bool ClassDecl::isIncompatibleWithWeakReferences() const {
67196720
return false;
67206721
}
67216722

6723+
bool ClassDecl::isIncompatibleWithUnownedReferences() const {
6724+
if (Bits.ClassDecl.IsIncompatibleWithUnownedReferences) {
6725+
return true;
6726+
}
6727+
if (auto superclass = getSuperclassDecl()) {
6728+
return superclass->isIncompatibleWithUnownedReferences();
6729+
}
6730+
return false;
6731+
}
6732+
67226733
bool ClassDecl::inheritsSuperclassInitializers() const {
67236734
// If there's no superclass, there's nothing to inherit.
67246735
if (!getSuperclassDecl())

lib/ClangImporter/ImportDecl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2594,6 +2594,14 @@ namespace {
25942594
}
25952595
}
25962596

2597+
if (auto classResult = dyn_cast<ClassDecl>(result)) {
2598+
// Foreign reference types cannot be held as weak references, since the
2599+
// Swift runtime has no way to make the pointer null when the object is
2600+
// deallocated.
2601+
// Unowned references to foreign reference types are supported.
2602+
classResult->setIsIncompatibleWithWeakReferences();
2603+
}
2604+
25972605
if (cxxRecordDecl) {
25982606
if (auto structResult = dyn_cast<StructDecl>(result)) {
25992607
// Address-only type is a type that can't be passed in registers.

lib/Sema/TypeCheckAttr.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5451,7 +5451,11 @@ Type TypeChecker::checkReferenceOwnershipAttr(VarDecl *var, Type type,
54515451
}
54525452

54535453
ClassDecl *underlyingClass = underlyingType->getClassOrBoundGenericClass();
5454-
if (underlyingClass && underlyingClass->isIncompatibleWithWeakReferences()) {
5454+
if (underlyingClass &&
5455+
((ownershipKind == ReferenceOwnership::Weak &&
5456+
underlyingClass->isIncompatibleWithWeakReferences()) ||
5457+
(ownershipKind == ReferenceOwnership::Unowned &&
5458+
underlyingClass->isIncompatibleWithUnownedReferences()))) {
54555459
Diags
54565460
.diagnose(attr->getLocation(),
54575461
diag::invalid_ownership_incompatible_class, underlyingType,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %target-typecheck-verify-swift -cxx-interoperability-mode=default -I %S/Inputs -disable-availability-checking
2+
3+
import POD
4+
5+
struct HasWeakReference {
6+
weak var x: Empty? // expected-error {{'Empty' is incompatible with 'weak' references}}
7+
}
8+
9+
struct HasUnownedReference {
10+
unowned var x: Empty!
11+
}

0 commit comments

Comments
 (0)