-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[cxx-interop] Import typedef
-ed template instantiations
#32950
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f6aba5e
37e7250
7cc5bc3
504e7aa
b5dedaf
f94381f
4ef3f11
a799142
48a7f58
19b1a48
b3ee3fd
af8b601
b2b4df4
f254133
f885bfd
82db93b
92c50fc
92183a5
03acf1a
ed4cef9
9aea080
2543808
4174cb0
d41e7ae
35a532d
44f6be0
ccecfb0
ac0ee65
10ccf60
3bf07ba
696561a
132c652
d9672d7
a55c910
2fe1324
6b33e78
5957b9a
2bed093
dd5d8b8
8b3f7ce
e8e520e
9d73a76
3be0ce5
9d23642
3e33c83
806d77c
de0c304
cc49f22
e52f480
8cd82eb
d39dee5
27eb828
2782db5
7300f81
8f11ace
5c79803
26e77a7
37ff5ac
c40d45d
67be1bf
cbf7aff
6b653cb
aae18ae
f0f7710
2ba3396
db2e990
6070598
9d54715
c48342c
ae3275a
0965b7b
9cade2c
21d41f8
3046c15
bc695ed
50e503b
f29a93b
e7c5172
f23898a
3eeaabc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,6 +67,7 @@ Assumptions: | |
+ [Function templates: calls with generic type parameters](#function-templates-calls-with-generic-type-parameters) | ||
+ [Function templates: importing as real generic functions](#function-templates-importing-as-real-generic-functions) | ||
+ [Class templates](#class-templates) | ||
+ [Class templates: importing instantiation behind typedef](#class-templates-importing-instantiation-behind-typedef) | ||
+ [Class templates: importing specific specilalizations](#class-templates-importing-specific-specilalizations) | ||
+ [Class templates: using with generic type parameters](#class-templates-using-with-generic-type-parameters) | ||
+ [Class templates: using in generic code through a synthesized protocol](#class-templates-using-in-generic-code-through-a-synthesized-protocol) | ||
|
@@ -2575,6 +2576,45 @@ We could ignore explicit specializations of function templates, because they | |
don't affect the API. Explicit specializations of class templates can | ||
dramatically change the API of the type. | ||
|
||
### Class templates: Importing full class template instantiations | ||
|
||
A class template instantiation could be imported as a struct named | ||
`__CxxTemplateInst` plus Itanium mangled type of the instantiation (see the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of prefixing each declaration name, could we add another special module context like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes we could. The benefit would be having shorter mangled names and smaller metadata. The downside is slight increase in implementation complexity. For my use cases, I'd definitely appreciate any shortening of mangled names I can get. However, we biased towards reducing implementation complexity. What's your preference? |
||
`type` production in the Itanium specification). Note that Itanium mangling is | ||
used on all platforms, regardless of the ABI of the C++ toolchain, to ensure | ||
that the mangled name is a valid Swift type name (this is not the case for MSVC | ||
mangled names). A prefix with a double underscore (to ensure we have a reserved | ||
C++ identifier) is added to limit the possibility for conflicts with names of | ||
user-defined structs. The struct is notionally defined in the `__C` module, | ||
similarly to regular C and C++ structs and classes. Consider the following C++ | ||
module: | ||
|
||
```c++ | ||
// C++ header. | ||
|
||
template<class T> | ||
struct MagicWrapper { | ||
T t; | ||
}; | ||
struct MagicNumber {}; | ||
|
||
typedef MagicWrapper<MagicNumber> WrappedMagicNumber; | ||
``` | ||
|
||
`WrappedMagicNumber` will be imported as a typealias for a struct | ||
`__CxxTemplateInst12MagicWrapperI11MagicNumberE`. Interface of the imported | ||
module will look as follows: | ||
|
||
```swift | ||
// C++ header imported to Swift. | ||
|
||
struct __CxxTemplateInst12MagicWrapperI11MagicNumberE { | ||
var t: MagicNumber | ||
} | ||
struct MagicNumber {} | ||
typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE | ||
``` | ||
|
||
### Class templates: importing specific specilalizations | ||
|
||
Just like with calls to C++ function templates, it is easy to compile a use of a | ||
|
@@ -2752,7 +2792,7 @@ func useConcrete() { | |
|
||
### Class templates: importing as real generic structs | ||
|
||
If we know the complete set of allowed type arguments to a C++ function | ||
If we know the complete set of allowed type arguments to a C++ struct | ||
template, we could import it as an actual Swift generic struct. Every method of | ||
that struct will perform dynamic dispatch based on type parameters. See | ||
the section about function templates for more details. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H | ||
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H | ||
|
||
template<class T> | ||
struct MagicWrapper { | ||
T t; | ||
int getValuePlusArg(int arg) const { return t.getValue() + arg; } | ||
}; | ||
|
||
struct IntWrapper { | ||
int value; | ||
int getValue() const { return value; } | ||
}; | ||
|
||
typedef MagicWrapper<IntWrapper> WrappedMagicNumberA; | ||
typedef MagicWrapper<IntWrapper> WrappedMagicNumberB; | ||
|
||
#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H | ||
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H | ||
|
||
template<class T> | ||
struct MagicWrapper { | ||
T t; | ||
int getValuePlusArg(int arg) const { return t.getValue() + arg; } | ||
}; | ||
|
||
struct IntWrapper { | ||
int value; | ||
int getValue() const { return value; } | ||
}; | ||
|
||
inline int forceInstantiation() { | ||
auto t = MagicWrapper<IntWrapper>(); | ||
return t.getValuePlusArg(14); | ||
} | ||
|
||
// The ClassTemplateSpecializationDecl node for MagicWrapper<IntWrapper> already has a definition | ||
// because function above forced the instantiation. Its members are fully | ||
// instantiated, so nothing needs to be explicitly instantiated by the Swift | ||
// compiler. | ||
typedef MagicWrapper<IntWrapper> FullyDefinedMagicallyWrappedInt; | ||
|
||
#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H | ||
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H | ||
|
||
template<class T> | ||
struct MagicWrapper { | ||
T t; | ||
int getValuePlusArg(int arg) const { return t.getValue() + arg; } | ||
}; | ||
|
||
struct IntWrapper { | ||
int value; | ||
int getValue() const { return value; } | ||
}; | ||
|
||
inline MagicWrapper<IntWrapper> forceInstantiation() { | ||
return MagicWrapper<IntWrapper>(); | ||
} | ||
|
||
// The ClassTemplateSpecializationDecl node for MagicWrapper<IntWrapper> already has a definition | ||
// because function above forced the instantiation. Its members are not | ||
// instantiated though, the Swift compiler needs to instantiate them. | ||
typedef MagicWrapper<IntWrapper> PartiallyDefinedMagicallyWrappedInt; | ||
|
||
#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H | ||
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H | ||
|
||
template<class T> | ||
struct MagicWrapper { | ||
T t; | ||
int getValuePlusArg(int arg) const { return t + arg; } | ||
}; | ||
|
||
typedef MagicWrapper<int> WrappedMagicInt; | ||
|
||
#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H | ||
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H | ||
|
||
template<class T> | ||
struct MagicWrapper { | ||
T t; | ||
int getValuePlusArg(int arg) const { return t.getValue() + arg; } | ||
}; | ||
|
||
struct IntWrapper { | ||
int value; | ||
int getValue() const { return value; } | ||
}; | ||
|
||
// The ClassTemplateSpecializationDecl node for MagicWrapper<IntWrapper> doesn't have a | ||
// definition in Clang because nothing in this header required the | ||
// instantiation. Therefore, the Swift compiler must trigger instantiation. | ||
typedef MagicWrapper<IntWrapper> MagicallyWrappedIntWithoutDefinition; | ||
|
||
#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H | ||
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H | ||
|
||
struct MagicNumber { | ||
int getInt() const { return 42; } | ||
}; | ||
|
||
template<class T> | ||
struct MagicWrapper { | ||
void callGetInt() const { | ||
T::getIntDoesNotExist(); | ||
} | ||
|
||
template <typename A> int sfinaeGetInt(A a, decltype(&A::getInt)) { | ||
return a.getInt(); | ||
} | ||
template <typename A> int sfinaeGetInt(A a, ...) { | ||
return -42; | ||
} | ||
}; | ||
|
||
typedef MagicWrapper<int> BrokenMagicWrapper; | ||
|
||
#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H |
Uh oh!
There was an error while loading. Please reload this page.