diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 05e2fd184c4f8..81b6265cf81ae 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -35,6 +35,7 @@ #include "swift/AST/Pattern.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SemanticAttrs.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/Types.h" @@ -47,11 +48,10 @@ #include "swift/Parse/Lexer.h" #include "swift/Parse/Parser.h" #include "swift/Strings.h" - #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" -#include "clang/AST/DeclObjCCommon.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjCCommon.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" @@ -3481,6 +3481,11 @@ namespace { ctors.push_back(createDefaultConstructor(Impl, result)); } + // We can assume that it is possible to correctly construct the object by + // simply initializing its member variables to arbitrary supplied values + // only when the same is possible in C++. While we could check for that + // exactly, checking whether the C++ class is an aggregate + // (C++ [dcl.init.aggr]) has the same effect. bool isAggregate = !cxxRecordDecl || cxxRecordDecl->isAggregate(); if (hasReferenceableFields && hasMemberwiseInitializer && isAggregate) { // The default zero initializer suppresses the implicit value @@ -3513,8 +3518,14 @@ namespace { result->setIsCxxNonTrivial(!cxxRecordDecl->isTriviallyCopyable()); for (auto ctor : cxxRecordDecl->ctors()) { - if (ctor->isCopyConstructor() && - (ctor->isDeleted() || ctor->getAccess() != clang::AS_public)) { + if (ctor->isCopyConstructor()) { + // If we have no way of copying the type we can't import the class + // at all because we cannot express the correct semantics as a swift + // struct. + if (ctor->isDeleted() || ctor->getAccess() != clang::AS_public) + return nullptr; + } + if (ctor->getAccess() != clang::AS_public) { result->setIsCxxNonTrivial(true); break; } @@ -3540,19 +3551,45 @@ namespace { return VisitRecordDecl(decl); auto &clangSema = Impl.getClangSema(); - // Make Clang define the implicit default constructor if the class needs - // it. Make sure we only do this if the class has been fully defined and - // we're not in a dependent context (this is equivalent to the logic in - // CanDeclareSpecialMemberFunction in Clang's SemaLookup.cpp). + // Make Clang define any implicit constructors it may need (copy, + // default). Make sure we only do this if the class has been fully defined + // and we're not in a dependent context (this is equivalent to the logic + // in CanDeclareSpecialMemberFunction in Clang's SemaLookup.cpp). if (decl->getDefinition() && !decl->isBeingDefined() && - !decl->isDependentContext() && - decl->needsImplicitDefaultConstructor()) { - clang::CXXConstructorDecl *ctor = - clangSema.DeclareImplicitDefaultConstructor( - const_cast(decl->getDefinition())); - if (!ctor->isDeleted()) - clangSema.DefineImplicitDefaultConstructor(clang::SourceLocation(), - ctor); + !decl->isDependentContext()) { + if (decl->needsImplicitDefaultConstructor()) { + clang::CXXConstructorDecl *ctor = + clangSema.DeclareImplicitDefaultConstructor( + const_cast(decl->getDefinition())); + if (!ctor->isDeleted()) + clangSema.DefineImplicitDefaultConstructor(clang::SourceLocation(), + ctor); + } + clang::CXXConstructorDecl *copyCtor = nullptr; + if (decl->needsImplicitCopyConstructor()) { + copyCtor = clangSema.DeclareImplicitCopyConstructor( + const_cast(decl)); + } else { + // We may have a defaulted copy constructor that needs to be defined. + // Try to find it. + for (auto methods : decl->methods()) { + if (auto declCtor = dyn_cast(methods)) { + if (declCtor->isCopyConstructor() && declCtor->isDefaulted() && + declCtor->getAccess() == clang::AS_public && + !declCtor->isDeleted() && + // Note: we use "doesThisDeclarationHaveABody" here because + // that's what "DefineImplicitCopyConstructor" checks. + !declCtor->doesThisDeclarationHaveABody()) { + copyCtor = declCtor; + break; + } + } + } + } + if (copyCtor) { + clangSema.DefineImplicitCopyConstructor(clang::SourceLocation(), + copyCtor); + } } return VisitRecordDecl(decl); diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 02c9f8b71ef30..cef95a38e7260 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2788,20 +2788,10 @@ void IRGenModule::emitDynamicReplacementOriginalFunctionThunk(SILFunction *f) { IGF.Builder.CreateRet(Res); } -/// If the calling convention for `ctor` doesn't match the calling convention -/// that we assumed for it when we imported it as `initializer`, emit and -/// return a thunk that conforms to the assumed calling convention. The thunk -/// is marked `alwaysinline`, so it doesn't generate any runtime overhead. -/// If the assumed calling convention was correct, just return `ctor`. -/// -/// See also comments in CXXMethodConventions in SIL/IR/SILFunctionType.cpp. -static llvm::Constant * -emitCXXConstructorThunkIfNeeded(IRGenModule &IGM, SILFunction *initializer, - const clang::CXXConstructorDecl *ctor, - const LinkEntity &entity, - llvm::Constant *ctorAddress) { - Signature signature = IGM.getSignature(initializer->getLoweredFunctionType()); - +llvm::Constant *swift::irgen::emitCXXConstructorThunkIfNeeded( + IRGenModule &IGM, Signature signature, + const clang::CXXConstructorDecl *ctor, StringRef name, + llvm::Constant *ctorAddress) { llvm::FunctionType *assumedFnType = signature.getType(); llvm::FunctionType *ctorFnType = cast(ctorAddress->getType()->getPointerElementType()); @@ -2810,13 +2800,6 @@ emitCXXConstructorThunkIfNeeded(IRGenModule &IGM, SILFunction *initializer, return ctorAddress; } - // The thunk has private linkage, so it doesn't need to have a predictable - // mangled name -- we just need to make sure the name is unique. - llvm::SmallString<32> name; - llvm::raw_svector_ostream stream(name); - stream << "__swift_cxx_ctor"; - entity.mangle(stream); - llvm::Function *thunk = llvm::Function::Create( assumedFnType, llvm::Function::PrivateLinkage, name, &IGM.Module); @@ -2892,11 +2875,20 @@ llvm::Function *IRGenModule::getAddrOfSILFunction( } else { auto globalDecl = getClangGlobalDeclForFunction(clangDecl); clangAddr = getAddrOfClangGlobalDecl(globalDecl, forDefinition); + } - if (auto ctor = dyn_cast(clangDecl)) { - clangAddr = - emitCXXConstructorThunkIfNeeded(*this, f, ctor, entity, clangAddr); - } + if (auto ctor = dyn_cast(clangDecl)) { + Signature signature = getSignature(f->getLoweredFunctionType()); + + // The thunk has private linkage, so it doesn't need to have a predictable + // mangled name -- we just need to make sure the name is unique. + llvm::SmallString<32> name; + llvm::raw_svector_ostream stream(name); + stream << "__swift_cxx_ctor"; + entity.mangle(stream); + + clangAddr = emitCXXConstructorThunkIfNeeded(*this, signature, ctor, name, + clangAddr); } } diff --git a/lib/IRGen/GenDecl.h b/lib/IRGen/GenDecl.h index 40b011b272371..4ac3de02d8348 100644 --- a/lib/IRGen/GenDecl.h +++ b/lib/IRGen/GenDecl.h @@ -17,12 +17,13 @@ #ifndef SWIFT_IRGEN_GENDECL_H #define SWIFT_IRGEN_GENDECL_H +#include "DebugTypeInfo.h" +#include "IRGen.h" #include "swift/Basic/OptimizationMode.h" #include "swift/SIL/SILLocation.h" +#include "clang/AST/DeclCXX.h" #include "llvm/IR/CallingConv.h" #include "llvm/Support/CommandLine.h" -#include "DebugTypeInfo.h" -#include "IRGen.h" namespace llvm { class AttributeList; @@ -57,6 +58,18 @@ namespace irgen { createLinkerDirectiveVariable(IRGenModule &IGM, StringRef Name); void disableAddressSanitizer(IRGenModule &IGM, llvm::GlobalVariable *var); + + /// If the calling convention for `ctor` doesn't match the calling convention + /// that we assumed for it when we imported it as `initializer`, emit and + /// return a thunk that conforms to the assumed calling convention. The thunk + /// is marked `alwaysinline`, so it doesn't generate any runtime overhead. + /// If the assumed calling convention was correct, just return `ctor`. + /// + /// See also comments in CXXMethodConventions in SIL/IR/SILFunctionType.cpp. + llvm::Constant * + emitCXXConstructorThunkIfNeeded(IRGenModule &IGM, Signature signature, + const clang::CXXConstructorDecl *ctor, + StringRef name, llvm::Constant *ctorAddress); } } diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index de2f8ebc3cda2..205e50db8adb4 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -20,9 +20,11 @@ #include "swift/AST/Decl.h" #include "swift/AST/IRGenOptions.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SemanticAttrs.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/Types.h" #include "swift/IRGen/Linking.h" +#include "swift/SIL/SILFunctionBuilder.h" #include "swift/SIL/SILModule.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" @@ -36,6 +38,7 @@ #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" +#include "GenDecl.h" #include "GenMeta.h" #include "GenRecord.h" #include "GenType.h" @@ -43,10 +46,11 @@ #include "IRGenModule.h" #include "IndirectTypeInfo.h" #include "MemberAccessStrategy.h" +#include "MetadataLayout.h" #include "NonFixedTypeInfo.h" #include "ResilientTypeInfo.h" +#include "Signature.h" #include "StructMetadataVisitor.h" -#include "MetadataLayout.h" #pragma clang diagnostic ignored "-Winconsistent-missing-override" @@ -326,6 +330,7 @@ namespace { public StructTypeInfoBase { const clang::RecordDecl *ClangDecl; + public: LoadableClangRecordTypeInfo(ArrayRef fields, unsigned explosionSize, @@ -374,6 +379,73 @@ namespace { ClangFieldInfo> { const clang::RecordDecl *ClangDecl; + const clang::CXXConstructorDecl *findCopyConstructor() const { + const clang::CXXRecordDecl *cxxRecordDecl = + dyn_cast(ClangDecl); + if (!cxxRecordDecl) + return nullptr; + for (auto method : cxxRecordDecl->methods()) { + if (auto ctor = dyn_cast(method)) { + if (ctor->isCopyConstructor()) + return ctor; + } + } + return nullptr; + } + + CanSILFunctionType createCXXCopyConstructorFunctionType(IRGenFunction &IGF, + SILType T) const { + // Create the following function type: + // @convention(c) (UnsafePointer) -> @out T + // This is how clang *would* import the copy constructor. So, later, when + // we pass it to "emitCXXConstructorThunkIfNeeded" we get a thunk with + // the following LLVM function type: + // void (%struct.T* %this, %struct.T* %0) + auto ptrTypeDecl = + IGF.getSILModule().getASTContext().getUnsafePointerDecl(); + auto subst = SubstitutionMap::get(ptrTypeDecl->getGenericSignature(), + {T.getASTType()}, + ArrayRef{}); + auto ptrType = ptrTypeDecl->getDeclaredInterfaceType().subst(subst); + SILParameterInfo ptrParam(ptrType->getCanonicalType(), + ParameterConvention::Direct_Unowned); + SILResultInfo result(T.getASTType(), ResultConvention::Indirect); + + return SILFunctionType::get( + GenericSignature(), + SILFunctionType::ExtInfo().withRepresentation( + SILFunctionTypeRepresentation::CFunctionPointer), + SILCoroutineKind::None, + /*callee=*/ParameterConvention::Direct_Unowned, + /*params*/ {ptrParam}, + /*yields*/ {}, /*results*/ {result}, + /*error*/ None, + /*pattern subs*/ SubstitutionMap(), + /*invocation subs*/ SubstitutionMap(), IGF.IGM.Context); + } + + void emitCopyWithCopyConstructor( + IRGenFunction &IGF, SILType T, + const clang::CXXConstructorDecl *copyConstructor, llvm::Value *src, + llvm::Value *dest) const { + auto fnType = createCXXCopyConstructorFunctionType(IGF, T); + auto globalDecl = + clang::GlobalDecl(copyConstructor, clang::Ctor_Complete); + auto clangFnAddr = + IGF.IGM.getAddrOfClangGlobalDecl(globalDecl, NotForDefinition); + auto callee = cast(clangFnAddr->stripPointerCasts()); + Signature signature = IGF.IGM.getSignature(fnType); + std::string name = "__swift_cxx_copy_ctor" + callee->getName().str(); + clangFnAddr = emitCXXConstructorThunkIfNeeded( + IGF.IGM, signature, copyConstructor, name, clangFnAddr); + callee = cast(clangFnAddr); + dest = IGF.coerceValue(dest, callee->getFunctionType()->getParamType(0), + IGF.IGM.DataLayout); + src = IGF.coerceValue(src, callee->getFunctionType()->getParamType(1), + IGF.IGM.DataLayout); + IGF.Builder.CreateCall(callee, {dest, src}); + } + public: AddressOnlyClangRecordTypeInfo(ArrayRef fields, llvm::Type *storageType, Size size, @@ -451,6 +523,21 @@ namespace { "member functions."); } + void initializeWithCopy(IRGenFunction &IGF, Address destAddr, + Address srcAddr, SILType T, + bool isOutlined) const override { + if (auto copyConstructor = findCopyConstructor()) { + emitCopyWithCopyConstructor(IGF, T, copyConstructor, + srcAddr.getAddress(), + destAddr.getAddress()); + return; + } + StructTypeInfoBase::initializeWithCopy(IGF, destAddr, + srcAddr, T, + isOutlined); + } + llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF) const { return None; } llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF, SILType T) const { return None; diff --git a/stdlib/public/SwiftShims/RefCount.h b/stdlib/public/SwiftShims/RefCount.h index 5c8211f5e9fe1..5499de8d56299 100644 --- a/stdlib/public/SwiftShims/RefCount.h +++ b/stdlib/public/SwiftShims/RefCount.h @@ -18,7 +18,7 @@ // This definition is a placeholder for importing into Swift. // It provides size and alignment but cannot be manipulated safely there. typedef struct { - __swift_uintptr_t refCounts SWIFT_ATTRIBUTE_UNAVAILABLE; + __swift_uintptr_t refCounts; } InlineRefCountsPlaceholder; #if defined(__swift__) diff --git a/test/Interop/Cxx/class/Inputs/constructors.h b/test/Interop/Cxx/class/Inputs/constructors.h index 5602941aa11fb..a21f75dea1010 100644 --- a/test/Interop/Cxx/class/Inputs/constructors.h +++ b/test/Interop/Cxx/class/Inputs/constructors.h @@ -63,6 +63,17 @@ struct TemplatedConstructorWithExtraArg { TemplatedConstructorWithExtraArg(T value, U other) { } }; +struct HasUserProvidedCopyConstructor { + int numCopies; + HasUserProvidedCopyConstructor(int numCopies = 0) : numCopies(numCopies) {} + HasUserProvidedCopyConstructor(const HasUserProvidedCopyConstructor &other) + : numCopies(other.numCopies + 1) {} +}; + +struct DeletedCopyConstructor { + DeletedCopyConstructor(const DeletedCopyConstructor &) = delete; +}; + // TODO: we should be able to import this constructor correctly. Until we can, // make sure not to crash. struct UsingBaseConstructor : ConstructorWithParam { diff --git a/test/Interop/Cxx/class/constructors-copy-irgen.swift b/test/Interop/Cxx/class/constructors-copy-irgen.swift new file mode 100644 index 0000000000000..a0686ea021c72 --- /dev/null +++ b/test/Interop/Cxx/class/constructors-copy-irgen.swift @@ -0,0 +1,47 @@ +// Target-specific tests for C++ copy constructor code generation. + +// RUN: %swift -module-name Swift -target x86_64-apple-macosx10.9 -dump-clang-diagnostics -I %S/Inputs -enable-cxx-interop -emit-ir %s -parse-stdlib -parse-as-library -disable-legacy-type-info | %FileCheck %s -check-prefix=ITANIUM_X64 +// RUN: %swift -module-name Swift -target armv7-none-linux-androideabi -dump-clang-diagnostics -I %S/Inputs -enable-cxx-interop -emit-ir %s -parse-stdlib -parse-as-library -disable-legacy-type-info | %FileCheck %s -check-prefix=ITANIUM_ARM +// RUN: %swift -module-name Swift -target x86_64-unknown-windows-msvc -dump-clang-diagnostics -I %S/Inputs -enable-cxx-interop -emit-ir %s -parse-stdlib -parse-as-library -disable-legacy-type-info | %FileCheck %s -check-prefix=MICROSOFT_X64 + +import Constructors +import TypeClassification + +typealias Void = () +struct UnsafePointer { } +struct UnsafeMutablePointer { } + +// ITANIUM_X64-LABEL: define swiftcc void @"$ss35copyWithUserProvidedCopyConstructorySo03HascdeF0V_ACtACF" +// ITANIUM_X64-SAME: (%TSo30HasUserProvidedCopyConstructorV* {{.*}}[[ARG0:%.*]], %TSo30HasUserProvidedCopyConstructorV* {{.*}}[[ARG1:%.*]], %TSo30HasUserProvidedCopyConstructorV* {{.*}}[[ARG2:%.*]]) +// ITANIUM_X64: [[ARG0_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG0]] to %struct.HasUserProvidedCopyConstructor* +// ITANIUM_X64: [[ARG2_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG2]] to %struct.HasUserProvidedCopyConstructor* +// ITANIUM_X64: call void @_ZN30HasUserProvidedCopyConstructorC1ERKS_(%struct.HasUserProvidedCopyConstructor* [[ARG0_AS_STRUCT]], %struct.HasUserProvidedCopyConstructor* [[ARG2_AS_STRUCT]]) +// ITANIUM_X64: [[ARG1_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG1]] to %struct.HasUserProvidedCopyConstructor* +// ITANIUM_X64: [[ARG2_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG2]] to %struct.HasUserProvidedCopyConstructor* +// ITANIUM_X64: call void @_ZN30HasUserProvidedCopyConstructorC1ERKS_(%struct.HasUserProvidedCopyConstructor* [[ARG1_AS_STRUCT]], %struct.HasUserProvidedCopyConstructor* [[ARG2_AS_STRUCT]]) +// ITANIUM_X64: ret void + +// ITANIUM_ARM-LABEL: define protected swiftcc void @"$ss35copyWithUserProvidedCopyConstructorySo03HascdeF0V_ACtACF" +// ITANIUM_ARM-SAME: (%TSo30HasUserProvidedCopyConstructorV* {{.*}}[[ARG0:%.*]], %TSo30HasUserProvidedCopyConstructorV* {{.*}}[[ARG1:%.*]], %TSo30HasUserProvidedCopyConstructorV* {{.*}}[[ARG2:%.*]]) +// ITANIUM_ARM: [[ARG0_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG0]] to %struct.HasUserProvidedCopyConstructor* +// ITANIUM_ARM: [[ARG2_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG2]] to %struct.HasUserProvidedCopyConstructor* +// ITANIUM_ARM: call %struct.HasUserProvidedCopyConstructor* @_ZN30HasUserProvidedCopyConstructorC2ERKS_(%struct.HasUserProvidedCopyConstructor* [[ARG0_AS_STRUCT]], %struct.HasUserProvidedCopyConstructor* [[ARG2_AS_STRUCT]]) +// ITANIUM_ARM: [[ARG1_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG1]] to %struct.HasUserProvidedCopyConstructor* +// ITANIUM_ARM: [[ARG2_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG2]] to %struct.HasUserProvidedCopyConstructor* +// ITANIUM_ARM: call %struct.HasUserProvidedCopyConstructor* @_ZN30HasUserProvidedCopyConstructorC2ERKS_(%struct.HasUserProvidedCopyConstructor* [[ARG1_AS_STRUCT]], %struct.HasUserProvidedCopyConstructor* [[ARG2_AS_STRUCT]]) +// ITANIUM_ARM: ret void + +// MICROSOFT_X64-LABEL: define dllexport swiftcc void @"$ss35copyWithUserProvidedCopyConstructorySo03HascdeF0V_ACtACF" +// MICROSOFT_X64-SAME: (%TSo30HasUserProvidedCopyConstructorV* {{.*}}[[ARG0:%.*]], %TSo30HasUserProvidedCopyConstructorV* {{.*}}[[ARG1:%.*]], %TSo30HasUserProvidedCopyConstructorV* {{.*}}[[ARG2:%.*]]) +// MICROSOFT_X64: [[ARG0_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG0]] to %struct.HasUserProvidedCopyConstructor* +// MICROSOFT_X64: [[ARG2_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG2]] to %struct.HasUserProvidedCopyConstructor* +// MICROSOFT_X64: call %struct.HasUserProvidedCopyConstructor* @"??0HasUserProvidedCopyConstructor@@QEAA@AEBU0@@Z"(%struct.HasUserProvidedCopyConstructor* [[ARG0_AS_STRUCT]], %struct.HasUserProvidedCopyConstructor* [[ARG2_AS_STRUCT]]) +// MICROSOFT_X64: [[ARG1_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG1]] to %struct.HasUserProvidedCopyConstructor* +// MICROSOFT_X64: [[ARG2_AS_STRUCT:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG2]] to %struct.HasUserProvidedCopyConstructor* +// MICROSOFT_X64: call %struct.HasUserProvidedCopyConstructor* @"??0HasUserProvidedCopyConstructor@@QEAA@AEBU0@@Z"(%struct.HasUserProvidedCopyConstructor* [[ARG1_AS_STRUCT]], %struct.HasUserProvidedCopyConstructor* [[ARG2_AS_STRUCT]]) +// MICROSOFT_X64: ret void + +public func copyWithUserProvidedCopyConstructor(_ x: HasUserProvidedCopyConstructor) + -> (HasUserProvidedCopyConstructor, HasUserProvidedCopyConstructor) { + return (x, x) +} diff --git a/test/Interop/Cxx/class/constructors-copy-module-interface.swift b/test/Interop/Cxx/class/constructors-copy-module-interface.swift new file mode 100644 index 0000000000000..5bdc58b2e2a18 --- /dev/null +++ b/test/Interop/Cxx/class/constructors-copy-module-interface.swift @@ -0,0 +1,5 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=Constructors -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// Make sure we don't import non-copyable types because we will have no way to +// represent and copy/move these in swift with correct semantics. +// CHECK-NOT: DeletedCopyConstructor diff --git a/test/Interop/Cxx/class/constructors-irgen.swift b/test/Interop/Cxx/class/constructors-irgen.swift index 6c13f75cee119..095b65960d3da 100644 --- a/test/Interop/Cxx/class/constructors-irgen.swift +++ b/test/Interop/Cxx/class/constructors-irgen.swift @@ -52,19 +52,25 @@ public func createStructWithSubobjectCopyConstructorAndValue() { // ITANIUM_X64-LABEL: define swiftcc void @"$ss48createStructWithSubobjectCopyConstructorAndValueyyF"() // ITANIUM_X64: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV // ITANIUM_X64: [[OBJ:%.*]] = alloca %TSo42StructWithSubobjectCopyConstructorAndValueV + // ITANIUM_X64: [[TMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV // ITANIUM_X64: [[MEMBER_AS_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]] to %struct.StructWithCopyConstructorAndValue* // ITANIUM_X64: void @_ZN33StructWithCopyConstructorAndValueC1Ev(%struct.StructWithCopyConstructorAndValue* [[MEMBER_AS_STRUCT]]) - // ITANIUM_X64: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOc"(%TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], %TSo33StructWithCopyConstructorAndValueV* [[TMP:%.*]]) + // ITANIUM_X64: [[TMP_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[TMP]] to %struct.StructWithCopyConstructorAndValue* + // ITANIUM_X64: [[MEMBER_AS_STRUCT_2:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]] to %struct.StructWithCopyConstructorAndValue* + // ITANIUM_X64: call void @_ZN33StructWithCopyConstructorAndValueC1ERKS_(%struct.StructWithCopyConstructorAndValue* [[TMP_STRUCT]], %struct.StructWithCopyConstructorAndValue* [[MEMBER_AS_STRUCT_2]]) // ITANIUM_X64: [[OBJ_MEMBER:%.*]] = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 // ITANIUM_X64: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOb"(%TSo33StructWithCopyConstructorAndValueV* [[TMP]], %TSo33StructWithCopyConstructorAndValueV* [[OBJ_MEMBER]]) // ITANIUM_X64: ret void - + // ITANIUM_ARM-LABEL: define protected swiftcc void @"$ss48createStructWithSubobjectCopyConstructorAndValueyyF"() // ITANIUM_ARM: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV // ITANIUM_ARM: [[OBJ:%.*]] = alloca %TSo42StructWithSubobjectCopyConstructorAndValueV + // ITANIUM_ARM: [[TMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV // ITANIUM_ARM: [[MEMBER_AS_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]] to %struct.StructWithCopyConstructorAndValue* // ITANIUM_ARM: call %struct.StructWithCopyConstructorAndValue* @_ZN33StructWithCopyConstructorAndValueC2Ev(%struct.StructWithCopyConstructorAndValue* [[MEMBER_AS_STRUCT]]) - // ITANIUM_ARM: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOc"(%TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], %TSo33StructWithCopyConstructorAndValueV* [[TMP:%.*]]) + // ITANIUM_ARM: [[TMP_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[TMP]] to %struct.StructWithCopyConstructorAndValue* + // ITANIUM_ARM: [[MEMBER_AS_STRUCT_2:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]] to %struct.StructWithCopyConstructorAndValue* + // ITANIUM_ARM: call %struct.StructWithCopyConstructorAndValue* @_ZN33StructWithCopyConstructorAndValueC2ERKS_(%struct.StructWithCopyConstructorAndValue* [[TMP_STRUCT]], %struct.StructWithCopyConstructorAndValue* [[MEMBER_AS_STRUCT_2]]) // ITANIUM_ARM: [[OBJ_MEMBER:%.*]] = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 // ITANIUM_ARM: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOb"(%TSo33StructWithCopyConstructorAndValueV* [[TMP]], %TSo33StructWithCopyConstructorAndValueV* [[OBJ_MEMBER]]) // ITANIUM_ARM: ret void @@ -72,9 +78,12 @@ public func createStructWithSubobjectCopyConstructorAndValue() { // MICROSOFT_X64-LABEL: define dllexport swiftcc void @"$ss48createStructWithSubobjectCopyConstructorAndValueyyF"() // MICROSOFT_X64: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV // MICROSOFT_X64: [[OBJ:%.*]] = alloca %TSo42StructWithSubobjectCopyConstructorAndValueV + // MICROSOFT_X64: [[TMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV // MICROSOFT_X64: [[MEMBER_AS_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]] to %struct.StructWithCopyConstructorAndValue* // MICROSOFT_X64: call %struct.StructWithCopyConstructorAndValue* @"??0StructWithCopyConstructorAndValue@@QEAA@XZ"(%struct.StructWithCopyConstructorAndValue* [[MEMBER_AS_STRUCT]]) - // MICROSOFT_X64: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOc"(%TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], %TSo33StructWithCopyConstructorAndValueV* [[TMP:%.*]]) + // MICROSOFT_X64: [[TMP_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[TMP]] to %struct.StructWithCopyConstructorAndValue* + // MICROSOFT_X64: [[MEMBER_AS_STRUCT_2:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]] to %struct.StructWithCopyConstructorAndValue* + // MICROSOFT_X64: call %struct.StructWithCopyConstructorAndValue* @"??0StructWithCopyConstructorAndValue@@QEAA@AEBU0@@Z"(%struct.StructWithCopyConstructorAndValue* [[TMP_STRUCT]], %struct.StructWithCopyConstructorAndValue* [[MEMBER_AS_STRUCT_2]]) // MICROSOFT_X64: [[OBJ_MEMBER:%.*]] = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 // MICROSOFT_X64: call %TSo33StructWithCopyConstructorAndValueV* @"$sSo33StructWithCopyConstructorAndValueVWOb"(%TSo33StructWithCopyConstructorAndValueV* [[TMP]], %TSo33StructWithCopyConstructorAndValueV* [[OBJ_MEMBER]]) // MICROSOFT_X64: ret void diff --git a/test/Interop/Cxx/class/type-classification-loadable-silgen.swift b/test/Interop/Cxx/class/type-classification-loadable-silgen.swift index c77cfdd9e47b0..c39ac1a996c07 100644 --- a/test/Interop/Cxx/class/type-classification-loadable-silgen.swift +++ b/test/Interop/Cxx/class/type-classification-loadable-silgen.swift @@ -52,21 +52,6 @@ func pass(s: StructWithSubobjectDefaultedCopyConstructor) { // CHECK: bb0(%0 : $StructWithSubobjectDefaultedCopyConstructor): } -// CHECK-LABEL: sil hidden [ossa] @$s4main4pass{{.*[ (]}}StructWithPrivateDefaultedCopyConstructor) -func pass(s: StructWithPrivateDefaultedCopyConstructor) { - // CHECK: bb0(%0 : $*StructWithPrivateDefaultedCopyConstructor): -} - -// CHECK-LABEL: sil hidden [ossa] @$s4main4pass{{.*[ (]}}StructWithInheritedPrivateDefaultedCopyConstructor) -func pass(s: StructWithInheritedPrivateDefaultedCopyConstructor) { - // CHECK: bb0(%0 : $*StructWithInheritedPrivateDefaultedCopyConstructor): -} - -// CHECK-LABEL: sil hidden [ossa] @$s4main4pass{{.*[ (]}}StructWithSubobjectPrivateDefaultedCopyConstructor) -func pass(s: StructWithSubobjectPrivateDefaultedCopyConstructor) { - // CHECK: bb0(%0 : $*StructWithSubobjectPrivateDefaultedCopyConstructor): -} - // CHECK-LABEL: sil hidden [ossa] @$s4main4pass{{.*[ (]}}StructWithMoveConstructor) func pass(s: StructWithMoveConstructor) { // CHECK: bb0(%0 : $*StructWithMoveConstructor): @@ -149,12 +134,7 @@ func pass(s: StructTriviallyCopyableMovable) { // CHECK: bb0(%0 : $StructTriviallyCopyableMovable): } -// CHECK-LABEL: sil hidden [ossa] @$s4main4pass{{.*[ (]}}StructNonCopyableTriviallyMovable) -func pass(s: StructNonCopyableTriviallyMovable) { - // CHECK: bb0(%0 : $*StructNonCopyableTriviallyMovable): -} - // CHECK-LABEL: sil hidden [ossa] @$s4main4pass{{.*[ (]}}StructNonCopyableNonMovable) func pass(s: StructNonCopyableNonMovable) { - // CHECK: bb0(%0 : $*StructNonCopyableNonMovable): + // CHECK: bb0(%0 : $StructNonCopyableNonMovable): } diff --git a/test/Interop/Cxx/class/type-classification-module-interface.swift b/test/Interop/Cxx/class/type-classification-module-interface.swift index 5945975214eeb..72dd0085d3bc9 100644 --- a/test/Interop/Cxx/class/type-classification-module-interface.swift +++ b/test/Interop/Cxx/class/type-classification-module-interface.swift @@ -1,6 +1,10 @@ // RUN: %target-swift-ide-test -print-module -module-to-print=TypeClassification -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s -// Make sure we don't import objects that we can't destroy. +// Make sure we don't import objects that we can't copy or destroy. +// CHECK-NOT: StructWithPrivateDefaultedCopyConstructor +// CHECK-NOT: StructWithInheritedPrivateDefaultedCopyConstructor +// CHECK-NOT: StructWithSubobjectPrivateDefaultedCopyConstructor +// CHECK-NOT: StructNonCopyableTriviallyMovable // CHECK-NOT: StructWithPrivateDefaultedDestructor // CHECK-NOT: StructWithInheritedPrivateDefaultedDestructor // CHECK-NOT: StructWithSubobjectPrivateDefaultedDestructor diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift index 201ea8f6d53f0..5e0c03c94b63c 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift @@ -50,8 +50,11 @@ public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { // CHECK: [[MEMBER_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]] to %struct.StructWithCopyConstructorAndValue* // CHECK: call {{.*}}@{{_ZN33StructWithCopyConstructorAndValueC(1|2)Ei|"\?\?0StructWithCopyConstructorAndValue@@QEAA@H@Z"}}(%struct.StructWithCopyConstructorAndValue* {{(noalias )?}}[[MEMBER_STRUCT]], i32 42) // CHECK: [[TEMP_AS_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[TEMP]] to %struct.StructWithCopyConstructorAndValue* -// CHECK: [[OBJ_AS_STRUCT:%.*]] = bitcast %TSo037StructWithCopyConstructorAndSubobjectcdE5ValueV* [[OBJ]] to %struct.StructWithCopyConstructorAndSubobjectCopyConstructorAndValue* -// CHECK: call {{.*}}@{{_ZN60StructWithCopyConstructorAndSubobjectCopyConstructorAndValueC(1|2)E33StructWithCopyConstructorAndValue|"\?\?0StructWithCopyConstructorAndSubobjectCopyConstructorAndValue@@QEAA@UStructWithCopyConstructorAndValue@@@Z"}}(%struct.StructWithCopyConstructorAndSubobjectCopyConstructorAndValue* {{(noalias )?}}[[OBJ_AS_STRUCT]], %struct.StructWithCopyConstructorAndValue* [[TEMP_AS_STRUCT]]) +// CHECK: [[MEMBER_AS_STRUCT:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]] to %struct.StructWithCopyConstructorAndValue* +// CHECK: call {{.*}}@{{_ZN33StructWithCopyConstructorAndValueC(1|2)ERKS_|"\?\?0StructWithCopyConstructorAndValue@@QEAA@AEBU0@@Z"}}(%struct.StructWithCopyConstructorAndValue* [[TEMP_AS_STRUCT]], %struct.StructWithCopyConstructorAndValue* [[MEMBER_AS_STRUCT]]) +// CHECK: [[TEMP_AS_STRUCT_2:%.*]] = bitcast %TSo33StructWithCopyConstructorAndValueV* [[TEMP]] to %struct.StructWithCopyConstructorAndValue* +// CHECK: [[OBJ_AS_STRUCT_2:%.*]] = bitcast %TSo037StructWithCopyConstructorAndSubobjectcdE5ValueV* [[OBJ]] to %struct.StructWithCopyConstructorAndSubobjectCopyConstructorAndValue* +// CHECK: call {{.*}}@{{_ZN60StructWithCopyConstructorAndSubobjectCopyConstructorAndValueC(1|2)E33StructWithCopyConstructorAndValue|"\?\?0StructWithCopyConstructorAndSubobjectCopyConstructorAndValue@@QEAA@UStructWithCopyConstructorAndValue@@@Z"}}(%struct.StructWithCopyConstructorAndSubobjectCopyConstructorAndValue* {{(noalias )?}}[[OBJ_AS_STRUCT_2]], %struct.StructWithCopyConstructorAndValue* [[TEMP_AS_STRUCT_2]]) // CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TEMP2]], i32 0, i32 0 // CHECK: [[TEMP_MEMBER_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[TEMP_MEMBER]], i32 0, i32 0 // CHECK: [[LHS:%.*]] = load i32, i32* [[TEMP_MEMBER_VAL]] diff --git a/test/Interop/Cxx/value-witness-table/Inputs/copy-constructors.h b/test/Interop/Cxx/value-witness-table/Inputs/copy-constructors.h new file mode 100644 index 0000000000000..a3864f6e0556d --- /dev/null +++ b/test/Interop/Cxx/value-witness-table/Inputs/copy-constructors.h @@ -0,0 +1,30 @@ +#ifndef TEST_INTEROP_CXX_VALUE_WITNESS_TABLE_INPUTS_COPY_CONSTRUCTORS_H +#define TEST_INTEROP_CXX_VALUE_WITNESS_TABLE_INPUTS_COPY_CONSTRUCTORS_H + +struct HasUserProvidedCopyConstructor { + int numCopies; + HasUserProvidedCopyConstructor(int numCopies = 0) : numCopies(numCopies) {} + HasUserProvidedCopyConstructor(const HasUserProvidedCopyConstructor &other) + : numCopies(other.numCopies + 1) {} +}; + +struct HasNonTrivialImplicitCopyConstructor { + HasUserProvidedCopyConstructor box; + HasNonTrivialImplicitCopyConstructor() + : box(HasUserProvidedCopyConstructor()) {} +}; + +struct HasNonTrivialDefaultCopyConstructor { + HasUserProvidedCopyConstructor box; + HasNonTrivialDefaultCopyConstructor() + : box(HasUserProvidedCopyConstructor()) {} + HasNonTrivialDefaultCopyConstructor( + const HasNonTrivialDefaultCopyConstructor &) = default; +}; + +// Make sure that we don't crash on struct templates with copy-constructors. +template struct S { + S(S const &) {} +}; + +#endif // TEST_INTEROP_CXX_VALUE_WITNESS_TABLE_INPUTS_COPY_CONSTRUCTORS_H diff --git a/test/Interop/Cxx/value-witness-table/Inputs/module.modulemap b/test/Interop/Cxx/value-witness-table/Inputs/module.modulemap index d1475b59aa170..30e88d4db9b35 100644 --- a/test/Interop/Cxx/value-witness-table/Inputs/module.modulemap +++ b/test/Interop/Cxx/value-witness-table/Inputs/module.modulemap @@ -7,3 +7,8 @@ module WitnessLayoutOpts { header "witness-layout-opts.h" requires cplusplus } + +module CopyConstructors { + header "copy-constructors.h" + requires cplusplus +} diff --git a/test/Interop/Cxx/value-witness-table/copy-constructors-execution.swift b/test/Interop/Cxx/value-witness-table/copy-constructors-execution.swift new file mode 100644 index 0000000000000..2d9a307cb58b1 --- /dev/null +++ b/test/Interop/Cxx/value-witness-table/copy-constructors-execution.swift @@ -0,0 +1,51 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test + +import CopyConstructors +import StdlibUnittest + +var CXXCopyConstructorTestSuite = TestSuite("CXX Copy Constructor") + +// It doesn't really matter how many copies were made (as long as it's at least +// one). What we really want to be checking is that the correct copy constructor +// was eventually called. + +CXXCopyConstructorTestSuite.test("Basic object with custom copy constructor") { + // Make sure we don't inline this function. We should copy "userCC" into the + // two tuple elements (in the return address). If we inline this function, it + // would allow Swift to put "userCC" directly into "expectTrue" which would + // eliminate the copy. + @inline(never) + func createHasUserProvidedCopyConstructor() -> (HasUserProvidedCopyConstructor, HasUserProvidedCopyConstructor) { + let userCC = HasUserProvidedCopyConstructor(0) + return (userCC, userCC) + } + + let result = createHasUserProvidedCopyConstructor() + expectTrue(result.0.numCopies + result.1.numCopies > 0) +} + +CXXCopyConstructorTestSuite.test("Implicit copy constructor, member with user-defined copy constructor") { + @inline(never) + func createTypeWithNonTrivialImplicitCopyConstructor() -> (HasNonTrivialImplicitCopyConstructor, HasNonTrivialImplicitCopyConstructor) { + let implicit = HasNonTrivialImplicitCopyConstructor() + return (implicit, implicit) + } + + let result = createTypeWithNonTrivialImplicitCopyConstructor() + expectTrue(result.0.box.numCopies + result.1.box.numCopies > 0) +} + +CXXCopyConstructorTestSuite.test("Default copy constructor, member with user-defined copy constructor") { + @inline(never) + func createTypeWithNonTrivialDefaultCopyConstructor() -> (HasNonTrivialDefaultCopyConstructor, HasNonTrivialDefaultCopyConstructor) { + let def = HasNonTrivialDefaultCopyConstructor() + return (def, def) + } + + let result = createTypeWithNonTrivialDefaultCopyConstructor() + expectTrue(result.0.box.numCopies + result.1.box.numCopies > 0) +} + +runAllTests() diff --git a/test/Interop/Cxx/value-witness-table/copy-constructors-irgen.swift b/test/Interop/Cxx/value-witness-table/copy-constructors-irgen.swift new file mode 100644 index 0000000000000..cdfbc80fda533 --- /dev/null +++ b/test/Interop/Cxx/value-witness-table/copy-constructors-irgen.swift @@ -0,0 +1,45 @@ +// RUN: %target-swift-frontend -enable-cxx-interop -I %S/Inputs %s -emit-ir | %FileCheck %s + +// REQUIRES: CPU=x86_64 +// REQUIRES: objc_interop + +import CopyConstructors + +// CHECK-LABEL: define swiftcc void @"$s4main31testUserProvidedCopyConstructor3objSo03HascdeF0V_AEtAE_tF" +// CHECK: [[T0_DEST:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG0:%[0-9]+]] to %struct.HasUserProvidedCopyConstructor* +// CHECK: [[T0_SRC:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG2:%[0-9]+]] to %struct.HasUserProvidedCopyConstructor* +// CHECK: call void @_ZN30HasUserProvidedCopyConstructorC1ERKS_(%struct.HasUserProvidedCopyConstructor* [[T0_DEST]], %struct.HasUserProvidedCopyConstructor* [[T0_SRC]]) +// CHECK: [[T1_DEST:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG1:%[0-9]+]] to %struct.HasUserProvidedCopyConstructor* +// CHECK: [[T1_SRC:%.*]] = bitcast %TSo30HasUserProvidedCopyConstructorV* [[ARG2]] to %struct.HasUserProvidedCopyConstructor* +// CHECK: call void @_ZN30HasUserProvidedCopyConstructorC1ERKS_(%struct.HasUserProvidedCopyConstructor* [[T1_DEST]], %struct.HasUserProvidedCopyConstructor* [[T1_SRC]]) +// CHECK: ret void + +// CHECK-LABEL: define linkonce_odr void @_ZN30HasUserProvidedCopyConstructorC1ERKS_ + +public func testUserProvidedCopyConstructor(obj : HasUserProvidedCopyConstructor) -> (HasUserProvidedCopyConstructor, HasUserProvidedCopyConstructor) { + return (obj, obj) +} + +// CHECK-LABEL: define swiftcc void @"$s4main26testDefaultCopyConstructor3defSo013HasNonTrivialcdE0V_AEtAE_tF" +// CHECK: call void @_ZN35HasNonTrivialDefaultCopyConstructorC1ERKS_ +// CHECK: call void @_ZN35HasNonTrivialDefaultCopyConstructorC1ERKS_ + +// Make sure we call the copy constructor of our member (HasUserProvidedCopyConstructor) +// CHECK-LABEL: define linkonce_odr void @_ZN35HasNonTrivialDefaultCopyConstructorC1ERKS_ +// CHECK: call void @_ZN35HasNonTrivialDefaultCopyConstructorC2ERKS_ + +public func testDefaultCopyConstructor(def : HasNonTrivialDefaultCopyConstructor) -> (HasNonTrivialDefaultCopyConstructor, HasNonTrivialDefaultCopyConstructor) { + return (def, def) +} + +// CHECK-LABEL: define swiftcc void @"$s4main27testImplicitCopyConstructor3impSo013HasNonTrivialcdE0V_AEtAE_tF" +// CHECK: call void @_ZN36HasNonTrivialImplicitCopyConstructorC1ERKS_ +// CHECK: call void @_ZN36HasNonTrivialImplicitCopyConstructorC1ERKS_ + +// Same as above. +// CHECK-LABEL: define linkonce_odr void @_ZN36HasNonTrivialImplicitCopyConstructorC1ERKS_ +// CHECK: call void @_ZN36HasNonTrivialImplicitCopyConstructorC2ERKS_ + +public func testImplicitCopyConstructor(imp : HasNonTrivialImplicitCopyConstructor) -> (HasNonTrivialImplicitCopyConstructor, HasNonTrivialImplicitCopyConstructor) { + return (imp, imp) +}