From 168c92821243e2eef5c62d642308c548ba7cdad9 Mon Sep 17 00:00:00 2001 From: John Hui Date: Tue, 19 May 2026 18:12:37 -0700 Subject: [PATCH] [cxx-interop] Fix crash when specializing a templated SubscriptDecl rewriteIntegerTypes unwrapped the outer (Self) -> ... curry layer for any instance member, constructor, or static decl. SubscriptDecl interface types are not curried this way (they are already (Args) -> Element), so the strip overshot into the bare element type and the subsequent getParams() dereferenced garbage. Gate the unwrap on hasImplicitSelfDecl(), which is the precise condition for having an outer Self curry layer. rdar://177482177 --- lib/ClangImporter/ClangImporter.cpp | 20 +++++++++---------- .../operators/Inputs/subscript-overloads.h | 11 ++++++++++ .../subscript-overloads-typechecker.swift | 8 ++++++++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index d9b62241a4b5d..c0f7cdd7f2497 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -7363,19 +7363,17 @@ ClangImporter::instantiateCXXClassTemplate( // "long long" and then back into Swift as "Int64" not "Int." static ValueDecl *rewriteIntegerTypes(SubstitutionMap subst, ValueDecl *oldDecl, AbstractFunctionDecl *newDecl) { - auto originalFnSubst = cast(oldDecl) - ->getInterfaceType() + auto originalFnSubst = oldDecl->getInterfaceType() ->getAs() ->substGenericArgs(subst); - // The constructor type is a function type as follows: - // (CType.Type) -> (Generic) -> CType - // And a method's function type is as follows: - // (inout CType) -> (Generic) -> Void - // In either case, we only want the result of that function type because that - // is the function type with the generic params that need to be substituted: - // (Generic) -> CType - if (isa(oldDecl) || oldDecl->isInstanceMember() || - oldDecl->isStatic()) + // AbstractFunctionDecl interface types with an implicit self are curried as: + // (Self[.Type]) -> (Generic) -> Result + // Strip the outer self arrow to get the (Generic) -> Result layer, which is + // what the rest of this function compares against newDecl's parameters. + // SubscriptDecl interface types are not curried this way (they are already + // (Generic) -> Element; see InterfaceTypeRequest::evaluate). + if (auto *afd = dyn_cast(oldDecl); + afd && afd->hasImplicitSelfDecl()) originalFnSubst = cast(originalFnSubst->getResult().getPointer()); SmallVector fixedParameters; diff --git a/test/Interop/Cxx/operators/Inputs/subscript-overloads.h b/test/Interop/Cxx/operators/Inputs/subscript-overloads.h index 4e829420bd8e8..23aa30b07c4e9 100644 --- a/test/Interop/Cxx/operators/Inputs/subscript-overloads.h +++ b/test/Interop/Cxx/operators/Inputs/subscript-overloads.h @@ -90,3 +90,14 @@ class Overloaded { __attribute__((deprecated("use GetVal instead"))) unsigned operator[](DeprecatedIndex d) const { return storage[d.index].val; } }; + +struct TemplatedReturningInt { + int data[4] = {}; + template int &operator[](I index) { return data[index]; } +}; + +struct TemplatedTakingInt { + int data[4] = {}; + // This template doesn't instantiate unless I is int. Bogus but valid. + template I &operator[](int x) { return data[x]; } +}; diff --git a/test/Interop/Cxx/operators/subscript-overloads-typechecker.swift b/test/Interop/Cxx/operators/subscript-overloads-typechecker.swift index 13a9f92a2873f..0af814cf96dc5 100644 --- a/test/Interop/Cxx/operators/subscript-overloads-typechecker.swift +++ b/test/Interop/Cxx/operators/subscript-overloads-typechecker.swift @@ -122,3 +122,11 @@ u[getValPtr] = uGetValPtr // expected-error {{subscript is get-only}} let deprecatedIdx = Overloaded.DeprecatedIndex(index: 0) let _: CUnsignedInt = v[deprecatedIdx] // expected-warning {{deprecated: use GetVal instead}} + +var tri = TemplatedReturningInt() +tri[CInt(0)] = CInt(4) +let _ = tri[CInt(0)] + +var tti = TemplatedTakingInt() +tti[CInt(0)] = CInt(4) +let _: CInt = tti[CInt(0)]