Files
swift-mirror/test/Interop/Cxx/foreign-reference/upcast-module-interface.swift
John Hui ab44b20a4a [cxx-interop] Prevent upcasting through explicit FRT annotation
Previously, when a derived class re-stated a SWIFT_SHARED_REFERENCE
annotation (or any other reference type annotation), ClangImporter would
allow upcasting to its base if the retain/release op *strings* matched
the base's. This is unsound: two unrelated classes that happen to name
their retain/release ops the same way would be considered upcast-able,
and a string match between overriding methods doesn't actually
guarantee that calling the base's retain/release op on a derived
pointer is correct.

This change removes the string-matching upcast logic. An explicit
annotation on a class now acts as an upcast barrier: the class is
imported as a foreign reference type with no Swift superclass,
regardless of whether its base is also an FRT.

To participate in the FRT inheritance chain, intermediate classes should
inherit the annotation from their base instead of re-stating it.

rdar://179748445
2026-06-16 17:49:20 -07:00

67 lines
2.1 KiB
Swift

// RUN: %target-swift-ide-test -print-module -module-to-print=Upcast -I %S/Inputs -I %swift_src_root/lib/ClangImporter/SwiftBridging -source-filename=x -cxx-interoperability-mode=upcoming-swift -enable-experimental-feature ForeignReferenceTypeInheritance -print-implicit-attrs | %FileCheck %s
// REQUIRES: swift_feature_ForeignReferenceTypeInheritance
// CHECK: class Base {
// CHECK: var baseValue: Int32
// CHECK: func getBaseValue() -> Int32
// CHECK: func setBaseValue(_ v: Int32)
// CHECK: class func create() -> Base
// CHECK: }
// CHECK: class Derived : Base {
// CHECK: var derivedValue: Int32
// CHECK: func getDerivedValue() -> Int32
// CHECK: override class func create() -> Derived
// CHECK: }
// CHECK: class LeafDerived : Derived {
// CHECK: var leafValue: Int32
// CHECK: func getLeafValue() -> Int32
// CHECK: override class func create() -> LeafDerived
// CHECK: }
// CHECK: class Unrelated {
// CHECK: var unrelatedValue: Int32
// CHECK: class func create() -> Unrelated
// CHECK: }
// Virtual base: no Swift superclass relationship.
// CHECK: class VirtualDerived {
// CHECK: class RefCountedBase {
// CHECK: var baseField: Int32
// CHECK: func getBaseValue() -> Int32
// CHECK: class func create() -> RefCountedBase
// CHECK: }
// CHECK: class RefCountedDerived : RefCountedBase {
// CHECK: var derivedField: Int32
// CHECK: func getDerivedField() -> Int32
// CHECK: override class func create() -> RefCountedDerived
// CHECK: }
// CHECK: class OverridesLifetimeOps {
// CHECK: class OverridesLifetimeOpsDerived {
// CHECK: class ReannotatedRefCountedDerived {
// CHECK: class DerivedFromEmptyAndBase : Base {
// CHECK: var extraValue: Int32
// CHECK: func getExtraValue() -> Int32
// CHECK: override class func create() -> DerivedFromEmptyAndBase
// CHECK: }
// CHECK: class CRTPBase<CRTPDerived> {
// CHECK: var crtpBaseValue: Int32
// CHECK: func derivedSelf() -> CRTPDerived!
// CHECK: }
// CHECK: class CRTPDerived : CRTPBase<CRTPDerived> {
// CHECK: var crtpDerivedValue: Int32
// CHECK: class func create() -> CRTPDerived
// CHECK: }
// CHECK: typealias CRTPBaseOfDerived = CRTPBase<CRTPDerived>