Files
fahadnayyar a4eeae2a01 [cxx-interop] Re-enable warnings for unannotated C++ APIs returning SWIFT_SHARED_REFERENCE types under an experimental feature flag (#82488)
This patch re-enables diagnostics for unannotated C++ functions or
methods returning `SWIFT_SHARED_REFERENCE` types. These warnings now
fire only **once per source location**, even in the presence of multiple
template instantiations. This avoids diagnostic duplication that was a
key source of noise in the compilation of larger codebases.

These warnings were previously disabled starting in **Swift 6.2** via
[PR-#81411](https://github.com/swiftlang/swift/pull/81411) due to
concerns around false positives and excessive duplication in projects
adopting C++ interop. This patch addresses the duplication issue by
adding source-location-based caching, which ensures that a warning is
emitted only once per source location, even across template
instantiations with different types.

However, the false positive issue remains to be investigated and will be
addressed in a follow-up patch. Until that happens, the warnings are
gated behind a new experimental feature flag:
`WarnUnannotatedReturnOfCxxFrt`. This feature will be enabled by default
only after thorough qualification and testing on large C++ codebases.

rdar://154261051
2025-07-15 02:56:34 -07:00

400 lines
17 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() { // expected-warning {{'returnDerivedFromImmortalRefType' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
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(); } // expected-warning {{'returnRefType' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
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() { // expected-warning {{'returnDerivedFromValueTypeAndAnnotated' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
return new DerivedFromValueTypeAndAnnotated();
}
struct DerivedFromRefType final : RefType {};
DerivedFromRefType *returnDerivedFromRefType() { // expected-warning {{'returnDerivedFromRefType' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
return new DerivedFromRefType();
}
struct __attribute__((swift_attr("import_reference")))
__attribute__((swift_attr("retain:ret3")))
__attribute__((swift_attr("release:rel3"))) DerivedFromRefTypeAndAnnotated
: RefType {};
DerivedFromRefTypeAndAnnotated *returnDerivedFromRefTypeAndAnnotated() { // expected-warning {{'returnDerivedFromRefTypeAndAnnotated' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
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() { // expected-warning {{'returnDerivedFromRefTypeAAndBAnnotated' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
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(); }; // expected-warning {{'returnRefType' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENC}}
struct DerivedFromRefType final : RefType {};
DerivedFromRefType *returnDerivedFromRefType() { // expected-warning {{'returnDerivedFromRefType' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
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() { // expected-warning {{'returnDerivedFromBaseRef3' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
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(); }; // expected-warning {{'returnD' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
} // 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(); }; // expected-warning {{'returnVirtualDiamond' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
} // 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(); }; // expected-warning {{'returnDiamond' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
} // 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(); }; // expected-warning {{'returnForest' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
} // namespace InheritingTemplatedRefType
void forestRetain(InheritingTemplatedRefType::IntrusiveRefCountedTemplate<
InheritingTemplatedRefType::Forest> *forest) {
forest->retain();
}
void forestRelease(InheritingTemplatedRefType::IntrusiveRefCountedTemplate<
InheritingTemplatedRefType::Forest> *forest) {
forest->release();
}
SWIFT_END_NULLABILITY_ANNOTATIONS