@@ -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
0 commit comments