@@ -109,16 +109,18 @@ Solution::computeSubstitutions(GenericSignature sig,
109109 lookupConformanceFn);
110110}
111111
112- static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate (
113- ASTContext &ctx, AbstractFunctionDecl *oldDecl, SubstitutionMap subst,
114- clang::FunctionDecl *specialized) {
112+ // Derive a concrete function type for fdecl by substituting the generic args
113+ // and use that to derive the corresponding function type and parameter list.
114+ static std::pair<FunctionType *, ParameterList *>
115+ substituteFunctionTypeAndParamList (ASTContext &ctx, AbstractFunctionDecl *fdecl,
116+ SubstitutionMap subst) {
115117 FunctionType *newFnType = nullptr ;
116118 // Create a new ParameterList with the substituted type.
117119 if (auto oldFnType = dyn_cast<GenericFunctionType>(
118- oldDecl ->getInterfaceType ().getPointer ())) {
120+ fdecl ->getInterfaceType ().getPointer ())) {
119121 newFnType = oldFnType->substGenericArgs (subst);
120122 } else {
121- newFnType = cast<FunctionType>(oldDecl ->getInterfaceType ().getPointer ());
123+ newFnType = cast<FunctionType>(fdecl ->getInterfaceType ().getPointer ());
122124 }
123125 // The constructor type is a function type as follows:
124126 // (CType.Type) -> (Generic) -> CType
@@ -127,22 +129,49 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
127129 // In either case, we only want the result of that function type because that
128130 // is the function type with the generic params that need to be substituted:
129131 // (Generic) -> CType
130- if (isa<ConstructorDecl>(oldDecl ) || oldDecl ->isInstanceMember () ||
131- oldDecl ->isStatic ())
132+ if (isa<ConstructorDecl>(fdecl ) || fdecl ->isInstanceMember () ||
133+ fdecl ->isStatic ())
132134 newFnType = cast<FunctionType>(newFnType->getResult ().getPointer ());
133135 SmallVector<ParamDecl *, 4 > newParams;
134136 unsigned i = 0 ;
137+
135138 for (auto paramTy : newFnType->getParams ()) {
136- auto *oldParamDecl = oldDecl ->getParameters ()->get (i);
139+ auto *oldParamDecl = fdecl ->getParameters ()->get (i);
137140 auto *newParamDecl =
138- ParamDecl::cloneWithoutType (oldDecl ->getASTContext (), oldParamDecl);
141+ ParamDecl::cloneWithoutType (fdecl ->getASTContext (), oldParamDecl);
139142 newParamDecl->setInterfaceType (paramTy.getParameterType ());
140143 newParams.push_back (newParamDecl);
141144 (void )++i;
142145 }
143146 auto *newParamList =
144147 ParameterList::create (ctx, SourceLoc (), newParams, SourceLoc ());
145148
149+ return {newFnType, newParamList};
150+ }
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+
146175 if (isa<ConstructorDecl>(oldDecl)) {
147176 DeclName ctorName (ctx, DeclBaseName::createConstructor (), newParamList);
148177 auto newCtorDecl = ConstructorDecl::createImported (
@@ -152,7 +181,7 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
152181 /* throws=*/ false , /* throwsLoc=*/ SourceLoc (),
153182 newParamList, /* genericParams=*/ nullptr ,
154183 oldDecl->getDeclContext ());
155- return ConcreteDeclRef ( newCtorDecl) ;
184+ return newCtorDecl;
156185 }
157186
158187 // Generate a name for the specialized function.
@@ -176,7 +205,48 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
176205 newFnDecl->setImportAsStaticMember ();
177206 }
178207 newFnDecl->setSelfAccessKind (cast<FuncDecl>(oldDecl)->getSelfAccessKind ());
179- return ConcreteDeclRef (newFnDecl);
208+ return newFnDecl;
209+ }
210+
211+ // Synthesizes the body of a thunk that takes extra metatype arguments and
212+ // skips over them to forward them along to the FuncDecl contained by context.
213+ // This is used when importing a C++ templated function where the template params
214+ // are not used in the function signature. We supply the type params as explicit
215+ // metatype arguments to aid in typechecking, but they shouldn't be forwarded to
216+ // the corresponding C++ function.
217+ static std::pair<BraceStmt *, bool >
218+ synthesizeForwardingThunkBody (AbstractFunctionDecl *afd, void *context) {
219+ ASTContext &ctx = afd->getASTContext ();
220+
221+ auto thunkDecl = cast<FuncDecl>(afd);
222+ auto specializedFuncDecl = static_cast <FuncDecl *>(context);
223+
224+ SmallVector<Argument, 8 > forwardingParams;
225+ for (auto param : *thunkDecl->getParameters ()) {
226+ if (isa<MetatypeType>(param->getType ().getPointer ())) {
227+ continue ;
228+ }
229+ auto paramRefExpr = new (ctx) DeclRefExpr (param, DeclNameLoc (),
230+ /* Implicit=*/ true );
231+ paramRefExpr->setType (param->getType ());
232+ forwardingParams.push_back (Argument (SourceLoc (), Identifier (), paramRefExpr));
233+ }
234+
235+ auto *specializedFuncDeclRef = new (ctx) DeclRefExpr (ConcreteDeclRef (specializedFuncDecl),
236+ DeclNameLoc (), true );
237+ specializedFuncDeclRef->setType (specializedFuncDecl->getInterfaceType ());
238+
239+ auto argList = ArgumentList::createImplicit (ctx, forwardingParams);
240+ auto *specializedFuncCallExpr = CallExpr::createImplicit (ctx, specializedFuncDeclRef, argList);
241+ specializedFuncCallExpr->setType (thunkDecl->getResultInterfaceType ());
242+ specializedFuncCallExpr->setThrows (false );
243+
244+ auto returnStmt = new (ctx) ReturnStmt (SourceLoc (), specializedFuncCallExpr,
245+ /* implicit=*/ true );
246+
247+ auto body = BraceStmt::create (ctx, SourceLoc (), {returnStmt}, SourceLoc (),
248+ /* implicit=*/ true );
249+ return {body, /* isTypeChecked=*/ true };
180250}
181251
182252ConcreteDeclRef
@@ -215,13 +285,35 @@ Solution::resolveConcreteDeclRef(ValueDecl *decl,
215285 const_cast <clang::FunctionTemplateDecl *>(
216286 cast<clang::FunctionTemplateDecl>(decl->getClangDecl ())),
217287 subst);
218- return generateDeclRefForSpecializedCXXFunctionTemplate (
288+ auto newDecl = generateSpecializedCXXFunctionTemplate (
219289 decl->getASTContext (), cast<AbstractFunctionDecl>(decl), subst, newFn);
290+ if (auto fn = dyn_cast<FuncDecl>(decl)) {
291+ if (newFn->getNumParams () != fn->getParameters ()->size ()) {
292+ // We added additional metatype parameters to aid template
293+ // specialization, which are no longer now that we've specialized
294+ // this function. Create a thunk that only forwards the original
295+ // parameters along to the clang function.
296+ auto thunkTypeAndParamList = substituteFunctionTypeAndParamList (decl->getASTContext (),
297+ fn, subst);
298+ auto thunk = FuncDecl::createImplicit (
299+ fn->getASTContext (), fn->getStaticSpelling (), fn->getName (),
300+ fn->getNameLoc (), fn->hasAsync (), fn->hasThrows (),
301+ /* genericParams=*/ nullptr , thunkTypeAndParamList.second ,
302+ thunkTypeAndParamList.first ->getResult (), fn->getDeclContext ());
303+ thunk->copyFormalAccessFrom (fn);
304+ thunk->setBodySynthesizer (synthesizeForwardingThunkBody, cast<FuncDecl>(newDecl));
305+ thunk->setSelfAccessKind (fn->getSelfAccessKind ());
306+
307+ return ConcreteDeclRef (thunk);
308+ }
309+ }
310+ return ConcreteDeclRef (newDecl);
220311 }
221312
222313 return ConcreteDeclRef (decl, subst);
223314}
224315
316+
225317ConstraintLocator *Solution::getCalleeLocator (ConstraintLocator *locator,
226318 bool lookThroughApply) const {
227319 auto &cs = getConstraintSystem ();
0 commit comments