Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -6509,6 +6509,13 @@ class ConstructorDecl : public AbstractFunctionDecl {
GenericParamList *GenericParams,
DeclContext *Parent);

static ConstructorDecl *
createImported(ASTContext &ctx, ClangNode clangNode, DeclName name,
SourceLoc constructorLoc, bool failable,
SourceLoc failabilityLoc, bool throws, SourceLoc throwsLoc,
ParameterList *bodyParams, GenericParamList *genericParams,
DeclContext *parent);

SourceLoc getConstructorLoc() const { return getNameLoc(); }
SourceLoc getStartLoc() const { return getConstructorLoc(); }
SourceRange getSourceRange() const;
Expand Down
14 changes: 14 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7524,6 +7524,20 @@ ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc,
assert(Name.getBaseName() == DeclBaseName::createConstructor());
}

ConstructorDecl *ConstructorDecl::createImported(
ASTContext &ctx, ClangNode clangNode, DeclName name,
SourceLoc constructorLoc, bool failable, SourceLoc failabilityLoc,
bool throws, SourceLoc throwsLoc, ParameterList *bodyParams,
GenericParamList *genericParams, DeclContext *parent) {
void *declPtr = allocateMemoryForDecl<ConstructorDecl>(
ctx, sizeof(ConstructorDecl), true);
auto ctor = ::new (declPtr)
ConstructorDecl(name, constructorLoc, failable, failabilityLoc, throws,
throwsLoc, bodyParams, genericParams, parent);
ctor->setClangNode(clangNode);
return ctor;
}

bool ConstructorDecl::isObjCZeroParameterWithLongSelector() const {
// The initializer must have a single, non-empty argument name.
if (getName().getArgumentNames().size() != 1 ||
Expand Down
25 changes: 21 additions & 4 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,19 @@ Solution::computeSubstitutions(GenericSignature sig,
}

static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
ASTContext &ctx, FuncDecl *oldDecl, SubstitutionMap subst,
ASTContext &ctx, AbstractFunctionDecl *oldDecl, SubstitutionMap subst,
clang::FunctionDecl *specialized) {
// Create a new ParameterList with the substituted type.
auto oldFnType =
cast<GenericFunctionType>(oldDecl->getInterfaceType().getPointer());
auto newFnType = oldFnType->substGenericArgs(subst);
// The constructor type is a function type as follows:
// (CType.Type) -> (Generic) -> CType
// But we only want the result of that function type because that is the
// function type with the generic params that need to be substituted:
// (Generic) -> CType
if (isa<ConstructorDecl>(oldDecl))
newFnType = cast<FunctionType>(newFnType->getResult().getPointer());
SmallVector<ParamDecl *, 4> newParams;
unsigned i = 0;
for (auto paramTy : newFnType->getParams()) {
Expand All @@ -126,6 +133,16 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
auto *newParamList =
ParameterList::create(ctx, SourceLoc(), newParams, SourceLoc());

if (isa<ConstructorDecl>(oldDecl)) {
DeclName ctorName(ctx, DeclBaseName::createConstructor(), newParamList);
auto newCtorDecl = ConstructorDecl::createImported(
ctx, specialized, ctorName, oldDecl->getLoc(), /*failable=*/false,
/*failabilityLoc=*/SourceLoc(), /*throws=*/false,
/*throwsLoc=*/SourceLoc(), newParamList, /*genericParams=*/nullptr,
oldDecl->getDeclContext());
return ConcreteDeclRef(newCtorDecl);
}

// Generate a name for the specialized function.
std::string newNameStr;
llvm::raw_string_ostream buffer(newNameStr);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@varungandhi-apple because I added a special case for constructor decls, we don't need to use getMangledName. So, thanks for telling me to wait in #34389.

Expand All @@ -139,8 +156,8 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(

auto newFnDecl = FuncDecl::createImported(
ctx, oldDecl->getLoc(), newName, oldDecl->getNameLoc(),
/*Async*/ false, oldDecl->hasThrows(), newParamList,
newFnType->getResult(), /*GenericParams*/ nullptr,
/*Async=*/false, oldDecl->hasThrows(), newParamList,
newFnType->getResult(), /*GenericParams=*/nullptr,
oldDecl->getDeclContext(), specialized);
return ConcreteDeclRef(newFnDecl);
}
Expand Down Expand Up @@ -168,7 +185,7 @@ Solution::resolveConcreteDeclRef(ValueDecl *decl,
cast<clang::FunctionTemplateDecl>(decl->getClangDecl())),
subst);
return generateDeclRefForSpecializedCXXFunctionTemplate(
decl->getASTContext(), cast<FuncDecl>(decl), subst, newFn);
decl->getASTContext(), cast<AbstractFunctionDecl>(decl), subst, newFn);
}

