@@ -149,6 +149,65 @@ substituteFunctionTypeAndParamList(ASTContext &ctx, AbstractFunctionDecl *fdecl,
149
149
return {newFnType, newParamList};
150
150
}
151
151
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
+
152
211
// Synthesizes the body of a thunk that takes extra metatype arguments and
153
212
// skips over them to forward them along to the FuncDecl contained by context.
154
213
// This is used when importing a C++ templated function where the template params
@@ -226,91 +285,8 @@ Solution::resolveConcreteDeclRef(ValueDecl *decl,
226
285
const_cast <clang::FunctionTemplateDecl *>(
227
286
cast<clang::FunctionTemplateDecl>(decl->getClangDecl ())),
228
287
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);
314
290
if (auto fn = dyn_cast<FuncDecl>(decl)) {
315
291
if (newFn->getNumParams () != fn->getParameters ()->size ()) {
316
292
// We added additional metatype parameters to aid template
@@ -328,10 +304,9 @@ Solution::resolveConcreteDeclRef(ValueDecl *decl,
328
304
thunk->setBodySynthesizer (synthesizeForwardingThunkBody, cast<FuncDecl>(newDecl));
329
305
thunk->setSelfAccessKind (fn->getSelfAccessKind ());
330
306
331
- newDecl = thunk;
307
+ return ConcreteDeclRef ( thunk) ;
332
308
}
333
309
}
334
-
335
310
return ConcreteDeclRef (newDecl);
336
311
}
337
312
0 commit comments