You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This patch removes the `SWIFT_RETURNED_AS_RETAINED_BY_DEFAULT`
annotation while maintaining the support for
`SWIFT_RETURNED_AS_UNRETAINED_BY_DEFAULT`. These type-level annotations
were initially introduced in
[PR-81093](#81093) to reduce the
annotation burden in large C++ codebases where many C++ APIs returning
`SWIFT_SHARED_REFERENCE` types are exposed to Swift.
### Motivation
The original goal was to make C++ interop more ergonomic by allowing
type-level defaults for ownership conventions
for`SWIFT_SHARED_REFERENCE` types . However, defaulting to retained
return values (+1) seems to be problematic and poses memory safety
risks.
### Why we’re removing `SWIFT_RETURNED_AS_RETAINED_BY_DEFAULT`
- **Memory safety risks:** Defaulting to retained can potentially lead
to use-after-free bugs when the API implementation actually returns
`unowned` (`+0`). These errors are subtle and can be hard to debug or
discover, particularly in the absence of explicit API-level
`SWIFT_RETURNS_(UN)RETAINED` annotations.
- **Risky transitive behavior:** If a `SWIFT_SHARED_REFERENCE` type is
annotated with `SWIFT_RETURNED_AS_RETAINED_BY_DEFAULT`, any new C++ API
returning this type will inherit the retained behavior by default—even
if the API's actual return behavior is unretained. Unless explicitly
overridden with `SWIFT_RETURNS_UNRETAINED`, this can introduce a silent
mismatch in ownership expectations and lead to use-after-free bugs. This
is especially risky in large or evolving codebases where such defaults
may be overlooked.
- **Simpler multiple inheritance semantics:** With only one type-level
default (`SWIFT_RETURNED_AS_UNRETAINED_BY_DEFAULT`), we avoid
complications that can arise when multiple base classes specify
conflicting ownership defaults. This simplifies reasoning about behavior
in class hierarchies and avoids ambiguity when Swift determines the
ownership convention for inherited APIs.
### Why we’re keeping `SWIFT_RETURNED_AS_UNRETAINED_BY_DEFAULT`
- It still enables projects to suppress warnings for unannotated C++
APIs returning `SWIFT_SHARED_REFERENCE` types, helping to reduce noise
while maintaining clarity.
- It encourages explicitness for retained behavior. Developers must
annotate retained return values with `SWIFT_RETURNS_RETAINED`, making
ownership intent clearer and safer.
- The worst-case outcome of assuming unretained when the return is
actually retained is a memory leak, which is more tolerable and easier
to debug than a use-after-free.
- Having a single default mechanism improves clarity for documentation,
diagnostics, and long-term maintenance of Swift/C++ interop code.
BaseTypeNonDefault *returnBaseTypeNonDefault() { // expected-warning {{'returnBaseTypeNonDefault' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
423
+
BaseTypeNonDefault *createBaseTypeNonDefault() { // expected-warning {{'createBaseTypeNonDefault' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
457
424
returnnewBaseTypeNonDefault();
458
425
}
459
-
DerivedTypeNonDefault *returnDerivedTypeNonDefault() { // expected-warning {{'returnDerivedTypeNonDefault' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
426
+
DerivedTypeNonDefault *createDerivedTypeNonDefault() { // expected-warning {{'createDerivedTypeNonDefault' should be annotated with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE}}
0 commit comments