return ConcreteDeclRef(decl, subst);
Expand Down
16 changes: 16 additions & 0 deletions test/Interop/Cxx/class/Inputs/constructors.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,22 @@ struct IntWrapper {
int x;
};

struct TemplatedConstructor {
ArgType value;

template<class T>
TemplatedConstructor(T value) : value(value) { }
};

struct TemplatedConstructorWithExtraArg {
template<class T>
TemplatedConstructorWithExtraArg(int, T value) { }
template<class T>
TemplatedConstructorWithExtraArg(T value, int) { }
template<class T, class U>
TemplatedConstructorWithExtraArg(T value, U other) { }
};

// TODO: we should be able to import this constructor correctly. Until we can,
// make sure not to crash.
struct UsingBaseConstructor : ConstructorWithParam {
Expand Down
7 changes: 7 additions & 0 deletions test/Interop/Cxx/class/constructors-executable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,11 @@ CxxConstructorTestSuite.test("ConstructorWithParam") {
expectEqual(44, instance.x)
}

CxxConstructorTestSuite.test("TemplatedConstructor") {
let arg = ArgType(i: 2)
let instance = TemplatedConstructor(arg)

expectEqual(2, instance.value.i)
}

runAllTests()
30 changes: 30 additions & 0 deletions test/Interop/Cxx/class/constructors-irgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,33 @@ public func createStructWithSubobjectCopyConstructorAndValue() {
let member = StructWithCopyConstructorAndValue()
let obj = StructWithSubobjectCopyConstructorAndValue(member: member)
}

public func createTemplatedConstructor() {
// ITANIUM_X64-LABEL: define swiftcc void @"$ss26createTemplatedConstructoryyF"()
// ITANIUM_X64: [[OBJ:%.*]] = alloca %TSo20TemplatedConstructorV
// ITANIUM_X64: [[IVAL:%.*]] = load i32, i32*
// ITANIUM_X64: [[OBJ_AS_STRUCT:%.*]] = bitcast %TSo20TemplatedConstructorV* [[OBJ]] to %struct.TemplatedConstructor*
// ITANIUM_X64: call void @_ZN20TemplatedConstructorC1I7ArgTypeEET_(%struct.TemplatedConstructor* [[OBJ_AS_STRUCT]], i32 [[IVAL]])
// ITANIUM_X64: ret void

// ITANIUM_X64-LABEL: define linkonce_odr void @_ZN20TemplatedConstructorC1I7ArgTypeEET_(%struct.TemplatedConstructor* %this, i32 %value.coerce)

// ITANIUM_ARM-LABEL: define protected swiftcc void @"$ss26createTemplatedConstructoryyF"()
// ITANIUM_ARM: [[OBJ:%.*]] = alloca %TSo20TemplatedConstructorV
// ITANIUM_ARM: [[IVAL:%.*]] = load [1 x i32], [1 x i32]*
// ITANIUM_ARM: [[OBJ_AS_STRUCT:%.*]] = bitcast %TSo20TemplatedConstructorV* [[OBJ]] to %struct.TemplatedConstructor*
// ITANIUM_ARM: call %struct.TemplatedConstructor* @_ZN20TemplatedConstructorC2I7ArgTypeEET_(%struct.TemplatedConstructor* [[OBJ_AS_STRUCT]], [1 x i32] [[IVAL]])
// ITANIUM_ARM: ret void

// ITANIUM_ARM-LABEL: define linkonce_odr %struct.TemplatedConstructor* @_ZN20TemplatedConstructorC2I7ArgTypeEET_(%struct.TemplatedConstructor* returned %this, [1 x i32] %value.coerce)

// MICROSOFT_X64-LABEL: define dllexport swiftcc void @"$ss26createTemplatedConstructoryyF"()
// MICROSOFT_X64: [[OBJ:%.*]] = alloca %TSo20TemplatedConstructorV
// MICROSOFT_X64: [[IVAL:%.*]] = load i32, i32*
// MICROSOFT_X64: [[OBJ_AS_STRUCT:%.*]] = bitcast %TSo20TemplatedConstructorV* [[OBJ]] to %struct.TemplatedConstructor*
// MICROSOFT_X64: call %struct.TemplatedConstructor* @"??$?0UArgType@@@TemplatedConstructor@@QEAA@UArgType@@@Z"(%struct.TemplatedConstructor* [[OBJ_AS_STRUCT]], i32 [[IVAL]])
// MICROSOFT_X64: ret void

// MICROSOFT_X64-LABEL: define linkonce_odr dso_local %struct.TemplatedConstructor* @"??$?0UArgType@@@TemplatedConstructor@@QEAA@UArgType@@@Z"(%struct.TemplatedConstructor* returned %this, i32 %value.coerce)
let templated = TemplatedConstructor(ArgType())
}
9 changes: 9 additions & 0 deletions test/Interop/Cxx/class/constructors-module-interface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,12 @@
// CHECK-NEXT: var i: Int32
// CHECK-NEXT: init(_ Arg: ArgType)
// CHECK-NEXT: }
// CHECK: struct TemplatedConstructor {
// CHECK-NEXT: var value: ArgType
// CHECK-NEXT: init<T>(_ value: T)
// CHECK-NEXT: }
// CHECK: struct TemplatedConstructorWithExtraArg {
// CHECK-NEXT: init<T>(_: Int32, _ value: T)
// CHECK-NEXT: init<T>(_ value: T, _: Int32)
// CHECK-NEXT: init<T, U>(_ value: T, _ other: U)
// CHECK-NEXT: }
13 changes: 13 additions & 0 deletions test/Interop/Cxx/class/constructors-silgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,16 @@ public func singleMemberTypeValueInit() {
public func deletedConstructor(a: UnsafeMutablePointer<Int32>) {
let deletedExplicitly = DefaultConstructorDeleted(a: a)
}

// CHECK-LABEL: sil [ossa] @$s4main20templatedConstructoryyF : $@convention(thin) () -> ()
// CHECK: [[TEMPL:%.*]] = alloc_stack $TemplatedConstructor
// CHECK: [[ARG:%.*]] = alloc_stack $ArgType
// CHECK: [[ARG_VAL:%.*]] = load [trivial] [[ARG]] : $*ArgType
// CHECK: [[FN:%.*]] = function_ref @{{_ZN20TemplatedConstructorC1I7ArgTypeEET_|\?\?\$\?0UArgType@@@TemplatedConstructor@@QEAA@UArgType@@@Z}} : $@convention(c) (ArgType) -> @out TemplatedConstructor
// CHECK: apply [[FN]]([[TEMPL]], [[ARG_VAL]]) : $@convention(c) (ArgType) -> @out TemplatedConstructor
// CHECK-LABEL: end sil function '$s4main20templatedConstructoryyF'

// CHECK-LABEL: sil hidden_external [clang TemplatedConstructor.init] @{{_ZN20TemplatedConstructorC1I7ArgTypeEET_|\?\?\$\?0UArgType@@@TemplatedConstructor@@QEAA@UArgType@@@Z}} : $@convention(c) (ArgType) -> @out TemplatedConstructor
public func templatedConstructor() {
let templated = TemplatedConstructor(ArgType())
}