Skip to content

[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

Merged
merged 80 commits into from
Aug 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
f6aba5e
wip
hlopko May 29, 2020
37e7250
Progress
hlopko Jun 10, 2020
7cc5bc3
Stuff
hlopko Jun 11, 2020
504e7aa
Stuff
hlopko Jun 11, 2020
b5dedaf
Change naive name mangling with clang mangler
hlopko Jun 12, 2020
f94381f
Extract decl-with-definition
hlopko Jul 14, 2020
4ef3f11
Extract decl-with-definition-of-members
hlopko Jul 14, 2020
a799142
Extract decl-without-definition
hlopko Jul 14, 2020
48a7f58
Extract canonical-types
hlopko Jul 14, 2020
19b1a48
Add templates-with-primitive-argument
hlopko Jul 14, 2020
b3ee3fd
Extract explitic-specialization
hlopko Jul 15, 2020
af8b601
Extract using-directive
hlopko Jul 15, 2020
b2b4df4
Remove old files
hlopko Jul 15, 2020
f254133
Add a silgen test
scentini Jul 16, 2020
f885bfd
Refactor tests
hlopko Jul 16, 2020
82db93b
Use Itanium mangler also on windows
hlopko Jul 16, 2020
92c50fc
Replace _ZTS prefix with __CxxTemplateInst in the fake struct name
scentini Jul 16, 2020
92183a5
Add non-passing tests caused by eager instantiation
hlopko Jul 17, 2020
03acf1a
Add sfinae failing example
hlopko Jul 17, 2020
ed4cef9
Cleanup
hlopko Jul 17, 2020
9aea080
Add canonical types silgen test
hlopko Jul 17, 2020
2543808
Add irgen tests
hlopko Jul 17, 2020
4174cb0
Add module interface tests, clean old tests
scentini Jul 17, 2020
d41e7ae
Remove debug test runs
hlopko Jul 20, 2020
35a532d
Merge branch 'master' into typedefs
hlopko Jul 20, 2020
44f6be0
Merge branch 'master' into typedefs
hlopko Jul 21, 2020
ccecfb0
Merge branch 'master' into typedefs
hlopko Jul 23, 2020
ac0ee65
Fix i386 iphone target
hlopko Jul 24, 2020
10ccf60
Update test/Interop/Cxx/templates/Inputs/decl-with-definition-includi…
Jul 28, 2020
3bf07ba
Add a section to the interop manifesto
hlopko Jul 28, 2020
696561a
Add comments
hlopko Jul 28, 2020
132c652
Fix check-not
hlopko Jul 28, 2020
d9672d7
Update test/Interop/Cxx/templates/eager-instatiation-problems.swift
Jul 28, 2020
a55c910
Update test/Interop/Cxx/templates/Inputs/decl-with-definition.h
Jul 28, 2020
2fe1324
Update test/Interop/Cxx/templates/Inputs/decl-with-definition.h
Jul 28, 2020
6b33e78
Update test/Interop/Cxx/templates/Inputs/decl-with-definition-includi…
Jul 28, 2020
5957b9a
Simplify canonical-types tests
hlopko Jul 28, 2020
2bed093
[WIP] Add mangling tests
hlopko Jul 28, 2020
dd5d8b8
Add mangling tests
hlopko Jul 29, 2020
8b3f7ce
Extract constant
hlopko Jul 29, 2020
e8e520e
Add linkage test
scentini Jul 29, 2020
9d73a76
Add clarity to tests
scentini Jul 29, 2020
3be0ce5
Fix formatting
hlopko Jul 30, 2020
9d23642
Document __C
hlopko Jul 30, 2020
3e33c83
Remove extra test run
hlopko Jul 30, 2020
806d77c
Add demangling test
hlopko Jul 30, 2020
de0c304
Merge branch 'mangling_docs' into typedefs
hlopko Jul 31, 2020
cc49f22
Document __CxxTemplateInst in mangling docs
hlopko Jul 31, 2020
e52f480
Update docs/ABI/Mangling.rst
Aug 6, 2020
8cd82eb
Update docs/ABI/Mangling.rst
Aug 6, 2020
d39dee5
Update docs/ABI/Mangling.rst
Aug 6, 2020
27eb828
Update docs/CppInteroperabilityManifesto.md
Aug 6, 2020
2782db5
Update test/Interop/Cxx/templates/Inputs/linkage.h
Aug 6, 2020
7300f81
Update test/Interop/Cxx/templates/canonical-types.swift
Aug 6, 2020
8f11ace
Update test/Interop/Cxx/templates/explicit-specialization.swift
Aug 6, 2020
5c79803
Update docs/ABI/Mangling.rst
Aug 3, 2020
26e77a7
Add example
hlopko Aug 3, 2020
37ff5ac
Fix rst syntax
Aug 3, 2020
c40d45d
Update docs/ABI/Mangling.rst
Aug 6, 2020
67be1bf
Update docs/ABI/Mangling.rst
Aug 7, 2020
cbf7aff
Address comments
hlopko Aug 7, 2020
6b653cb
Add doc example
hlopko Aug 7, 2020
aae18ae
Reflow
hlopko Aug 7, 2020
f0f7710
Merge master
hlopko Aug 10, 2020
2ba3396
Update docs/CppInteroperabilityManifesto.md
Aug 10, 2020
db2e990
Update docs/CppInteroperabilityManifesto.md
Aug 10, 2020
6070598
Update lib/AST/ASTMangler.cpp
Aug 10, 2020
9d54715
Update lib/AST/ASTMangler.cpp
Aug 10, 2020
c48342c
Update lib/ClangImporter/ImportDecl.cpp
Aug 10, 2020
ae3275a
Update lib/ClangImporter/ImportDecl.cpp
Aug 10, 2020
0965b7b
Update test/Interop/Cxx/templates/Inputs/decl-with-definition-includi…
Aug 10, 2020
9cade2c
Update test/Interop/Cxx/templates/Inputs/decl-with-definition.h
Aug 10, 2020
21d41f8
Update test/Interop/Cxx/templates/Inputs/decl-without-definition.h
Aug 10, 2020
3046c15
Update test/Interop/Cxx/templates/Inputs/decl-without-definition.h
Aug 10, 2020
bc695ed
Update test/Interop/Cxx/templates/Inputs/linkage.h
Aug 10, 2020
50e503b
Sync CppInteroperabilityManifesto with mangling docs
hlopko Aug 10, 2020
f29a93b
Address comments
hlopko Aug 10, 2020
e7c5172
Typo
hlopko Aug 10, 2020
f23898a
Merge branch 'master' into typedefs
hlopko Aug 10, 2020
3eeaabc
Update docs/ABI/Mangling.rst
Aug 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1107,3 +1107,40 @@ nominal type descriptor symbol for ``CxxStruct`` while compiling the ``main`` mo
.. code::

sSo9CxxStructVMn // -> nominal type descriptor for __C.CxxStruct

Importing C++ class template instantiations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A class template instantiation is imported as a struct named
``__CxxTemplateInst`` plus Itanium mangled type of the instantiation (see the
``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:

.. code-block:: c++

template<class T>
struct MagicWrapper {
T t;
};

struct MagicNumber {};

typedef MagicWrapper<MagicNumber> WrappedMagicNumber;

``WrappedMagicNumber`` is imported as a typealias for struct
``__CxxTemplateInst12MagicWrapperI11MagicNumberE``. Interface of the imported
module looks as follows:

.. code-block:: swift

struct __CxxTemplateInst12MagicWrapperI11MagicNumberE {
var t: MagicNumber
}
struct MagicNumber {}
typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE
42 changes: 41 additions & 1 deletion docs/CppInteroperabilityManifesto.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The 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 So and SC for ObjC/C synthesized declarations?

Copy link
Contributor

Choose a reason for hiding this comment

The 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
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ constexpr static const StringLiteral MANGLING_MODULE_OBJC = "__C";
constexpr static const StringLiteral MANGLING_MODULE_CLANG_IMPORTER =
"__C_Synthesized";

/// The name prefix for C++ template instantiation imported as a Swift struct.
constexpr static const StringLiteral CXX_TEMPLATE_INST_PREFIX =
"__CxxTemplateInst";

constexpr static const StringLiteral SEMANTICS_PROGRAMTERMINATION_POINT =
"programtermination_point";

Expand Down
9 changes: 9 additions & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Mangle.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
Expand Down Expand Up @@ -2114,6 +2115,7 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
// Always use Clang names for imported Clang declarations, unless they don't
// have one.
auto tryAppendClangName = [this, decl]() -> bool {
auto *nominal = dyn_cast<NominalTypeDecl>(decl);
auto namedDecl = getClangDeclForMangling(decl);
if (!namedDecl)
return false;
Expand All @@ -2126,6 +2128,13 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
appendIdentifier(interface->getObjCRuntimeNameAsString());
} else if (UseObjCRuntimeNames && protocol) {
appendIdentifier(protocol->getObjCRuntimeNameAsString());
} else if (auto ctsd = dyn_cast<clang::ClassTemplateSpecializationDecl>(namedDecl)) {
// If this is a `ClassTemplateSpecializationDecl`, it was
// imported as a Swift decl with `__CxxTemplateInst...` name.
// `ClassTemplateSpecializationDecl`'s name does not include information about
// template arguments, and in order to prevent name clashes we use the
// name of the Swift decl which does include template arguments.
appendIdentifier(nominal->getName().str());
} else {
appendIdentifier(namedDecl->getName());
}
Expand Down
29 changes: 24 additions & 5 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3477,14 +3477,33 @@ namespace {

Decl *VisitClassTemplateSpecializationDecl(
const clang::ClassTemplateSpecializationDecl *decl) {
// FIXME: We could import specializations, but perhaps only as unnamed
// structural types.
return nullptr;
// `Sema::isCompleteType` will try to instantiate the class template as a
// side-effect and we rely on this here. `decl->getDefinition()` can
// return nullptr before the call to sema and return its definition
// afterwards.
if (!Impl.getClangSema().isCompleteType(
decl->getLocation(),
Impl.getClangASTContext().getRecordType(decl))) {
// If we got nullptr definition now it means the type is not complete.
// We don't import incomplete types.
return nullptr;
}
auto def = dyn_cast<clang::ClassTemplateSpecializationDecl>(
decl->getDefinition());
assert(def && "Class template instantiation didn't have definition");
// FIXME: This will instantiate all members of the specialization (and detect
// instantiation failures in them), which can be more than is necessary
// and is more than what Clang does. As a result we reject some C++
// programs that Clang accepts.
Impl.getClangSema().InstantiateClassTemplateSpecializationMembers(
def->getLocation(), def, clang::TSK_ExplicitInstantiationDefinition);

return VisitRecordDecl(def);
}

Decl *VisitClassTemplatePartialSpecializationDecl(
const clang::ClassTemplatePartialSpecializationDecl *decl) {
// Note: templates are not imported.
const clang::ClassTemplatePartialSpecializationDecl *decl) {
// Note: partial template specializations are not imported.
return nullptr;
}

Expand Down
30 changes: 30 additions & 0 deletions lib/ClangImporter/ImportName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
#include "swift/Basic/StringExtras.h"
#include "swift/ClangImporter/ClangImporterOptions.h"
#include "swift/Parse/Parser.h"
#include "swift/Strings.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Mangle.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/OperatorKinds.h"
Expand Down Expand Up @@ -1698,6 +1700,34 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
}
}

if (auto classTemplateSpecDecl =
dyn_cast<clang::ClassTemplateSpecializationDecl>(D)) {
if (!isa<clang::ClassTemplatePartialSpecializationDecl>(D)) {

auto &astContext = classTemplateSpecDecl->getASTContext();
// Itanium mangler produces valid Swift identifiers, use it to generate a name for
// this instantiation.
clang::MangleContext *mangler = clang::ItaniumMangleContext::create(
astContext, astContext.getDiagnostics());
llvm::SmallString<128> storage;
llvm::raw_svector_ostream buffer(storage);
mangler->mangleTypeName(astContext.getRecordType(classTemplateSpecDecl),
buffer);

// The Itanium mangler does not provide a way to get the mangled
// representation of a type. Instead, we call mangleTypeName() that
// returns the name of the RTTI typeinfo symbol, and remove the _ZTS
// prefix. Then we prepend __CxxTemplateInst to reduce chances of conflict
// with regular C and C++ structs.
llvm::SmallString<128> mangledNameStorage;
llvm::raw_svector_ostream mangledName(mangledNameStorage);
assert(buffer.str().take_front(4) == "_ZTS");
mangledName << CXX_TEMPLATE_INST_PREFIX << buffer.str().drop_front(4);

baseName = swiftCtx.getIdentifier(mangledName.str()).get();
}
}

// swift_newtype-ed declarations may have common words with the type name
// stripped.
if (auto newtypeDecl = findSwiftNewtype(D, clangSema, version)) {
Expand Down
23 changes: 21 additions & 2 deletions lib/ClangImporter/SwiftLookupTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1881,10 +1881,16 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table,
// struct names when relevant, not just pointer names. That way we can check
// both CFDatabase.def and the objc_bridge attribute and cover all our bases.
if (auto *tagDecl = dyn_cast<clang::TagDecl>(named)) {
if (!tagDecl->getDefinition())
// We add entries for ClassTemplateSpecializations that don't have
// definition. It's possible that the decl will be instantiated by
// SwiftDeclConverter later on. We cannot force instantiating
// ClassTemplateSPecializations here because we're currently writing the
// AST, so we cannot modify it.
if (!isa<clang::ClassTemplateSpecializationDecl>(named) &&
!tagDecl->getDefinition()) {
return;
}
}

// If we have a name to import as, add this entry to the table.
auto currentVersion =
ImportNameVersion::fromOptions(nameImporter.getLangOpts());
Expand Down Expand Up @@ -2077,6 +2083,19 @@ void SwiftLookupTableWriter::populateTableWithDecl(SwiftLookupTable &table,

// Add this entry to the lookup table.
addEntryToLookupTable(table, named, nameImporter);
if (auto typedefDecl = dyn_cast<clang::TypedefNameDecl>(named)) {
if (auto typedefType = dyn_cast<clang::TemplateSpecializationType>(
typedefDecl->getUnderlyingType())) {
if (auto CTSD = dyn_cast<clang::ClassTemplateSpecializationDecl>(
typedefType->getAsTagDecl())) {
// Adding template instantiation behind typedef as a top-level entry
// so the instantiation appears in the API.
assert(!isa<clang::ClassTemplatePartialSpecializationDecl>(CTSD) &&
"Class template partial specialization cannot appear behind typedef");
addEntryToLookupTable(table, CTSD, nameImporter);
}
}
}
}

void SwiftLookupTableWriter::populateTable(SwiftLookupTable &table,
Expand Down
18 changes: 18 additions & 0 deletions test/Interop/Cxx/templates/Inputs/canonical-types.h
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
24 changes: 24 additions & 0 deletions test/Interop/Cxx/templates/Inputs/decl-with-definition.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
12 changes: 12 additions & 0 deletions test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.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
20 changes: 20 additions & 0 deletions test/Interop/Cxx/templates/Inputs/decl-without-definition.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
24 changes: 24 additions & 0 deletions test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.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
Loading