Skip to content

Commit 9cc5d12

Browse files
authored
Merge pull request #41363 from apple/revert-41217-cleanup-and-fixes-for-function-templates
Revert "[cxx-interop] A few cleanups and fixes for function templates."
2 parents 0f036ae + 5de0963 commit 9cc5d12

13 files changed

+117
-122
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4672,7 +4672,8 @@ clang::FunctionDecl *ClangImporter::instantiateCXXFunctionTemplate(
46724672
ctx.Diags.diagnose(SourceLoc(),
46734673
diag::unable_to_convert_generic_swift_types.ID,
46744674
{func->getName(), StringRef(failedTypesStr)});
4675-
return nullptr;
4675+
// Return a valid FunctionDecl but, we'll never use it.
4676+
return func->getAsFunction();
46764677
}
46774678

46784679
// Instanciate a specialization of this template using the substitution map.

lib/ClangImporter/ImportType.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1945,7 +1945,7 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
19451945
Type swiftParamTy;
19461946
bool isParamTypeImplicitlyUnwrapped = false;
19471947
bool isInOut = false;
1948-
if (isa<clang::PointerType>(paramTy) &&
1948+
if ((isa<clang::ReferenceType>(paramTy) || isa<clang::PointerType>(paramTy)) &&
19491949
isa<clang::TemplateTypeParmType>(paramTy->getPointeeType())) {
19501950
auto pointeeType = paramTy->getPointeeType();
19511951
auto templateParamType = cast<clang::TemplateTypeParmType>(pointeeType);
@@ -1957,13 +1957,6 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
19571957
swiftParamTy = genericType->wrapInPointer(pointerKind);
19581958
if (!swiftParamTy)
19591959
return nullptr;
1960-
} else if (isa<clang::ReferenceType>(paramTy) &&
1961-
isa<clang::TemplateTypeParmType>(paramTy->getPointeeType())) {
1962-
auto templateParamType =
1963-
cast<clang::TemplateTypeParmType>(paramTy->getPointeeType());
1964-
swiftParamTy =
1965-
findGenericTypeInGenericDecls(templateParamType, genericParams);
1966-
isInOut = true;
19671960
} else if (auto *templateParamType =
19681961
dyn_cast<clang::TemplateTypeParmType>(paramTy)) {
19691962
swiftParamTy =

lib/Sema/CSApply.cpp

Lines changed: 62 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,65 @@ substituteFunctionTypeAndParamList(ASTContext &ctx, AbstractFunctionDecl *fdecl,
149149
return {newFnType, newParamList};
150150
}
151151

152+
static ValueDecl *generateSpecializedCXXFunctionTemplate(
153+
ASTContext &ctx, AbstractFunctionDecl *oldDecl, SubstitutionMap subst,
154+
clang::FunctionDecl *specialized) {
155+
auto newFnTypeAndParams = substituteFunctionTypeAndParamList(ctx, oldDecl, subst);
156+
auto newFnType = newFnTypeAndParams.first;
157+
auto paramList = newFnTypeAndParams.second;
158+
159+
SmallVector<ParamDecl *, 4> newParamsWithoutMetatypes;
160+
for (auto param : *paramList ) {
161+
if (isa<FuncDecl>(oldDecl) &&
162+
isa<MetatypeType>(param->getType().getPointer())) {
163+
// Metatype parameters are added synthetically to account for template
164+
// params that don't make it to the function signature. These shouldn't
165+
// exist in the resulting specialized FuncDecl. Note that this doesn't
166+
// affect constructors because all template params for a constructor
167+
// must be in the function signature by design.
168+
continue;
169+
}
170+
newParamsWithoutMetatypes.push_back(param);
171+
}
172+
auto *newParamList =
173+
ParameterList::create(ctx, SourceLoc(), newParamsWithoutMetatypes, SourceLoc());
174+
175+
if (isa<ConstructorDecl>(oldDecl)) {
176+
DeclName ctorName(ctx, DeclBaseName::createConstructor(), newParamList);
177+
auto newCtorDecl = ConstructorDecl::createImported(
178+
ctx, specialized, ctorName, oldDecl->getLoc(),
179+
/*failable=*/false, /*failabilityLoc=*/SourceLoc(),
180+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
181+
/*throws=*/false, /*throwsLoc=*/SourceLoc(),
182+
newParamList, /*genericParams=*/nullptr,
183+
oldDecl->getDeclContext());
184+
return newCtorDecl;
185+
}
186+
187+
// Generate a name for the specialized function.
188+
std::string newNameStr;
189+
llvm::raw_string_ostream buffer(newNameStr);
190+
std::unique_ptr<clang::MangleContext> mangler(
191+
specialized->getASTContext().createMangleContext());
192+
mangler->mangleName(specialized, buffer);
193+
buffer.flush();
194+
// Add all parameters as empty parameters.
195+
auto newName = DeclName(
196+
ctx, DeclName(ctx.getIdentifier(newNameStr)).getBaseName(), newParamList);
197+
198+
auto newFnDecl = FuncDecl::createImported(
199+
ctx, oldDecl->getLoc(), newName, oldDecl->getNameLoc(),
200+
/*Async=*/false, oldDecl->hasThrows(), newParamList,
201+
newFnType->getResult(), /*GenericParams=*/nullptr,
202+
oldDecl->getDeclContext(), specialized);
203+
if (oldDecl->isStatic()) {
204+
newFnDecl->setStatic();
205+
newFnDecl->setImportAsStaticMember();
206+
}
207+
newFnDecl->setSelfAccessKind(cast<FuncDecl>(oldDecl)->getSelfAccessKind());
208+
return newFnDecl;
209+
}
210+
152211
// Synthesizes the body of a thunk that takes extra metatype arguments and
153212
// skips over them to forward them along to the FuncDecl contained by context.
154213
// This is used when importing a C++ templated function where the template params
@@ -226,91 +285,8 @@ Solution::resolveConcreteDeclRef(ValueDecl *decl,
226285
const_cast<clang::FunctionTemplateDecl *>(
227286
cast<clang::FunctionTemplateDecl>(decl->getClangDecl())),
228287
subst);
229-
// We failed to specialize this function template. The compiler is going to
230-
// exit soon. Return something valid in the meantime.
231-
if (!newFn)
232-
return ConcreteDeclRef(decl);
233-
234-
auto newDecl = cast_or_null<ValueDecl>(
235-
decl->getASTContext().getClangModuleLoader()->importDeclDirectly(
236-
newFn));
237-
238-
if (auto fn = dyn_cast<AbstractFunctionDecl>(newDecl)) {
239-
// On Windows x86-64 we have to hack around the fact that
240-
// Int -> long long -> Int64. So we re-write the parameters mapping
241-
// Int64 -> Int.
242-
auto triple = decl->getASTContext().LangOpts.Target;
243-
if (triple.isOSWindows() && triple.isArch64Bit() &&
244-
!triple.isWindowsCygwinEnvironment() &&
245-
// Make sure we're substituting in at least one Int or UInt
246-
// (technically not necessary).
247-
llvm::any_of(subst.getReplacementTypes(), [](Type t) {
248-
return t->isEqual(t->getASTContext().getIntType()) ||
249-
t->isEqual(t->getASTContext().getUIntType());
250-
})) {
251-
auto originalFnSubst = cast<AbstractFunctionDecl>(decl)
252-
->getInterfaceType()
253-
->getAs<GenericFunctionType>()
254-
->substGenericArgs(subst);
255-
// The constructor type is a function type as follows:
256-
// (CType.Type) -> (Generic) -> CType
257-
// And a method's function type is as follows:
258-
// (inout CType) -> (Generic) -> Void
259-
// In either case, we only want the result of that function type because that
260-
// is the function type with the generic params that need to be substituted:
261-
// (Generic) -> CType
262-
if (isa<ConstructorDecl>(decl) || decl->isInstanceMember() ||
263-
decl->isStatic())
264-
originalFnSubst = cast<FunctionType>(originalFnSubst->getResult().getPointer());
265-
266-
SmallVector<ParamDecl *, 4> fixedParameters;
267-
unsigned parameterIndex = 0;
268-
for (auto *newFnParam : *fn->getParameters()) {
269-
// If the user substituted this param with an (U)Int, use (U)Int.
270-
auto substParamType =
271-
originalFnSubst->getParams()[parameterIndex].getParameterType();
272-
if (substParamType->isEqual(fn->getASTContext().getIntType()) ||
273-
substParamType->isEqual(fn->getASTContext().getUIntType())) {
274-
auto intParam =
275-
ParamDecl::cloneWithoutType(fn->getASTContext(), newFnParam);
276-
intParam->setInterfaceType(substParamType);
277-
fixedParameters.push_back(intParam);
278-
} else {
279-
fixedParameters.push_back(newFnParam);
280-
}
281-
parameterIndex++;
282-
}
283-
284-
auto fixedParams =
285-
ParameterList::create(fn->getASTContext(), fixedParameters);
286-
fn->setParameters(fixedParams);
287-
288-
// Now fix the result type:
289-
if (originalFnSubst->getResult()->isEqual(
290-
fn->getASTContext().getIntType()) ||
291-
originalFnSubst->getResult()->isEqual(
292-
fn->getASTContext().getUIntType())) {
293-
// Constructors don't have a result.
294-
if (auto func = dyn_cast<FuncDecl>(fn)) {
295-
// We have to rebuild the whole function.
296-
auto newFnDecl = FuncDecl::createImported(
297-
func->getASTContext(), func->getNameLoc(),
298-
func->getName(), func->getNameLoc(),
299-
func->hasAsync(), func->hasThrows(),
300-
fixedParams, originalFnSubst->getResult(),
301-
/*genericParams=*/nullptr, func->getDeclContext(), newFn);
302-
if (func->isStatic()) newFnDecl->setStatic();
303-
if (func->isImportAsStaticMember()) newFnDecl->setImportAsStaticMember();
304-
if (!func->getDeclContext()->isModuleScopeContext()) {
305-
newFnDecl->setSelfAccessKind(func->getSelfAccessKind());
306-
newFnDecl->setSelfIndex(func->getSelfIndex());
307-
}
308-
newDecl = newFnDecl;
309-
}
310-
}
311-
}
312-
}
313-
288+
auto newDecl = generateSpecializedCXXFunctionTemplate(
289+
decl->getASTContext(), cast<AbstractFunctionDecl>(decl), subst, newFn);
314290
if (auto fn = dyn_cast<FuncDecl>(decl)) {
315291
if (newFn->getNumParams() != fn->getParameters()->size()) {
316292
// We added additional metatype parameters to aid template
@@ -328,10 +304,9 @@ Solution::resolveConcreteDeclRef(ValueDecl *decl,
328304
thunk->setBodySynthesizer(synthesizeForwardingThunkBody, cast<FuncDecl>(newDecl));
329305
thunk->setSelfAccessKind(fn->getSelfAccessKind());
330306

331-
newDecl = thunk;
307+
return ConcreteDeclRef(thunk);
332308
}
333309
}
334-
335310
return ConcreteDeclRef(newDecl);
336311
}
337312

test/Interop/Cxx/class/constructors-irgen.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ typealias Void = ()
1111
struct UnsafePointer<T> { }
1212
struct UnsafeMutablePointer<T> { }
1313

14-
struct Int { }
15-
struct UInt { }
16-
1714
public func createHasVirtualBase() -> HasVirtualBase {
1815
// ITANIUM_X64: define swiftcc void @"$ss20createHasVirtualBaseSo0bcD0VyF"(%TSo14HasVirtualBaseV* noalias nocapture sret({{.*}}) %0)
1916
// ITANIUM_X64-NOT: define

test/Interop/Cxx/class/constructors-silgen.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public func deletedConstructor(a: UnsafeMutablePointer<Int32>) {
6565
// CHECK: apply [[FN]]([[TEMPL]], [[ARG_VAL]]) : $@convention(c) (ArgType) -> @out TemplatedConstructor
6666
// CHECK-LABEL: end sil function '$s4main20templatedConstructoryyF'
6767

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

test/Interop/Cxx/templates/defaulted-template-type-parameter-module-interface.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// CHECK: func defaultedTemplateTypeParamAndUnrealtedParam(_: Int32)
1515
// CHECK: func overloadedDefaultedTemplate<T>(_: T)
1616
// CHECK: func overloadedDefaultedTemplate(_: Int32)
17-
// CHECK: func defaultedTemplateReferenceTypeParam<T>(_ t: inout T)
17+
// CHECK: func defaultedTemplateReferenceTypeParam<T>(_ t: UnsafeMutablePointer<T>)
1818
// The following types aren't imported correctly, but that does not have to do
1919
// with the fact that the template type paramaters are defaulted.
2020
// CHECK: func defaultedTemplatePointerTypeParam<T>(_ t: UnsafeMutablePointer<T>)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s
2+
3+
// TODO: This needs to be fixed in the SwiftTypeConverter.
4+
// Currently "Any" is imported as an Objective-C "id".
5+
// That doesn't work unless we have Objective-C interop.
6+
// Once that's done, this test can be merged with "template-irgen".
7+
// REQUIRES: objc_interop
8+
9+
import FunctionTemplates
10+
11+
// CHECK-LABEL: define {{.*}}void @"$s4main18testPassThroughAny1xypyp_tF"(%Any* noalias nocapture sret({{.*}}) %0, %Any* noalias nocapture dereferenceable({{32|16}}) %1)
12+
// CHECK: call i8* @_Z11passThroughIP11objc_objectET_S2_(i8*
13+
// CHECK: ret void
14+
public func testPassThroughAny(x: Any) -> Any {
15+
return passThrough(x)
16+
}
17+

test/Interop/Cxx/templates/function-template-module-interface.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
// CHECK: mutating func test2(_: Int32, _ varargs: Any...)
1515
// CHECK: }
1616

17-
// CHECK: func lvalueReference<T>(_ ref: inout T)
18-
// CHECK: func constLvalueReference<T>(_: inout T)
19-
// CHECK: func forwardingReference<T>(_: inout T)
17+
// CHECK: func lvalueReference<T>(_ ref: UnsafeMutablePointer<T>)
18+
// CHECK: func constLvalueReference<T>(_: UnsafePointer<T>)
19+
// CHECK: func forwardingReference<T>(_: UnsafeMutablePointer<T>)
2020
// CHECK: func PointerTemplateParameter<T>(_: UnsafeMutablePointer<T>)
2121

2222
// CHECK: enum Orbiters {
2323
// CHECK: static func galileo<T>(_: T)
2424
// CHECK: static func cassini<T, U>(_: T, _: U)
25-
// CHECK: static func magellan<T>(_: inout T)
25+
// CHECK: static func magellan<T>(_: UnsafeMutablePointer<T>)
2626
// CHECK: }

test/Interop/Cxx/templates/function-template.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ FunctionTemplateTestSuite.test("lvalueReference<T> where T == Int") {
2828
expectEqual(value, 42)
2929
}
3030

31+
// TODO: currently "Any" is imported as an Objective-C "id".
32+
// This doesn't work without the Objective-C runtime.
33+
#if _runtime(_ObjC)
34+
FunctionTemplateTestSuite.test("passThrough<T> where T == Any") {
35+
let result = passThrough(42 as Any)
36+
expectEqual(42, result as! Int)
37+
}
38+
#endif
39+
3140
// TODO: Generics, Any, and Protocols should be tested here but need to be
3241
// better supported in ClangTypeConverter first.
3342

test/Interop/Cxx/templates/member-templates-module-interface.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
// CHECK: mutating func passThroughConst<T>(_ val: T) -> T
99
// CHECK: func passThroughOnConst<T>(_ val: T) -> T
1010
// CHECK: func passThroughConstOnConst<T>(_ val: T) -> T
11-
// CHECK: mutating func doNothingConstRef<T>(_ val: inout T)
12-
// CHECK: mutating func make42Ref<T>(_ val: inout T)
11+
// CHECK: mutating func doNothingConstRef<T>(_ val: UnsafePointer<T>)
12+
// CHECK: mutating func make42Ref<T>(_ val: UnsafeMutablePointer<T>)
1313
// CHECK: }
1414

1515
// CHECK: struct __CxxTemplateInst32TemplateClassWithMemberTemplatesIiE {
@@ -24,5 +24,5 @@
2424
// CHECK: init()
2525
// CHECK: static func add<T>(_ a: T, _ b: T) -> T
2626
// CHECK: static func addTwoTemplates<T, U>(_ a: T, _ b: U) -> T
27-
// CHECK: static func removeReference<T>(_ a: inout T) -> T
27+
// CHECK: static func removeReference<T>(_ a: UnsafeMutablePointer<T>) -> T
2828
// CHECK: }

0 commit comments

Comments
 (0)