Skip to content

Conversation

@egorzhdan
Copy link
Contributor

C++ allows function templates that do not use all of their template parameters in the signature, such as:

template <typename T>
bool foo();

This is not compatible with Swift's generic model, so to let clients call such functions from Swift, ClangImporter generates an extra metatype parameter:

func foo<T>(T: T.Type) -> Bool

// Usage:
foo(Int.self)
foo(Bool.self)

That logic had a flaw that surfaced when the C++ function's behavior differs depending on the templated parameter. Instead of instantiating the function template with all of the required template parameters, and using the corresponding instantiation for each call, Swift was (correctly) instantiating the template for the necessary types, but then silently dropping all of the instantiations except for one, and using the remaining one for all callsites. This happened because all of the instantiations were getting the same name in Swift, and therefore had the exact same mangled name, which caused SILGen to pick one and discard the others.

This makes sure that if the extra metatype parameter was added to a function template, all of the function instantiations get unique mangled names.

rdar://166184513

…ed metatype parameters

C++ allows function templates that do not use all of their template parameters in the signature, such as:
```
template <typename T>
bool foo();
```

This is not compatible with Swift's generic model, so to let clients call such functions from Swift, ClangImporter generates an extra metatype parameter:
```
func foo<T>(T: T.Type) -> Bool

// Usage:
foo(Int.self)
foo(Bool.self)
```

That logic had a flaw that surfaced when the C++ function's behavior differs depending on the templated parameter. Instead of instantiating the function template with all of the required template parameters, and using the corresponding instantiation for each call, Swift was (correctly) instantiating the template for the necessary types, but then silently dropping all of the instantiations except for one, and using the remaining one for all callsites. This happened because all of the instantiations were getting the same name in Swift, and therefore had the exact same mangled name, which caused SILGen to pick one and discard the others.

This makes sure that if the extra metatype parameter was added to a function template, all of the function instantiations get unique mangled names.

rdar://166184513
@egorzhdan egorzhdan added the c++ interop Feature: Interoperability with C++ label Dec 18, 2025
@egorzhdan
Copy link
Contributor Author

@swift-ci please test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ interop Feature: Interoperability with C++

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants