From e0df8cd10001f7264d69d4c8b02a1c576ef0b272 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Fri, 3 Oct 2025 15:01:34 +0100 Subject: [PATCH] [cxx-interop] Avoid spurious references to `_OBJC_CLASS` symbols for C++ foreign reference types This removes erroneous references to `_OBJC_CLASS_$__xyz` symbols that Swift was emitting for certain usages of C/C++ foreign reference types. This was discovered when trying to iterate over a Swift array of foreign reference types using a Swift for-in loop. `Builtin.canBeClass` was returning true for foreign reference types, which led to the optimizer specializing the generic `canBeClass` function to unconditionally return true for foreign reference types. This meant that `_isClassOrObjCExistential` for a foreign reference type evaluated to true, which made the Swift stdlib take the code path that was intended for Objective-C classes in `ArrayBuffer.getElement`, which assumed that the `Element` type conforms to `AnyObject`. Foreign reference types do not actually conform to `AnyObject`. rdar://161814644 --- lib/AST/Type.cpp | 6 ++++++ .../Interop/Cxx/foreign-reference/array-of-classes.swift | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 6f5ba55d4637a..4c709ccfede2b 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -4413,6 +4413,12 @@ bool Type::findIf(llvm::function_ref pred) const { } TypeTraitResult TypeBase::canBeClass() { + // Foreign reference types are represented as Swift classes in the AST, + // however, they use custom retain/release operations, and therefore aren't + // AnyObjects. + if (isForeignReferenceType()) + return TypeTraitResult::IsNot; + // Any bridgeable object type can be a class. if (isBridgeableObjectType()) return TypeTraitResult::Is; diff --git a/test/Interop/Cxx/foreign-reference/array-of-classes.swift b/test/Interop/Cxx/foreign-reference/array-of-classes.swift index e9db746d53c63..17f135971f49c 100644 --- a/test/Interop/Cxx/foreign-reference/array-of-classes.swift +++ b/test/Interop/Cxx/foreign-reference/array-of-classes.swift @@ -58,6 +58,15 @@ func go() { y.append(x) // CHECK: 1 print(y.count) + + var loopCount = 0 + for it in y { +// CHECK: RefType() + print(it) + loopCount += 1 + } +// CHECK: 1 + print(loopCount) } go()