mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
**Explanation**: In Swift 6.1, we introduced warnings for C++ APIs returning `SWIFT_SHARED_REFERENCE` types that lack the `SWIFT_RETURNS_(UN)RETAINED` annotations. These warnings serve as a reminder to annotate APIs, as the absence of these annotations can lead to arbitrary assumptions about the ownership of returned `SWIFT_SHARED_REFERENCE` values. This could result in both use-after-free (memory safety) bugs and memory leaks. We have received feedback from a few adopters indicating potential false positive cases where these warnings are triggered. Consequently, we have decided to disable these warnings in Swift 6.2 and re-qualify the warnings on larger projects to ensure their effectiveness and eliminate false positives. - **Scope**: Disabling a previously shipped warning. There is no likelihood of any source breakage or semantic alterations. - **Issues**: rdar://150937617 , rdar://150800115 - **Original PRs**: N/A - **Risk**: Low - **Testing**: Lit test and adopted manually on a demo Xcode project - **Reviewers**: N/A Our intention is to re-enable the warnings in later beta releases of Swift 6.2 once we have stronger evidence of their effectiveness on large codebases and proof that there are no false positives.
400 lines
14 KiB
C++
400 lines
14 KiB
C++
#pragma once
|
|
|
|
#include "visibility.h"
|
|
|
|
// A wrapper around C++'s static_cast(), which allows Swift to get around interop's current lack of support for inheritance.
|
|
template <class I, class O> O cxxCast(I i) { return static_cast<O>(i); }
|
|
|
|
namespace Foo {
|
|
template <class I, class O>
|
|
O cxxCast(I i) {
|
|
return static_cast<O>(i);
|
|
}
|
|
} // namespace Foo
|
|
|
|
// A minimal foreign reference type.
|
|
struct
|
|
__attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:immortal")))
|
|
__attribute__((swift_attr("release:immortal")))
|
|
BaseT {
|
|
public:
|
|
bool isBase;
|
|
BaseT() { isBase = true; }
|
|
BaseT(const BaseT &) = delete;
|
|
static BaseT &getBaseT() { static BaseT singleton; return singleton; }
|
|
};
|
|
|
|
// A foreign reference type that is a subclass of BaseT.
|
|
struct
|
|
__attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:immortal")))
|
|
__attribute__((swift_attr("release:immortal")))
|
|
SubT : BaseT {
|
|
public:
|
|
SubT() { isBase = false; }
|
|
SubT(const SubT &) = delete;
|
|
static SubT &getSubT() { static SubT singleton; return singleton; }
|
|
};
|
|
|
|
struct
|
|
__attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:immortal")))
|
|
__attribute__((swift_attr("release:immortal")))
|
|
BaseWithVirtualDestructor {
|
|
int baseField = 123;
|
|
|
|
BaseWithVirtualDestructor() {}
|
|
virtual ~BaseWithVirtualDestructor() {}
|
|
};
|
|
|
|
struct
|
|
__attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:immortal")))
|
|
__attribute__((swift_attr("release:immortal")))
|
|
DerivedWithVirtualDestructor : public BaseWithVirtualDestructor {
|
|
int derivedField = 456;
|
|
|
|
DerivedWithVirtualDestructor() : BaseWithVirtualDestructor() {}
|
|
~DerivedWithVirtualDestructor() override {}
|
|
};
|
|
|
|
struct
|
|
__attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:immortal")))
|
|
__attribute__((swift_attr("release:immortal")))
|
|
DerivedOutOfOrder : public BaseT, public DerivedWithVirtualDestructor {
|
|
// DerivedWithVirtualDestructor is the primary base class despite being the
|
|
// second one the list.
|
|
|
|
int leafField = 789;
|
|
|
|
DerivedOutOfOrder() = default;
|
|
~DerivedOutOfOrder() override {}
|
|
|
|
static DerivedOutOfOrder& getInstance() {
|
|
static DerivedOutOfOrder singleton;
|
|
return singleton;
|
|
}
|
|
};
|
|
|
|
struct
|
|
__attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:immortal")))
|
|
__attribute__((swift_attr("release:immortal")))
|
|
BaseAlign8 {
|
|
long long field8 = 123;
|
|
}; // sizeof=8, dsize=8, align=8
|
|
|
|
struct DerivedHasTailPadding : public BaseAlign8 {
|
|
int field4 = 456;
|
|
}; // sizeof=16, dsize=12, align=8
|
|
|
|
struct DerivedUsesBaseTailPadding : public DerivedHasTailPadding {
|
|
short field2 = 789;
|
|
|
|
static DerivedUsesBaseTailPadding& getInstance() {
|
|
static DerivedUsesBaseTailPadding singleton;
|
|
return singleton;
|
|
}
|
|
}; // sizeof=16, dsize=14, align=8
|
|
|
|
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
|
|
|
|
namespace ImmortalRefereceExample {
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:immortal")))
|
|
__attribute__((swift_attr("release:immortal"))) ImmortalRefType {};
|
|
|
|
ImmortalRefType *returnImmortalRefType() { return new ImmortalRefType(); };
|
|
|
|
struct DerivedFromImmortalRefType : ImmortalRefType {};
|
|
DerivedFromImmortalRefType *returnDerivedFromImmortalRefType() {
|
|
return new DerivedFromImmortalRefType();
|
|
};
|
|
|
|
} // namespace ImmortalRefereceExample
|
|
|
|
namespace ExplicitAnnotationHasPrecedence1 {
|
|
struct ValueType {};
|
|
ValueType *returnValueType() { return new ValueType(); }
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:ret1")))
|
|
__attribute__((swift_attr("release:rel1"))) RefType {};
|
|
RefType *returnRefType() { return new RefType(); }
|
|
|
|
struct DerivedFromValueType : ValueType {};
|
|
DerivedFromValueType *returnDerivedFromValueType() {
|
|
return new DerivedFromValueType();
|
|
}
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:ret2")))
|
|
__attribute__((swift_attr("release:rel2"))) DerivedFromValueTypeAndAnnotated
|
|
: ValueType {};
|
|
DerivedFromValueTypeAndAnnotated *returnDerivedFromValueTypeAndAnnotated() {
|
|
return new DerivedFromValueTypeAndAnnotated();
|
|
}
|
|
|
|
struct DerivedFromRefType final : RefType {};
|
|
DerivedFromRefType *returnDerivedFromRefType() {
|
|
return new DerivedFromRefType();
|
|
}
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:ret3")))
|
|
__attribute__((swift_attr("release:rel3"))) DerivedFromRefTypeAndAnnotated
|
|
: RefType {};
|
|
DerivedFromRefTypeAndAnnotated *returnDerivedFromRefTypeAndAnnotated() {
|
|
return new DerivedFromRefTypeAndAnnotated();
|
|
}
|
|
} // namespace ExplicitAnnotationHasPrecedence1
|
|
|
|
void ret1(ExplicitAnnotationHasPrecedence1::RefType *v) {};
|
|
void rel1(ExplicitAnnotationHasPrecedence1::RefType *v) {};
|
|
|
|
void ret2(
|
|
ExplicitAnnotationHasPrecedence1::DerivedFromValueTypeAndAnnotated *v) {};
|
|
void rel2(
|
|
ExplicitAnnotationHasPrecedence1::DerivedFromValueTypeAndAnnotated *v) {};
|
|
|
|
void ret3(ExplicitAnnotationHasPrecedence1::DerivedFromRefTypeAndAnnotated *v) {
|
|
};
|
|
void rel3(ExplicitAnnotationHasPrecedence1::DerivedFromRefTypeAndAnnotated *v) {
|
|
};
|
|
|
|
namespace ExplicitAnnotationHasPrecedence2 {
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:retain_A")))
|
|
__attribute__((swift_attr("release:release_A"))) RefTypeA {};
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:retain_B")))
|
|
__attribute__((swift_attr("release:release_B"))) RefTypeB {};
|
|
|
|
struct DerivedFromRefTypeAAndB : RefTypeA, RefTypeB {}; // expected-warning {{unable to infer SWIFT_SHARED_REFERENCE for 'DerivedFromRefTypeAAndB', although one of its transitive base types is marked as SWIFT_SHARED_REFERENCE}}
|
|
DerivedFromRefTypeAAndB *returnDerivedFromRefTypeAAndB() {
|
|
return new DerivedFromRefTypeAAndB();
|
|
}
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:retain_C")))
|
|
__attribute__((swift_attr("release:release_C"))) DerivedFromRefTypeAAndBAnnotated
|
|
: RefTypeA,
|
|
RefTypeB {};
|
|
DerivedFromRefTypeAAndBAnnotated *returnDerivedFromRefTypeAAndBAnnotated() {
|
|
return new DerivedFromRefTypeAAndBAnnotated();
|
|
}
|
|
} // namespace ExplicitAnnotationHasPrecedence2
|
|
|
|
void retain_A(ExplicitAnnotationHasPrecedence2::RefTypeA *v) {};
|
|
void release_A(ExplicitAnnotationHasPrecedence2::RefTypeA *v) {};
|
|
void retain_B(ExplicitAnnotationHasPrecedence2::RefTypeB *v) {};
|
|
void release_B(ExplicitAnnotationHasPrecedence2::RefTypeB *v) {};
|
|
void retain_C(
|
|
ExplicitAnnotationHasPrecedence2::DerivedFromRefTypeAAndBAnnotated *v) {};
|
|
void release_C(
|
|
ExplicitAnnotationHasPrecedence2::DerivedFromRefTypeAAndBAnnotated *v) {};
|
|
|
|
namespace BasicInheritanceExample {
|
|
struct ValueType {};
|
|
ValueType *returnValueType() { return new ValueType(); };
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:RCRetain")))
|
|
__attribute__((swift_attr("release:RCRelease"))) RefType {};
|
|
|
|
RefType *returnRefType() { return new RefType(); };
|
|
|
|
struct DerivedFromRefType final : RefType {};
|
|
DerivedFromRefType *returnDerivedFromRefType() {
|
|
return new DerivedFromRefType();
|
|
};
|
|
} // namespace BasicInheritanceExample
|
|
|
|
void RCRetain(BasicInheritanceExample::RefType *v) {}
|
|
void RCRelease(BasicInheritanceExample::RefType *v) {}
|
|
|
|
namespace MultipleInheritanceExample1 {
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:baseRetain1")))
|
|
__attribute__((swift_attr("release:baseRelease1"))) BaseRef1 {};
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:baseRetain2")))
|
|
__attribute__((swift_attr("release:baseRelease2"))) BaseRef2 {};
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:baseRetain1")))
|
|
__attribute__((swift_attr("release:baseRelease1"))) BaseRef3 : BaseRef1 {};
|
|
|
|
struct DerivedFromBaseRef1AndBaseRef2 : BaseRef1, BaseRef2 {}; // expected-warning {{unable to infer SWIFT_SHARED_REFERENCE for 'DerivedFromBaseRef1AndBaseRef2', although one of its transitive base types is marked as SWIFT_SHARED_REFERENCE}}
|
|
DerivedFromBaseRef1AndBaseRef2 *returnDerivedFromBaseRef1AndBaseRef2() {
|
|
return new DerivedFromBaseRef1AndBaseRef2();
|
|
};
|
|
|
|
struct DerivedFromBaseRef3 : BaseRef3 {};
|
|
DerivedFromBaseRef3 *returnDerivedFromBaseRef3() {
|
|
return new DerivedFromBaseRef3();
|
|
};
|
|
} // namespace MultipleInheritanceExample1
|
|
|
|
void baseRetain1(MultipleInheritanceExample1::BaseRef1 *v) {}
|
|
void baseRelease1(MultipleInheritanceExample1::BaseRef1 *v) {}
|
|
|
|
void baseRetain2(MultipleInheritanceExample1::BaseRef2 *v) {}
|
|
void baseRelease2(MultipleInheritanceExample1::BaseRef2 *v) {}
|
|
|
|
namespace MultipleInheritanceExample2 {
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:bRetain1")))
|
|
__attribute__((swift_attr("release:bRelease1"))) B1 {};
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:bRetain2")))
|
|
__attribute__((swift_attr("release:bRelease2"))) B2 {};
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:bRetain3")))
|
|
__attribute__((swift_attr("release:bRelease3"))) B3 {};
|
|
|
|
struct D : B1, B2, B3 {}; // expected-warning {{unable to infer SWIFT_SHARED_REFERENCE for 'D', although one of its transitive base types is marked as SWIFT_SHARED_REFERENCE}}
|
|
D *returnD() { return new D(); };
|
|
} // namespace MultipleInheritanceExample2
|
|
|
|
void bRetain1(MultipleInheritanceExample2::B1 *v) {}
|
|
void bRelease1(MultipleInheritanceExample2::B1 *v) {}
|
|
|
|
void bRetain2(MultipleInheritanceExample2::B2 *v) {}
|
|
void bRelease2(MultipleInheritanceExample2::B2 *v) {}
|
|
|
|
void bRetain3(MultipleInheritanceExample2::B3 *v) {}
|
|
void bRelease3(MultipleInheritanceExample2::B3 *v) {}
|
|
|
|
// To check for x, y, x kind of pattern in parent's retain/release function name
|
|
// when infering SWIFT_SHARED_REFERENCE
|
|
namespace MultipleInheritanceExample3 {
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:retain1")))
|
|
__attribute__((swift_attr("release:release1"))) B1 {};
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:retain2")))
|
|
__attribute__((swift_attr("release:release2"))) B2 {};
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:retain1")))
|
|
__attribute__((swift_attr("release:release1"))) B3 : B1 {};
|
|
|
|
struct D : B1, B2, B3 {}; // expected-warning {{unable to infer SWIFT_SHARED_REFERENCE for 'D', although one of its transitive base types is marked as SWIFT_SHARED_REFERENCE}}
|
|
D *returnD() { return new D(); };
|
|
} // namespace MultipleInheritanceExample3
|
|
|
|
void retain1(MultipleInheritanceExample3::B1 *v) {}
|
|
void release1(MultipleInheritanceExample3::B1 *v) {}
|
|
|
|
void retain2(MultipleInheritanceExample3::B2 *v) {}
|
|
void release2(MultipleInheritanceExample3::B2 *v) {}
|
|
|
|
namespace OverloadedRetainRelease {
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:sameretain")))
|
|
__attribute__((swift_attr("release:samerelease"))) B1 {}; // expected-error {{multiple functions 'sameretain' found; there must be exactly one retain function for reference type 'B1'}}
|
|
// expected-error@-1 {{multiple functions 'samerelease' found; there must be exactly one release function for reference type 'B1'}}
|
|
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:sameretain")))
|
|
__attribute__((swift_attr("release:samerelease"))) B2 {}; // expected-error {{multiple functions 'sameretain' found; there must be exactly one retain function for reference type 'B2'}}
|
|
// expected-error@-1 {{multiple functions 'samerelease' found; there must be exactly one release function for reference type 'B2'}}
|
|
|
|
struct D : B1, B2 {}; // expected-error {{multiple functions 'sameretain' found; there must be exactly one retain function for reference type 'D'}}
|
|
// expected-error@-1 {{multiple functions 'samerelease' found; there must be exactly one release function for reference type 'D'}}
|
|
D *returnD() { return new D(); };
|
|
} // namespace OverloadedRetainRelease
|
|
|
|
void sameretain(OverloadedRetainRelease::B1 *v) {}
|
|
void samerelease(OverloadedRetainRelease::B1 *v) {}
|
|
|
|
void sameretain(OverloadedRetainRelease::B2 *v) {}
|
|
void samerelease(OverloadedRetainRelease::B2 *v) {}
|
|
|
|
namespace RefTypeDiamondInheritance {
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:retainA")))
|
|
__attribute__((swift_attr("release:releaseA"))) A {};
|
|
|
|
|
|
struct B : A {};
|
|
|
|
struct C : A {};
|
|
|
|
struct Diamond : B, C {}; // expected-warning {{unable to infer SWIFT_SHARED_REFERENCE for 'Diamond', although one of its transitive base types is marked as SWIFT_SHARED_REFERENCE}}
|
|
Diamond *returnDiamond() { return new Diamond(); };
|
|
|
|
struct BVirtual : virtual A {};
|
|
|
|
struct CVirtual : virtual A {};
|
|
|
|
struct VirtualDiamond : BVirtual, CVirtual {};
|
|
VirtualDiamond *returnVirtualDiamond() { return new VirtualDiamond(); };
|
|
} // namespace RefTypeDiamondInheritance
|
|
|
|
void retainA(RefTypeDiamondInheritance::A *a) {};
|
|
void releaseA(RefTypeDiamondInheritance::A *a) {};
|
|
|
|
namespace NonRefTypeDiamondInheritance {
|
|
struct A {};
|
|
|
|
struct __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:retainB")))
|
|
__attribute__((swift_attr("release:releaseB"))) B : A {};
|
|
|
|
struct C : A {};
|
|
|
|
struct Diamond : B, C {};
|
|
Diamond *returnDiamond() { return new Diamond(); };
|
|
|
|
} // namespace NonRefTypeDiamondInheritance
|
|
|
|
void retainB(NonRefTypeDiamondInheritance::B *a) {};
|
|
void releaseB(NonRefTypeDiamondInheritance::B *a) {};
|
|
|
|
namespace InheritingTemplatedRefType {
|
|
|
|
template <class T>
|
|
class __attribute__((swift_attr("import_reference")))
|
|
__attribute__((swift_attr("retain:forestRetain"))) __attribute__((
|
|
swift_attr("release:forestRelease"))) IntrusiveRefCountedTemplate {
|
|
public:
|
|
IntrusiveRefCountedTemplate() : referenceCount(1) {}
|
|
IntrusiveRefCountedTemplate(const IntrusiveRefCountedTemplate &) = delete;
|
|
void retain() { ++referenceCount; }
|
|
|
|
void release() {
|
|
--referenceCount;
|
|
if (referenceCount == 0)
|
|
delete static_cast<T *>(this);
|
|
}
|
|
|
|
private:
|
|
int referenceCount;
|
|
};
|
|
|
|
class Forest : public IntrusiveRefCountedTemplate<Forest> {};
|
|
Forest *returnForest() { return new Forest(); };
|
|
} // namespace InheritingTemplatedRefType
|
|
|
|
void forestRetain(InheritingTemplatedRefType::IntrusiveRefCountedTemplate<
|
|
InheritingTemplatedRefType::Forest> *forest) {
|
|
forest->retain();
|
|
}
|
|
void forestRelease(InheritingTemplatedRefType::IntrusiveRefCountedTemplate<
|
|
InheritingTemplatedRefType::Forest> *forest) {
|
|
forest->release();
|
|
}
|
|
|
|
SWIFT_END_NULLABILITY_ANNOTATIONS
|