diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index a65799b8c53cd..f35339c9ebb70 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -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 + struct MagicWrapper { + T t; + }; + + struct MagicNumber {}; + + typedef MagicWrapper 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 diff --git a/docs/CppInteroperabilityManifesto.md b/docs/CppInteroperabilityManifesto.md index f3a8df51820d2..b23c914268c1b 100644 --- a/docs/CppInteroperabilityManifesto.md +++ b/docs/CppInteroperabilityManifesto.md @@ -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 +`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 +struct MagicWrapper { + T t; +}; +struct MagicNumber {}; + +typedef MagicWrapper 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. diff --git a/include/swift/Strings.h b/include/swift/Strings.h index 32a7bb2d0072c..69b29ff4a52b9 100644 --- a/include/swift/Strings.h +++ b/include/swift/Strings.h @@ -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"; diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index e013ad5db8b3c..be1c4af4e0ea1 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -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" @@ -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(decl); auto namedDecl = getClangDeclForMangling(decl); if (!namedDecl) return false; @@ -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(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()); } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index e35b0aed470b7..b0ca58c4c4047 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -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( + 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; } diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 1611d20507369..46817ce93de2a 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -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" @@ -1698,6 +1700,34 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, } } + if (auto classTemplateSpecDecl = + dyn_cast(D)) { + if (!isa(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)) { diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index 74a64dcb025d5..3ac0d0fe45d0c 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -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(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(named) && + !tagDecl->getDefinition()) { return; + } } - // If we have a name to import as, add this entry to the table. auto currentVersion = ImportNameVersion::fromOptions(nameImporter.getLangOpts()); @@ -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(named)) { + if (auto typedefType = dyn_cast( + typedefDecl->getUnderlyingType())) { + if (auto CTSD = dyn_cast( + typedefType->getAsTagDecl())) { + // Adding template instantiation behind typedef as a top-level entry + // so the instantiation appears in the API. + assert(!isa(CTSD) && + "Class template partial specialization cannot appear behind typedef"); + addEntryToLookupTable(table, CTSD, nameImporter); + } + } + } } void SwiftLookupTableWriter::populateTable(SwiftLookupTable &table, diff --git a/test/Interop/Cxx/templates/Inputs/canonical-types.h b/test/Interop/Cxx/templates/Inputs/canonical-types.h new file mode 100644 index 0000000000000..865c85a882cf9 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/canonical-types.h @@ -0,0 +1,18 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +typedef MagicWrapper WrappedMagicNumberA; +typedef MagicWrapper WrappedMagicNumberB; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_CANONICAL_TYPES_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h b/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h new file mode 100644 index 0000000000000..4c772c9dfaca0 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-definition-including-members.h @@ -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 +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(); + return t.getValuePlusArg(14); +} + +// The ClassTemplateSpecializationDecl node for MagicWrapper 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 FullyDefinedMagicallyWrappedInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_INCLUDING_MEMBERS_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-definition.h b/test/Interop/Cxx/templates/Inputs/decl-with-definition.h new file mode 100644 index 0000000000000..d8fb7b56f676b --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-definition.h @@ -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 +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +inline MagicWrapper forceInstantiation() { + return MagicWrapper(); +} + +// The ClassTemplateSpecializationDecl node for MagicWrapper 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 PartiallyDefinedMagicallyWrappedInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_DEFINITION_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h b/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h new file mode 100644 index 0000000000000..2bba7d493e342 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-with-primitive-argument.h @@ -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 +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t + arg; } +}; + +typedef MagicWrapper WrappedMagicInt; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITH_PRIMITIVE_ARGUMENT_H diff --git a/test/Interop/Cxx/templates/Inputs/decl-without-definition.h b/test/Interop/Cxx/templates/Inputs/decl-without-definition.h new file mode 100644 index 0000000000000..a4eb3506672b2 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/decl-without-definition.h @@ -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 +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 doesn't have a +// definition in Clang because nothing in this header required the +// instantiation. Therefore, the Swift compiler must trigger instantiation. +typedef MagicWrapper MagicallyWrappedIntWithoutDefinition; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_DECL_WITHOUT_DEFINITION_H diff --git a/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h b/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h new file mode 100644 index 0000000000000..5992054ae9d3d --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/eager-instantiation-problems.h @@ -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 +struct MagicWrapper { + void callGetInt() const { + T::getIntDoesNotExist(); + } + + template int sfinaeGetInt(A a, decltype(&A::getInt)) { + return a.getInt(); + } + template int sfinaeGetInt(A a, ...) { + return -42; + } +}; + +typedef MagicWrapper BrokenMagicWrapper; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_EAGER_INSTANTIATION_PROBLEMS_H diff --git a/test/Interop/Cxx/templates/Inputs/explicit-specialization.h b/test/Interop/Cxx/templates/Inputs/explicit-specialization.h new file mode 100644 index 0000000000000..62b9f7aa030af --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/explicit-specialization.h @@ -0,0 +1,29 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H + +struct SpecializedIntWrapper { + int value; + int getValue() const { return value; } +}; + +struct NonSpecializedIntWrapper { + int value; + int getValue() const { return value; } +}; + +template +struct MagicWrapper { + T t; + int doubleIfSpecializedElseTriple() const { return 3 * t.getValue(); } +}; + +template <> +struct MagicWrapper { + SpecializedIntWrapper t; + int doubleIfSpecializedElseTriple() const { return 2 * t.getValue(); } +}; + +typedef MagicWrapper WrapperWithSpecialization; +typedef MagicWrapper WrapperWithoutSpecialization; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_EXPLICIT_SPECIALIZATION_H diff --git a/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h b/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h new file mode 100644 index 0000000000000..d700209d93873 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/linkage-of-swift-symbols-for-imported-types.h @@ -0,0 +1,21 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H + +template +struct MagicWrapper { + T t; + int callGetInt() const { + return t.getInt() + 5; + } +}; + +struct MagicNumber { + // Swift runtime defines many value witness tables for types with some common layouts. + // This struct's uncommon size forces the compiler to define a new value witness table instead of reusing one from the runtime. + char forceVWTableCreation[57]; + int getInt() const { return 12; } +}; + +typedef MagicWrapper WrappedMagicNumber; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_LINKAGE_OF_SWIFT_SYMBOLS_FOR_IMPORTED_TYPES_H diff --git a/test/Interop/Cxx/templates/Inputs/mangling.h b/test/Interop/Cxx/templates/Inputs/mangling.h new file mode 100644 index 0000000000000..f135b52747600 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/mangling.h @@ -0,0 +1,11 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H + +template +struct MagicWrapper {}; + +typedef MagicWrapper WrappedMagicInt; +typedef MagicWrapper WrappedMagicBool; + + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_MANGLING_H diff --git a/test/Interop/Cxx/templates/Inputs/module.modulemap b/test/Interop/Cxx/templates/Inputs/module.modulemap new file mode 100644 index 0000000000000..af6d28e675a40 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/module.modulemap @@ -0,0 +1,39 @@ +module DeclWithPrimitiveArgument { + header "decl-with-primitive-argument.h" +} + +module DeclWithoutDefinition { + header "decl-without-definition.h" +} + +module DeclWithDefinition { + header "decl-with-definition.h" +} + +module DeclWithDefinitionIncludingMembers { + header "decl-with-definition-including-members.h" +} + +module CanonicalTypes { + header "canonical-types.h" +} + +module ExplicitSpecialization { + header "explicit-specialization.h" +} + +module UsingDirective { + header "using-directive.h" +} + +module EagerInstantiationProblems { + header "eager-instantiation-problems.h" +} + +module Mangling { + header "mangling.h" +} + +module LinkageOfSwiftSymbolsForImportedTypes { + header "linkage-of-swift-symbols-for-imported-types.h" +} diff --git a/test/Interop/Cxx/templates/Inputs/using-directive.h b/test/Interop/Cxx/templates/Inputs/using-directive.h new file mode 100644 index 0000000000000..076660e8a19e4 --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/using-directive.h @@ -0,0 +1,17 @@ +#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H +#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H + +template +struct MagicWrapper { + T t; + int getValuePlusArg(int arg) const { return t.getValue() + arg; } +}; + +struct IntWrapper { + int value; + int getValue() const { return value; } +}; + +using UsingWrappedMagicNumber = MagicWrapper; + +#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_USING_DIRECTIVE_H diff --git a/test/Interop/Cxx/templates/canonical-types-module-interface.swift b/test/Interop/Cxx/templates/canonical-types-module-interface.swift new file mode 100644 index 0000000000000..3a90d1d44311a --- /dev/null +++ b/test/Interop/Cxx/templates/canonical-types-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=CanonicalTypes -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias WrappedMagicNumberA = __CxxTemplateInst12MagicWrapperI10IntWrapperE +// CHECK: typealias WrappedMagicNumberB = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/canonical-types.swift b/test/Interop/Cxx/templates/canonical-types.swift new file mode 100644 index 0000000000000..b399e0fc9b144 --- /dev/null +++ b/test/Interop/Cxx/templates/canonical-types.swift @@ -0,0 +1,15 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import CanonicalTypes +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("canonical-types") { + // Different typedefs with the same C++ canonical type must have the same type from Swift's perspective as well. + expectEqualType(WrappedMagicNumberA.self, WrappedMagicNumberB.self) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-definition-including-members.swift b/test/Interop/Cxx/templates/decl-with-definition-including-members.swift new file mode 100644 index 0000000000000..7d55595d4fbb4 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-including-members.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import DeclWithDefinitionIncludingMembers +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("fully-defined") { + let myInt = IntWrapper(value: 10) + var magicInt = FullyDefinedMagicallyWrappedInt(t: myInt) + expectEqual(magicInt.getValuePlusArg(5), 15) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-definition-irgen.swift b/test/Interop/Cxx/templates/decl-with-definition-irgen.swift new file mode 100644 index 0000000000000..34825a34ce7e4 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-irgen.swift @@ -0,0 +1,33 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import DeclWithDefinition + +public func getWrappedMagicInt() -> CInt { + let myInt = IntWrapper(value: 7) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + return magicInt.getValuePlusArg(13) +} + +// CHECK: define {{(protected |dllexport )?}}swiftcc i32 @"$s4main18getWrappedMagicInts5Int32VyF"() +// CHECK: %magicInt = alloca %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV, align 4 +// CHECK: %magicInt.t = getelementptr inbounds %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV, %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV* %magicInt, i32 0, i32 0 +// CHECK: [[MAGIC_WRAPPER:%.*]] = bitcast %TSo037__CxxTemplateInst12MagicWrapperI10IntE1EV* %magicInt to %struct.MagicWrapper* +// CHECK: call i32 @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|"\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z"}}(%struct.MagicWrapper* [[MAGIC_WRAPPER]], i32 13) + +// CHECK: define weak_odr{{( dso_local)?}} i32 @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|"\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z"}}(%struct.MagicWrapper* %this, i32 %arg) +// CHECK: %this.addr = alloca %struct.MagicWrapper*, align {{4|8}} +// CHECK: store %struct.MagicWrapper* %this, %struct.MagicWrapper** %this.addr, align {{4|8}} +// CHECK: %this1 = load %struct.MagicWrapper*, %struct.MagicWrapper** %this.addr, align {{4|8}} +// CHECK: %t = getelementptr inbounds %struct.MagicWrapper, %struct.MagicWrapper* %this1, i32 0, i32 0 +// CHECK: %call = call i32 @{{_ZNK10IntWrapper8getValueEv|"\?getValue@IntWrapper@@QEBAHXZ"}}(%struct.IntWrapper* %t) +// CHECK: [[ARG:%.*]] = load i32, i32* %arg.addr, align 4 +// CHECK: %add = add nsw i32 %call, [[ARG]] +// CHECK: ret i32 %add + +// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_ZNK10IntWrapper8getValueEv|"\?getValue@IntWrapper@@QEBAHXZ"}}(%struct.IntWrapper* %this) +// CHECK: %this.addr = alloca %struct.IntWrapper*, align {{4|8}} +// CHECK: store %struct.IntWrapper* %this, %struct.IntWrapper** %this.addr, align {{4|8}} +// CHECK: %this1 = load %struct.IntWrapper*, %struct.IntWrapper** %this.addr, align {{4|8}} +// CHECK: %value = getelementptr inbounds %struct.IntWrapper, %struct.IntWrapper* %this1, i32 0, i32 0 +// CHECK: [[VALUE:%.*]] = load i32, i32* %value, align 4 +// CHECK: ret i32 [[VALUE]] diff --git a/test/Interop/Cxx/templates/decl-with-definition-silgen.swift b/test/Interop/Cxx/templates/decl-with-definition-silgen.swift new file mode 100644 index 0000000000000..a9481f6ac9d6c --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition-silgen.swift @@ -0,0 +1,21 @@ +// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import DeclWithDefinition + +public func getWrappedMagicInt() -> CInt { + let myInt = IntWrapper(value: 21) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + return magicInt.getValuePlusArg(32) +} + +// CHECK: // getWrappedMagicInt() +// CHECK: sil @$s4main18getWrappedMagicInts5Int32VyF : $@convention(thin) () -> Int32 { +// CHECK: [[INT_WRAPPER:%.*]] = struct $IntWrapper ([[_:%.*]] : $Int32) +// CHECK: [[_:%.*]] = struct $__CxxTemplateInst12MagicWrapperI10IntWrapperE ([[INT_WRAPPER]] : $IntWrapper) +// CHECK: // function_ref {{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} +// CHECK: [[_:%.*]] = function_ref @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} : $@convention(c) (@inout __CxxTemplateInst12MagicWrapperI10IntWrapperE, Int32) -> Int32 + +// CHECK: // {{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} +// CHECK: MagicWrapper::getValuePlusArg + +// CHECK: sil [clang __CxxTemplateInst12MagicWrapperI10IntWrapperE.getValuePlusArg] @{{_ZNK12MagicWrapperI10IntWrapperE15getValuePlusArgEi|\?getValuePlusArg@\?\$MagicWrapper@UIntWrapper@@@@QEBAHH@Z}} : $@convention(c) (@inout __CxxTemplateInst12MagicWrapperI10IntWrapperE, Int32) -> Int32 diff --git a/test/Interop/Cxx/templates/decl-with-definition.swift b/test/Interop/Cxx/templates/decl-with-definition.swift new file mode 100644 index 0000000000000..ce0841c4b9c9b --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-definition.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import DeclWithDefinition +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("has-partial-definition") { + let myInt = IntWrapper(value: 32) + var magicInt = PartiallyDefinedMagicallyWrappedInt(t: myInt) + expectEqual(magicInt.getValuePlusArg(5), 37) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-with-primitive-argument.swift b/test/Interop/Cxx/templates/decl-with-primitive-argument.swift new file mode 100644 index 0000000000000..a2d5d1f8c9b98 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-with-primitive-argument.swift @@ -0,0 +1,15 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import DeclWithPrimitiveArgument +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("int-argument") { + var wrappedMagicInt = WrappedMagicInt(t: 42) + expectEqual(wrappedMagicInt.getValuePlusArg(5), 47) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift b/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift new file mode 100644 index 0000000000000..ca12841f96cb9 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-without-definition-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=DeclWithoutDefinition -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: init(value: Int32) +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias MagicallyWrappedIntWithoutDefinition = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/decl-without-definition.swift b/test/Interop/Cxx/templates/decl-without-definition.swift new file mode 100644 index 0000000000000..ef97376176ed4 --- /dev/null +++ b/test/Interop/Cxx/templates/decl-without-definition.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import DeclWithoutDefinition +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("without-definition") { + let myInt = IntWrapper(value: 17) + var magicInt = MagicallyWrappedIntWithoutDefinition(t: myInt) + expectEqual(magicInt.getValuePlusArg(11), 28) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/demangling.swift b/test/Interop/Cxx/templates/demangling.swift new file mode 100644 index 0000000000000..ac1e44efefe83 --- /dev/null +++ b/test/Interop/Cxx/templates/demangling.swift @@ -0,0 +1,12 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | grep 'define.*swiftcc.*$' | grep -o '\$[[:alnum:]]\+__CxxTemplateInst[[:alnum:]]\+' | xargs %swift-demangle | %FileCheck %s + +import Mangling + +public func receiveInstantiation(_ i: inout WrappedMagicInt) {} + +public func returnInstantiation() -> WrappedMagicInt { + return WrappedMagicInt() +} + +// CHECK: $s10demangling20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF ---> demangling.receiveInstantiation(inout __C.__CxxTemplateInst12MagicWrapperIiE) -> () +// CHECK: $s10demangling19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF ---> demangling.returnInstantiation() -> __C.__CxxTemplateInst12MagicWrapperIiE diff --git a/test/Interop/Cxx/templates/eager-instatiation-problems.swift b/test/Interop/Cxx/templates/eager-instatiation-problems.swift new file mode 100644 index 0000000000000..b2520b5b78275 --- /dev/null +++ b/test/Interop/Cxx/templates/eager-instatiation-problems.swift @@ -0,0 +1,32 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import EagerInstantiationProblems +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("eager-instantiation-of-members") { + // This will fail with: + // + // error: type 'int' cannot be used prior to '::' because it has no members + // T::getIntDoesNotExist(); + // + // whereas in C++ this compiles. This is caused by ClangImporter eagerly + // instantiating typedeffed templates and also their members. + // TODO(scentini): Fix this + // let _brokenMagicWrapper = BrokenMagicWrapper() +} + +TemplatesTestSuite.test("sfinae-example") { + // This will fail since we are currently not instantiating function templates. + // In C++ the first sfinaeGetInt should fail to instantiate, therefore get + // ignored, and only the second sfinaeGetInt is used. + // TODO(SR-12541): Fix this + // let magicNumber = MagicNumber() + // var brokenMagicWrapper = BrokenMagicWrapper() + // expectEqual(42, brokenMagicWrapper.sfinaeGetInt(magicNumber, 0)) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/explicit-specialization.swift b/test/Interop/Cxx/templates/explicit-specialization.swift new file mode 100644 index 0000000000000..58cb0c4d6746d --- /dev/null +++ b/test/Interop/Cxx/templates/explicit-specialization.swift @@ -0,0 +1,20 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import ExplicitSpecialization +import StdlibUnittest + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("explicit-specialization") { + let specializedInt = SpecializedIntWrapper(value: 7) + var specializedMagicInt = WrapperWithSpecialization(t: specializedInt) + expectEqual(specializedMagicInt.doubleIfSpecializedElseTriple(), 14) + + let nonSpecializedInt = NonSpecializedIntWrapper(value: 7) + var nonSpecializedMagicInt = WrapperWithoutSpecialization(t: nonSpecializedInt) + expectEqual(nonSpecializedMagicInt.doubleIfSpecializedElseTriple(), 21) +} + +runAllTests() diff --git a/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift b/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift new file mode 100644 index 0000000000000..f3a2ae75d69ba --- /dev/null +++ b/test/Interop/Cxx/templates/linkage-of-swift-symbols-for-imported-types-irgen.swift @@ -0,0 +1,28 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import LinkageOfSwiftSymbolsForImportedTypes + +public func forceValueWitnessTableCreation() -> Any { + let magicNumber = MagicNumber() + return WrappedMagicNumber(t: magicNumber) +} + +public func getMagicNumberForLinkageComparison() -> Any { + return MagicNumber() +} + +// CHECK: $sSo11MagicNumberVWV" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMn" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMf" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVML" = linkonce_odr hidden global + +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVWV" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMn" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMf" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVML" = linkonce_odr hidden global + +// CHECK: $sSo11MagicNumberVMB" = linkonce_odr hidden constant +// CHECK: $sSo11MagicNumberVMF" = linkonce_odr hidden constant + +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMB" = linkonce_odr hidden constant +// CHECK: $sSo034__CxxTemplateInst12MagicWrapperI11D7NumberEVMF" = linkonce_odr hidden constant diff --git a/test/Interop/Cxx/templates/mangling-irgen.swift b/test/Interop/Cxx/templates/mangling-irgen.swift new file mode 100644 index 0000000000000..363e1a3e76800 --- /dev/null +++ b/test/Interop/Cxx/templates/mangling-irgen.swift @@ -0,0 +1,18 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import Mangling + +public func receiveInstantiation(_ i: inout WrappedMagicInt) {} + +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF"(%TSo34__CxxTemplateInst12MagicWrapperIiEV* nocapture dereferenceable(1) %0) + +public func receiveInstantiation(_ i: inout WrappedMagicBool) {} + +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20receiveInstantiationyySo34__CxxTemplateInst12MagicWrapperIbEVzF"(%TSo34__CxxTemplateInst12MagicWrapperIbEV* nocapture dereferenceable(1) %0) + +public func returnInstantiation() -> WrappedMagicInt { + return WrappedMagicInt() +} + +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF"() + diff --git a/test/Interop/Cxx/templates/mangling-silgen.swift b/test/Interop/Cxx/templates/mangling-silgen.swift new file mode 100644 index 0000000000000..7d4cc6f7e3c39 --- /dev/null +++ b/test/Interop/Cxx/templates/mangling-silgen.swift @@ -0,0 +1,20 @@ +// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import Mangling + +public func recvInstantiation(_ i: inout WrappedMagicInt) {} + +// CHECK: // recvInstantiation(_:) +// CHECK: sil @$s4main17recvInstantiationyySo34__CxxTemplateInst12MagicWrapperIiEVzF : $@convention(thin) (@inout __CxxTemplateInst12MagicWrapperIiE) -> () + +public func recvInstantiation(_ i: inout WrappedMagicBool) {} + +// CHECK: // recvInstantiation(_:) +// CHECK: sil @$s4main17recvInstantiationyySo34__CxxTemplateInst12MagicWrapperIbEVzF : $@convention(thin) (@inout __CxxTemplateInst12MagicWrapperIbE) -> () + +public func returnInstantiation() -> WrappedMagicInt { + return WrappedMagicInt() +} + +// CHECK: // returnInstantiation() +// CHECK: sil @$s4main19returnInstantiationSo34__CxxTemplateInst12MagicWrapperIiEVyF : $@convention(thin) () -> __CxxTemplateInst12MagicWrapperIiE diff --git a/test/Interop/Cxx/templates/using-directive-module-interface.swift b/test/Interop/Cxx/templates/using-directive-module-interface.swift new file mode 100644 index 0000000000000..81b445d21e3d7 --- /dev/null +++ b/test/Interop/Cxx/templates/using-directive-module-interface.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=UsingDirective -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct __CxxTemplateInst12MagicWrapperI10IntWrapperE { +// CHECK: var t: IntWrapper +// CHECK: init() +// CHECK: init(t: IntWrapper) +// CHECK: mutating func getValuePlusArg(_ arg: Int32) -> Int32 +// CHECK: } +// CHECK: struct IntWrapper { +// CHECK: var value: Int32 +// CHECK: init() +// CHECK: init(value: Int32) +// CHECK: mutating func getValue() -> Int32 +// CHECK: } +// CHECK: typealias UsingWrappedMagicNumber = __CxxTemplateInst12MagicWrapperI10IntWrapperE diff --git a/test/Interop/Cxx/templates/using-directive.swift b/test/Interop/Cxx/templates/using-directive.swift new file mode 100644 index 0000000000000..7f9c983fee834 --- /dev/null +++ b/test/Interop/Cxx/templates/using-directive.swift @@ -0,0 +1,16 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop -Xcc -std=c++17) +// +// REQUIRES: executable_test + +import StdlibUnittest +import UsingDirective + +var TemplatesTestSuite = TestSuite("TemplatesTestSuite") + +TemplatesTestSuite.test("using-directive") { + let myInt = IntWrapper(value: 333) + var magicInt = UsingWrappedMagicNumber(t: myInt) + expectEqual(magicInt.getValuePlusArg(111), 444) +} + +runAllTests() diff --git a/test/lit.cfg b/test/lit.cfg index e8a4a36443fbf..27c40a1cb6764 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -282,6 +282,7 @@ config.sourcekitd_test = inferSwiftBinary('sourcekitd-test') config.complete_test = inferSwiftBinary('complete-test') config.swift_api_digester = inferSwiftBinary('swift-api-digester') config.swift_refactor = inferSwiftBinary('swift-refactor') +config.swift_demangle = inferSwiftBinary('swift-demangle') config.swift_demangle_yamldump = inferSwiftBinary('swift-demangle-yamldump') config.benchmark_o = inferSwiftBinary('Benchmark_O') config.benchmark_driver = inferSwiftBinary('Benchmark_Driver') @@ -439,6 +440,7 @@ config.substitutions.append( ('%llvm-dwarfdump', config.llvm_dwarfdump) ) config.substitutions.append( ('%llvm-readelf', config.llvm_readelf) ) config.substitutions.append( ('%llvm-dis', config.llvm_dis) ) config.substitutions.append( ('%llvm-nm', config.llvm_nm) ) +config.substitutions.append( ('%swift-demangle', config.swift_demangle) ) config.substitutions.append( ('%swift-demangle-yamldump', config.swift_demangle_yamldump) ) config.substitutions.append( ('%Benchmark_O', config.benchmark_o) ) config.substitutions.append( ('%Benchmark_Driver', config.benchmark_driver) )