1 | //===- SemaTemplateDeductionGude.cpp - Template Argument Deduction---------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements deduction guides for C++ class template argument |
10 | // deduction. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "TreeTransform.h" |
15 | #include "TypeLocBuilder.h" |
16 | #include "clang/AST/ASTConsumer.h" |
17 | #include "clang/AST/ASTContext.h" |
18 | #include "clang/AST/Decl.h" |
19 | #include "clang/AST/DeclBase.h" |
20 | #include "clang/AST/DeclCXX.h" |
21 | #include "clang/AST/DeclFriend.h" |
22 | #include "clang/AST/DeclTemplate.h" |
23 | #include "clang/AST/DeclarationName.h" |
24 | #include "clang/AST/Expr.h" |
25 | #include "clang/AST/ExprCXX.h" |
26 | #include "clang/AST/OperationKinds.h" |
27 | #include "clang/AST/RecursiveASTVisitor.h" |
28 | #include "clang/AST/TemplateBase.h" |
29 | #include "clang/AST/TemplateName.h" |
30 | #include "clang/AST/Type.h" |
31 | #include "clang/AST/TypeLoc.h" |
32 | #include "clang/Basic/LLVM.h" |
33 | #include "clang/Basic/SourceLocation.h" |
34 | #include "clang/Basic/Specifiers.h" |
35 | #include "clang/Basic/TypeTraits.h" |
36 | #include "clang/Sema/DeclSpec.h" |
37 | #include "clang/Sema/Initialization.h" |
38 | #include "clang/Sema/Lookup.h" |
39 | #include "clang/Sema/Overload.h" |
40 | #include "clang/Sema/Ownership.h" |
41 | #include "clang/Sema/Scope.h" |
42 | #include "clang/Sema/Template.h" |
43 | #include "clang/Sema/TemplateDeduction.h" |
44 | #include "llvm/ADT/ArrayRef.h" |
45 | #include "llvm/ADT/DenseSet.h" |
46 | #include "llvm/ADT/STLExtras.h" |
47 | #include "llvm/ADT/SmallVector.h" |
48 | #include "llvm/Support/Casting.h" |
49 | #include "llvm/Support/ErrorHandling.h" |
50 | #include <cassert> |
51 | #include <optional> |
52 | #include <utility> |
53 | |
54 | using namespace clang; |
55 | using namespace sema; |
56 | |
57 | namespace { |
58 | /// Tree transform to "extract" a transformed type from a class template's |
59 | /// constructor to a deduction guide. |
60 | class |
61 | : public TreeTransform<ExtractTypeForDeductionGuide> { |
62 | llvm::SmallVectorImpl<TypedefNameDecl *> &; |
63 | ClassTemplateDecl *; |
64 | const MultiLevelTemplateArgumentList *; |
65 | std::optional<TemplateDeclInstantiator> ; |
66 | |
67 | public: |
68 | typedef TreeTransform<ExtractTypeForDeductionGuide> ; |
69 | ( |
70 | Sema &SemaRef, |
71 | llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs, |
72 | ClassTemplateDecl *NestedPattern, |
73 | const MultiLevelTemplateArgumentList *OuterInstantiationArgs) |
74 | : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs), |
75 | NestedPattern(NestedPattern), |
76 | OuterInstantiationArgs(OuterInstantiationArgs) { |
77 | if (OuterInstantiationArgs) |
78 | TypedefNameInstantiator.emplace( |
79 | args&: SemaRef, args: SemaRef.getASTContext().getTranslationUnitDecl(), |
80 | args: *OuterInstantiationArgs); |
81 | } |
82 | |
83 | TypeSourceInfo *(TypeSourceInfo *TSI) { return TransformType(DI: TSI); } |
84 | |
85 | /// Returns true if it's safe to substitute \p Typedef with |
86 | /// \p OuterInstantiationArgs. |
87 | bool (TypedefNameDecl *Typedef) { |
88 | if (!NestedPattern) |
89 | return false; |
90 | |
91 | static auto WalkUp = [](DeclContext *DC, DeclContext *TargetDC) { |
92 | if (DC->Equals(DC: TargetDC)) |
93 | return true; |
94 | while (DC->isRecord()) { |
95 | if (DC->Equals(DC: TargetDC)) |
96 | return true; |
97 | DC = DC->getParent(); |
98 | } |
99 | return false; |
100 | }; |
101 | |
102 | if (WalkUp(Typedef->getDeclContext(), NestedPattern->getTemplatedDecl())) |
103 | return true; |
104 | if (WalkUp(NestedPattern->getTemplatedDecl(), Typedef->getDeclContext())) |
105 | return true; |
106 | return false; |
107 | } |
108 | |
109 | QualType |
110 | (TemplateName Template, |
111 | SourceLocation TemplateNameLoc, |
112 | TemplateArgumentListInfo &TemplateArgs) { |
113 | if (!OuterInstantiationArgs || |
114 | !isa_and_present<TypeAliasTemplateDecl>(Val: Template.getAsTemplateDecl())) |
115 | return Base::RebuildTemplateSpecializationType(Template, TemplateLoc: TemplateNameLoc, |
116 | Args&: TemplateArgs); |
117 | |
118 | auto *TATD = cast<TypeAliasTemplateDecl>(Val: Template.getAsTemplateDecl()); |
119 | auto *Pattern = TATD; |
120 | while (Pattern->getInstantiatedFromMemberTemplate()) |
121 | Pattern = Pattern->getInstantiatedFromMemberTemplate(); |
122 | if (!mightReferToOuterTemplateParameters(Typedef: Pattern->getTemplatedDecl())) |
123 | return Base::RebuildTemplateSpecializationType(Template, TemplateLoc: TemplateNameLoc, |
124 | Args&: TemplateArgs); |
125 | |
126 | Decl *NewD = |
127 | TypedefNameInstantiator->InstantiateTypeAliasTemplateDecl(D: TATD); |
128 | if (!NewD) |
129 | return QualType(); |
130 | |
131 | auto *NewTATD = cast<TypeAliasTemplateDecl>(Val: NewD); |
132 | MaterializedTypedefs.push_back(Elt: NewTATD->getTemplatedDecl()); |
133 | |
134 | return Base::RebuildTemplateSpecializationType( |
135 | Template: TemplateName(NewTATD), TemplateLoc: TemplateNameLoc, Args&: TemplateArgs); |
136 | } |
137 | |
138 | QualType (TypeLocBuilder &TLB, TypedefTypeLoc TL) { |
139 | ASTContext &Context = SemaRef.getASTContext(); |
140 | TypedefNameDecl *OrigDecl = TL.getTypedefNameDecl(); |
141 | TypedefNameDecl *Decl = OrigDecl; |
142 | // Transform the underlying type of the typedef and clone the Decl only if |
143 | // the typedef has a dependent context. |
144 | bool InDependentContext = OrigDecl->getDeclContext()->isDependentContext(); |
145 | |
146 | // A typedef/alias Decl within the NestedPattern may reference the outer |
147 | // template parameters. They're substituted with corresponding instantiation |
148 | // arguments here and in RebuildTemplateSpecializationType() above. |
149 | // Otherwise, we would have a CTAD guide with "dangling" template |
150 | // parameters. |
151 | // For example, |
152 | // template <class T> struct Outer { |
153 | // using Alias = S<T>; |
154 | // template <class U> struct Inner { |
155 | // Inner(Alias); |
156 | // }; |
157 | // }; |
158 | if (OuterInstantiationArgs && InDependentContext && |
159 | TL.getTypePtr()->isInstantiationDependentType()) { |
160 | Decl = cast_if_present<TypedefNameDecl>( |
161 | Val: TypedefNameInstantiator->InstantiateTypedefNameDecl( |
162 | D: OrigDecl, /*IsTypeAlias=*/isa<TypeAliasDecl>(Val: OrigDecl))); |
163 | if (!Decl) |
164 | return QualType(); |
165 | MaterializedTypedefs.push_back(Elt: Decl); |
166 | } else if (InDependentContext) { |
167 | TypeLocBuilder InnerTLB; |
168 | QualType Transformed = |
169 | TransformType(TLB&: InnerTLB, TL: OrigDecl->getTypeSourceInfo()->getTypeLoc()); |
170 | TypeSourceInfo *TSI = InnerTLB.getTypeSourceInfo(Context, T: Transformed); |
171 | if (isa<TypeAliasDecl>(Val: OrigDecl)) |
172 | Decl = TypeAliasDecl::Create( |
173 | C&: Context, DC: Context.getTranslationUnitDecl(), StartLoc: OrigDecl->getBeginLoc(), |
174 | IdLoc: OrigDecl->getLocation(), Id: OrigDecl->getIdentifier(), TInfo: TSI); |
175 | else { |
176 | assert(isa<TypedefDecl>(OrigDecl) && "Not a Type alias or typedef" ); |
177 | Decl = TypedefDecl::Create( |
178 | C&: Context, DC: Context.getTranslationUnitDecl(), StartLoc: OrigDecl->getBeginLoc(), |
179 | IdLoc: OrigDecl->getLocation(), Id: OrigDecl->getIdentifier(), TInfo: TSI); |
180 | } |
181 | MaterializedTypedefs.push_back(Elt: Decl); |
182 | } |
183 | |
184 | QualType TDTy = Context.getTypedefType(Decl); |
185 | TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T: TDTy); |
186 | TypedefTL.setNameLoc(TL.getNameLoc()); |
187 | |
188 | return TDTy; |
189 | } |
190 | }; |
191 | |
192 | // Build a deduction guide using the provided information. |
193 | // |
194 | // A deduction guide can be either a template or a non-template function |
195 | // declaration. If \p TemplateParams is null, a non-template function |
196 | // declaration will be created. |
197 | NamedDecl *buildDeductionGuide( |
198 | Sema &SemaRef, TemplateDecl *OriginalTemplate, |
199 | TemplateParameterList *TemplateParams, CXXConstructorDecl *Ctor, |
200 | ExplicitSpecifier ES, TypeSourceInfo *TInfo, SourceLocation LocStart, |
201 | SourceLocation Loc, SourceLocation LocEnd, bool IsImplicit, |
202 | llvm::ArrayRef<TypedefNameDecl *> MaterializedTypedefs = {}) { |
203 | DeclContext *DC = OriginalTemplate->getDeclContext(); |
204 | auto DeductionGuideName = |
205 | SemaRef.Context.DeclarationNames.getCXXDeductionGuideName( |
206 | TD: OriginalTemplate); |
207 | |
208 | DeclarationNameInfo Name(DeductionGuideName, Loc); |
209 | ArrayRef<ParmVarDecl *> Params = |
210 | TInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(); |
211 | |
212 | // Build the implicit deduction guide template. |
213 | auto *Guide = |
214 | CXXDeductionGuideDecl::Create(C&: SemaRef.Context, DC, StartLoc: LocStart, ES, NameInfo: Name, |
215 | T: TInfo->getType(), TInfo, EndLocation: LocEnd, Ctor); |
216 | Guide->setImplicit(IsImplicit); |
217 | Guide->setParams(Params); |
218 | |
219 | for (auto *Param : Params) |
220 | Param->setDeclContext(Guide); |
221 | for (auto *TD : MaterializedTypedefs) |
222 | TD->setDeclContext(Guide); |
223 | if (isa<CXXRecordDecl>(Val: DC)) |
224 | Guide->setAccess(AS_public); |
225 | |
226 | if (!TemplateParams) { |
227 | DC->addDecl(D: Guide); |
228 | return Guide; |
229 | } |
230 | |
231 | auto *GuideTemplate = FunctionTemplateDecl::Create( |
232 | C&: SemaRef.Context, DC, L: Loc, Name: DeductionGuideName, Params: TemplateParams, Decl: Guide); |
233 | GuideTemplate->setImplicit(IsImplicit); |
234 | Guide->setDescribedFunctionTemplate(GuideTemplate); |
235 | |
236 | if (isa<CXXRecordDecl>(Val: DC)) |
237 | GuideTemplate->setAccess(AS_public); |
238 | |
239 | DC->addDecl(D: GuideTemplate); |
240 | return GuideTemplate; |
241 | } |
242 | |
243 | // Transform a given template type parameter `TTP`. |
244 | TemplateTypeParmDecl * |
245 | transformTemplateTypeParam(Sema &SemaRef, DeclContext *DC, |
246 | TemplateTypeParmDecl *TTP, |
247 | MultiLevelTemplateArgumentList &Args, |
248 | unsigned NewDepth, unsigned NewIndex) { |
249 | // TemplateTypeParmDecl's index cannot be changed after creation, so |
250 | // substitute it directly. |
251 | auto *NewTTP = TemplateTypeParmDecl::Create( |
252 | C: SemaRef.Context, DC, KeyLoc: TTP->getBeginLoc(), NameLoc: TTP->getLocation(), D: NewDepth, |
253 | P: NewIndex, Id: TTP->getIdentifier(), Typename: TTP->wasDeclaredWithTypename(), |
254 | ParameterPack: TTP->isParameterPack(), HasTypeConstraint: TTP->hasTypeConstraint(), |
255 | NumExpanded: TTP->isExpandedParameterPack() |
256 | ? std::optional<unsigned>(TTP->getNumExpansionParameters()) |
257 | : std::nullopt); |
258 | if (const auto *TC = TTP->getTypeConstraint()) |
259 | SemaRef.SubstTypeConstraint(Inst: NewTTP, TC, TemplateArgs: Args, |
260 | /*EvaluateConstraint=*/true); |
261 | if (TTP->hasDefaultArgument()) { |
262 | TemplateArgumentLoc InstantiatedDefaultArg; |
263 | if (!SemaRef.SubstTemplateArgument( |
264 | Input: TTP->getDefaultArgument(), TemplateArgs: Args, Output&: InstantiatedDefaultArg, |
265 | Loc: TTP->getDefaultArgumentLoc(), Entity: TTP->getDeclName())) |
266 | NewTTP->setDefaultArgument(C: SemaRef.Context, DefArg: InstantiatedDefaultArg); |
267 | } |
268 | SemaRef.CurrentInstantiationScope->InstantiatedLocal(D: TTP, Inst: NewTTP); |
269 | return NewTTP; |
270 | } |
271 | // Similar to above, but for non-type template or template template parameters. |
272 | template <typename NonTypeTemplateOrTemplateTemplateParmDecl> |
273 | NonTypeTemplateOrTemplateTemplateParmDecl * |
274 | transformTemplateParam(Sema &SemaRef, DeclContext *DC, |
275 | NonTypeTemplateOrTemplateTemplateParmDecl *OldParam, |
276 | MultiLevelTemplateArgumentList &Args, unsigned NewIndex, |
277 | unsigned NewDepth) { |
278 | // Ask the template instantiator to do the heavy lifting for us, then adjust |
279 | // the index of the parameter once it's done. |
280 | auto *NewParam = cast<NonTypeTemplateOrTemplateTemplateParmDecl>( |
281 | SemaRef.SubstDecl(D: OldParam, Owner: DC, TemplateArgs: Args)); |
282 | NewParam->setPosition(NewIndex); |
283 | NewParam->setDepth(NewDepth); |
284 | return NewParam; |
285 | } |
286 | |
287 | /// Transform to convert portions of a constructor declaration into the |
288 | /// corresponding deduction guide, per C++1z [over.match.class.deduct]p1. |
289 | struct ConvertConstructorToDeductionGuideTransform { |
290 | ConvertConstructorToDeductionGuideTransform(Sema &S, |
291 | ClassTemplateDecl *Template) |
292 | : SemaRef(S), Template(Template) { |
293 | // If the template is nested, then we need to use the original |
294 | // pattern to iterate over the constructors. |
295 | ClassTemplateDecl *Pattern = Template; |
296 | while (Pattern->getInstantiatedFromMemberTemplate()) { |
297 | if (Pattern->isMemberSpecialization()) |
298 | break; |
299 | Pattern = Pattern->getInstantiatedFromMemberTemplate(); |
300 | NestedPattern = Pattern; |
301 | } |
302 | |
303 | if (NestedPattern) |
304 | OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(D: Template); |
305 | } |
306 | |
307 | Sema &SemaRef; |
308 | ClassTemplateDecl *Template; |
309 | ClassTemplateDecl *NestedPattern = nullptr; |
310 | |
311 | DeclContext *DC = Template->getDeclContext(); |
312 | CXXRecordDecl *Primary = Template->getTemplatedDecl(); |
313 | DeclarationName DeductionGuideName = |
314 | SemaRef.Context.DeclarationNames.getCXXDeductionGuideName(TD: Template); |
315 | |
316 | QualType DeducedType = SemaRef.Context.getTypeDeclType(Decl: Primary); |
317 | |
318 | // Index adjustment to apply to convert depth-1 template parameters into |
319 | // depth-0 template parameters. |
320 | unsigned Depth1IndexAdjustment = Template->getTemplateParameters()->size(); |
321 | |
322 | // Instantiation arguments for the outermost depth-1 templates |
323 | // when the template is nested |
324 | MultiLevelTemplateArgumentList OuterInstantiationArgs; |
325 | |
326 | /// Transform a constructor declaration into a deduction guide. |
327 | NamedDecl *transformConstructor(FunctionTemplateDecl *FTD, |
328 | CXXConstructorDecl *CD) { |
329 | SmallVector<TemplateArgument, 16> SubstArgs; |
330 | |
331 | LocalInstantiationScope Scope(SemaRef); |
332 | |
333 | // C++ [over.match.class.deduct]p1: |
334 | // -- For each constructor of the class template designated by the |
335 | // template-name, a function template with the following properties: |
336 | |
337 | // -- The template parameters are the template parameters of the class |
338 | // template followed by the template parameters (including default |
339 | // template arguments) of the constructor, if any. |
340 | TemplateParameterList *TemplateParams = |
341 | SemaRef.GetTemplateParameterList(TD: Template); |
342 | if (FTD) { |
343 | TemplateParameterList *InnerParams = FTD->getTemplateParameters(); |
344 | SmallVector<NamedDecl *, 16> AllParams; |
345 | SmallVector<TemplateArgument, 16> Depth1Args; |
346 | AllParams.reserve(N: TemplateParams->size() + InnerParams->size()); |
347 | AllParams.insert(I: AllParams.begin(), From: TemplateParams->begin(), |
348 | To: TemplateParams->end()); |
349 | SubstArgs.reserve(N: InnerParams->size()); |
350 | Depth1Args.reserve(N: InnerParams->size()); |
351 | |
352 | // Later template parameters could refer to earlier ones, so build up |
353 | // a list of substituted template arguments as we go. |
354 | for (NamedDecl *Param : *InnerParams) { |
355 | MultiLevelTemplateArgumentList Args; |
356 | Args.setKind(TemplateSubstitutionKind::Rewrite); |
357 | Args.addOuterTemplateArguments(Args: Depth1Args); |
358 | Args.addOuterRetainedLevel(); |
359 | if (NestedPattern) |
360 | Args.addOuterRetainedLevels(Num: NestedPattern->getTemplateDepth()); |
361 | NamedDecl *NewParam = transformTemplateParameter(TemplateParam: Param, Args); |
362 | if (!NewParam) |
363 | return nullptr; |
364 | // Constraints require that we substitute depth-1 arguments |
365 | // to match depths when substituted for evaluation later |
366 | Depth1Args.push_back(Elt: SemaRef.Context.getInjectedTemplateArg(ParamDecl: NewParam)); |
367 | |
368 | if (NestedPattern) { |
369 | TemplateDeclInstantiator Instantiator(SemaRef, DC, |
370 | OuterInstantiationArgs); |
371 | Instantiator.setEvaluateConstraints(false); |
372 | SemaRef.runWithSufficientStackSpace(Loc: NewParam->getLocation(), Fn: [&] { |
373 | NewParam = cast<NamedDecl>(Val: Instantiator.Visit(D: NewParam)); |
374 | }); |
375 | } |
376 | |
377 | assert(NewParam->getTemplateDepth() == 0 && |
378 | "Unexpected template parameter depth" ); |
379 | |
380 | AllParams.push_back(Elt: NewParam); |
381 | SubstArgs.push_back(Elt: SemaRef.Context.getInjectedTemplateArg(ParamDecl: NewParam)); |
382 | } |
383 | |
384 | // Substitute new template parameters into requires-clause if present. |
385 | Expr *RequiresClause = nullptr; |
386 | if (Expr *InnerRC = InnerParams->getRequiresClause()) { |
387 | MultiLevelTemplateArgumentList Args; |
388 | Args.setKind(TemplateSubstitutionKind::Rewrite); |
389 | Args.addOuterTemplateArguments(Args: Depth1Args); |
390 | Args.addOuterRetainedLevel(); |
391 | if (NestedPattern) |
392 | Args.addOuterRetainedLevels(Num: NestedPattern->getTemplateDepth()); |
393 | ExprResult E = SemaRef.SubstExpr(E: InnerRC, TemplateArgs: Args); |
394 | if (E.isInvalid()) |
395 | return nullptr; |
396 | RequiresClause = E.getAs<Expr>(); |
397 | } |
398 | |
399 | TemplateParams = TemplateParameterList::Create( |
400 | C: SemaRef.Context, TemplateLoc: InnerParams->getTemplateLoc(), |
401 | LAngleLoc: InnerParams->getLAngleLoc(), Params: AllParams, RAngleLoc: InnerParams->getRAngleLoc(), |
402 | RequiresClause); |
403 | } |
404 | |
405 | // If we built a new template-parameter-list, track that we need to |
406 | // substitute references to the old parameters into references to the |
407 | // new ones. |
408 | MultiLevelTemplateArgumentList Args; |
409 | Args.setKind(TemplateSubstitutionKind::Rewrite); |
410 | if (FTD) { |
411 | Args.addOuterTemplateArguments(Args: SubstArgs); |
412 | Args.addOuterRetainedLevel(); |
413 | } |
414 | |
415 | FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo() |
416 | ->getTypeLoc() |
417 | .getAsAdjusted<FunctionProtoTypeLoc>(); |
418 | assert(FPTL && "no prototype for constructor declaration" ); |
419 | |
420 | // Transform the type of the function, adjusting the return type and |
421 | // replacing references to the old parameters with references to the |
422 | // new ones. |
423 | TypeLocBuilder TLB; |
424 | SmallVector<ParmVarDecl *, 8> Params; |
425 | SmallVector<TypedefNameDecl *, 4> MaterializedTypedefs; |
426 | QualType NewType = transformFunctionProtoType(TLB, TL: FPTL, Params, Args, |
427 | MaterializedTypedefs); |
428 | if (NewType.isNull()) |
429 | return nullptr; |
430 | TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(Context&: SemaRef.Context, T: NewType); |
431 | |
432 | return buildDeductionGuide( |
433 | SemaRef, OriginalTemplate: Template, TemplateParams, Ctor: CD, ES: CD->getExplicitSpecifier(), |
434 | TInfo: NewTInfo, LocStart: CD->getBeginLoc(), Loc: CD->getLocation(), LocEnd: CD->getEndLoc(), |
435 | /*IsImplicit=*/true, MaterializedTypedefs); |
436 | } |
437 | |
438 | /// Build a deduction guide with the specified parameter types. |
439 | NamedDecl *buildSimpleDeductionGuide(MutableArrayRef<QualType> ParamTypes) { |
440 | SourceLocation Loc = Template->getLocation(); |
441 | |
442 | // Build the requested type. |
443 | FunctionProtoType::ExtProtoInfo EPI; |
444 | EPI.HasTrailingReturn = true; |
445 | QualType Result = SemaRef.BuildFunctionType(T: DeducedType, ParamTypes, Loc, |
446 | Entity: DeductionGuideName, EPI); |
447 | TypeSourceInfo *TSI = SemaRef.Context.getTrivialTypeSourceInfo(T: Result, Loc); |
448 | if (NestedPattern) |
449 | TSI = SemaRef.SubstType(T: TSI, TemplateArgs: OuterInstantiationArgs, Loc, |
450 | Entity: DeductionGuideName); |
451 | |
452 | if (!TSI) |
453 | return nullptr; |
454 | |
455 | FunctionProtoTypeLoc FPTL = |
456 | TSI->getTypeLoc().castAs<FunctionProtoTypeLoc>(); |
457 | |
458 | // Build the parameters, needed during deduction / substitution. |
459 | SmallVector<ParmVarDecl *, 4> Params; |
460 | for (auto T : ParamTypes) { |
461 | auto *TSI = SemaRef.Context.getTrivialTypeSourceInfo(T, Loc); |
462 | if (NestedPattern) |
463 | TSI = SemaRef.SubstType(T: TSI, TemplateArgs: OuterInstantiationArgs, Loc, |
464 | Entity: DeclarationName()); |
465 | if (!TSI) |
466 | return nullptr; |
467 | |
468 | ParmVarDecl *NewParam = |
469 | ParmVarDecl::Create(C&: SemaRef.Context, DC, StartLoc: Loc, IdLoc: Loc, Id: nullptr, |
470 | T: TSI->getType(), TInfo: TSI, S: SC_None, DefArg: nullptr); |
471 | NewParam->setScopeInfo(scopeDepth: 0, parameterIndex: Params.size()); |
472 | FPTL.setParam(i: Params.size(), VD: NewParam); |
473 | Params.push_back(Elt: NewParam); |
474 | } |
475 | |
476 | return buildDeductionGuide( |
477 | SemaRef, OriginalTemplate: Template, TemplateParams: SemaRef.GetTemplateParameterList(TD: Template), Ctor: nullptr, |
478 | ES: ExplicitSpecifier(), TInfo: TSI, LocStart: Loc, Loc, LocEnd: Loc, /*IsImplicit=*/true); |
479 | } |
480 | |
481 | private: |
482 | /// Transform a constructor template parameter into a deduction guide template |
483 | /// parameter, rebuilding any internal references to earlier parameters and |
484 | /// renumbering as we go. |
485 | NamedDecl *transformTemplateParameter(NamedDecl *TemplateParam, |
486 | MultiLevelTemplateArgumentList &Args) { |
487 | if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Val: TemplateParam)) |
488 | return transformTemplateTypeParam( |
489 | SemaRef, DC, TTP, Args, NewDepth: TTP->getDepth() - 1, |
490 | NewIndex: Depth1IndexAdjustment + TTP->getIndex()); |
491 | if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Val: TemplateParam)) |
492 | return transformTemplateParam(SemaRef, DC, OldParam: TTP, Args, |
493 | NewIndex: Depth1IndexAdjustment + TTP->getIndex(), |
494 | NewDepth: TTP->getDepth() - 1); |
495 | auto *NTTP = cast<NonTypeTemplateParmDecl>(Val: TemplateParam); |
496 | return transformTemplateParam(SemaRef, DC, OldParam: NTTP, Args, |
497 | NewIndex: Depth1IndexAdjustment + NTTP->getIndex(), |
498 | NewDepth: NTTP->getDepth() - 1); |
499 | } |
500 | |
501 | QualType transformFunctionProtoType( |
502 | TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, |
503 | SmallVectorImpl<ParmVarDecl *> &Params, |
504 | MultiLevelTemplateArgumentList &Args, |
505 | SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) { |
506 | SmallVector<QualType, 4> ParamTypes; |
507 | const FunctionProtoType *T = TL.getTypePtr(); |
508 | |
509 | // -- The types of the function parameters are those of the constructor. |
510 | for (auto *OldParam : TL.getParams()) { |
511 | ParmVarDecl *NewParam = OldParam; |
512 | // Given |
513 | // template <class T> struct C { |
514 | // template <class U> struct D { |
515 | // template <class V> D(U, V); |
516 | // }; |
517 | // }; |
518 | // First, transform all the references to template parameters that are |
519 | // defined outside of the surrounding class template. That is T in the |
520 | // above example. |
521 | if (NestedPattern) { |
522 | NewParam = transformFunctionTypeParam( |
523 | OldParam: NewParam, Args&: OuterInstantiationArgs, MaterializedTypedefs, |
524 | /*TransformingOuterPatterns=*/true); |
525 | if (!NewParam) |
526 | return QualType(); |
527 | } |
528 | // Then, transform all the references to template parameters that are |
529 | // defined at the class template and the constructor. In this example, |
530 | // they're U and V, respectively. |
531 | NewParam = |
532 | transformFunctionTypeParam(OldParam: NewParam, Args, MaterializedTypedefs, |
533 | /*TransformingOuterPatterns=*/false); |
534 | if (!NewParam) |
535 | return QualType(); |
536 | ParamTypes.push_back(Elt: NewParam->getType()); |
537 | Params.push_back(Elt: NewParam); |
538 | } |
539 | |
540 | // -- The return type is the class template specialization designated by |
541 | // the template-name and template arguments corresponding to the |
542 | // template parameters obtained from the class template. |
543 | // |
544 | // We use the injected-class-name type of the primary template instead. |
545 | // This has the convenient property that it is different from any type that |
546 | // the user can write in a deduction-guide (because they cannot enter the |
547 | // context of the template), so implicit deduction guides can never collide |
548 | // with explicit ones. |
549 | QualType ReturnType = DeducedType; |
550 | TLB.pushTypeSpec(T: ReturnType).setNameLoc(Primary->getLocation()); |
551 | |
552 | // Resolving a wording defect, we also inherit the variadicness of the |
553 | // constructor. |
554 | FunctionProtoType::ExtProtoInfo EPI; |
555 | EPI.Variadic = T->isVariadic(); |
556 | EPI.HasTrailingReturn = true; |
557 | |
558 | QualType Result = SemaRef.BuildFunctionType( |
559 | T: ReturnType, ParamTypes, Loc: TL.getBeginLoc(), Entity: DeductionGuideName, EPI); |
560 | if (Result.isNull()) |
561 | return QualType(); |
562 | |
563 | FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(T: Result); |
564 | NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); |
565 | NewTL.setLParenLoc(TL.getLParenLoc()); |
566 | NewTL.setRParenLoc(TL.getRParenLoc()); |
567 | NewTL.setExceptionSpecRange(SourceRange()); |
568 | NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); |
569 | for (unsigned I = 0, E = NewTL.getNumParams(); I != E; ++I) |
570 | NewTL.setParam(i: I, VD: Params[I]); |
571 | |
572 | return Result; |
573 | } |
574 | |
575 | ParmVarDecl *transformFunctionTypeParam( |
576 | ParmVarDecl *OldParam, MultiLevelTemplateArgumentList &Args, |
577 | llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs, |
578 | bool TransformingOuterPatterns) { |
579 | TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo(); |
580 | TypeSourceInfo *NewDI; |
581 | if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) { |
582 | // Expand out the one and only element in each inner pack. |
583 | Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, 0); |
584 | NewDI = |
585 | SemaRef.SubstType(TL: PackTL.getPatternLoc(), TemplateArgs: Args, |
586 | Loc: OldParam->getLocation(), Entity: OldParam->getDeclName()); |
587 | if (!NewDI) |
588 | return nullptr; |
589 | NewDI = |
590 | SemaRef.CheckPackExpansion(Pattern: NewDI, EllipsisLoc: PackTL.getEllipsisLoc(), |
591 | NumExpansions: PackTL.getTypePtr()->getNumExpansions()); |
592 | } else |
593 | NewDI = SemaRef.SubstType(T: OldDI, TemplateArgs: Args, Loc: OldParam->getLocation(), |
594 | Entity: OldParam->getDeclName()); |
595 | if (!NewDI) |
596 | return nullptr; |
597 | |
598 | // Extract the type. This (for instance) replaces references to typedef |
599 | // members of the current instantiations with the definitions of those |
600 | // typedefs, avoiding triggering instantiation of the deduced type during |
601 | // deduction. |
602 | NewDI = ExtractTypeForDeductionGuide( |
603 | SemaRef, MaterializedTypedefs, NestedPattern, |
604 | TransformingOuterPatterns ? &Args : nullptr) |
605 | .transform(TSI: NewDI); |
606 | |
607 | // Resolving a wording defect, we also inherit default arguments from the |
608 | // constructor. |
609 | ExprResult NewDefArg; |
610 | if (OldParam->hasDefaultArg()) { |
611 | // We don't care what the value is (we won't use it); just create a |
612 | // placeholder to indicate there is a default argument. |
613 | QualType ParamTy = NewDI->getType(); |
614 | NewDefArg = new (SemaRef.Context) |
615 | OpaqueValueExpr(OldParam->getDefaultArgRange().getBegin(), |
616 | ParamTy.getNonLValueExprType(Context: SemaRef.Context), |
617 | ParamTy->isLValueReferenceType() ? VK_LValue |
618 | : ParamTy->isRValueReferenceType() ? VK_XValue |
619 | : VK_PRValue); |
620 | } |
621 | // Handle arrays and functions decay. |
622 | auto NewType = NewDI->getType(); |
623 | if (NewType->isArrayType() || NewType->isFunctionType()) |
624 | NewType = SemaRef.Context.getDecayedType(T: NewType); |
625 | |
626 | ParmVarDecl *NewParam = ParmVarDecl::Create( |
627 | C&: SemaRef.Context, DC, StartLoc: OldParam->getInnerLocStart(), |
628 | IdLoc: OldParam->getLocation(), Id: OldParam->getIdentifier(), T: NewType, TInfo: NewDI, |
629 | S: OldParam->getStorageClass(), DefArg: NewDefArg.get()); |
630 | NewParam->setScopeInfo(scopeDepth: OldParam->getFunctionScopeDepth(), |
631 | parameterIndex: OldParam->getFunctionScopeIndex()); |
632 | SemaRef.CurrentInstantiationScope->InstantiatedLocal(D: OldParam, Inst: NewParam); |
633 | return NewParam; |
634 | } |
635 | }; |
636 | |
637 | unsigned getTemplateParameterDepth(NamedDecl *TemplateParam) { |
638 | if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Val: TemplateParam)) |
639 | return TTP->getDepth(); |
640 | if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Val: TemplateParam)) |
641 | return TTP->getDepth(); |
642 | if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Val: TemplateParam)) |
643 | return NTTP->getDepth(); |
644 | llvm_unreachable("Unhandled template parameter types" ); |
645 | } |
646 | |
647 | unsigned getTemplateParameterIndex(NamedDecl *TemplateParam) { |
648 | if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Val: TemplateParam)) |
649 | return TTP->getIndex(); |
650 | if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Val: TemplateParam)) |
651 | return TTP->getIndex(); |
652 | if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Val: TemplateParam)) |
653 | return NTTP->getIndex(); |
654 | llvm_unreachable("Unhandled template parameter types" ); |
655 | } |
656 | |
657 | // Find all template parameters that appear in the given DeducedArgs. |
658 | // Return the indices of the template parameters in the TemplateParams. |
659 | SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList( |
660 | const TemplateParameterList *TemplateParamsList, |
661 | ArrayRef<TemplateArgument> DeducedArgs) { |
662 | struct TemplateParamsReferencedFinder |
663 | : public RecursiveASTVisitor<TemplateParamsReferencedFinder> { |
664 | const TemplateParameterList *TemplateParamList; |
665 | llvm::BitVector ReferencedTemplateParams; |
666 | |
667 | TemplateParamsReferencedFinder( |
668 | const TemplateParameterList *TemplateParamList) |
669 | : TemplateParamList(TemplateParamList), |
670 | ReferencedTemplateParams(TemplateParamList->size()) {} |
671 | |
672 | bool VisitTemplateTypeParmType(TemplateTypeParmType *TTP) { |
673 | // We use the index and depth to retrieve the corresponding template |
674 | // parameter from the parameter list, which is more robost. |
675 | Mark(Depth: TTP->getDepth(), Index: TTP->getIndex()); |
676 | return true; |
677 | } |
678 | |
679 | bool VisitDeclRefExpr(DeclRefExpr *DRE) { |
680 | MarkAppeared(ND: DRE->getFoundDecl()); |
681 | return true; |
682 | } |
683 | |
684 | bool TraverseTemplateName(TemplateName Template) { |
685 | if (auto *TD = Template.getAsTemplateDecl()) |
686 | MarkAppeared(ND: TD); |
687 | return RecursiveASTVisitor::TraverseTemplateName(Template); |
688 | } |
689 | |
690 | void MarkAppeared(NamedDecl *ND) { |
691 | if (llvm::isa<NonTypeTemplateParmDecl, TemplateTypeParmDecl, |
692 | TemplateTemplateParmDecl>(Val: ND)) |
693 | Mark(Depth: getTemplateParameterDepth(TemplateParam: ND), Index: getTemplateParameterIndex(TemplateParam: ND)); |
694 | } |
695 | void Mark(unsigned Depth, unsigned Index) { |
696 | if (Index < TemplateParamList->size() && |
697 | TemplateParamList->getParam(Idx: Index)->getTemplateDepth() == Depth) |
698 | ReferencedTemplateParams.set(Index); |
699 | } |
700 | }; |
701 | TemplateParamsReferencedFinder Finder(TemplateParamsList); |
702 | Finder.TraverseTemplateArguments(Args: DeducedArgs); |
703 | |
704 | SmallVector<unsigned> Results; |
705 | for (unsigned Index = 0; Index < TemplateParamsList->size(); ++Index) { |
706 | if (Finder.ReferencedTemplateParams[Index]) |
707 | Results.push_back(Elt: Index); |
708 | } |
709 | return Results; |
710 | } |
711 | |
712 | bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext *DC) { |
713 | // Check whether we've already declared deduction guides for this template. |
714 | // FIXME: Consider storing a flag on the template to indicate this. |
715 | assert(Name.getNameKind() == |
716 | DeclarationName::NameKind::CXXDeductionGuideName && |
717 | "name must be a deduction guide name" ); |
718 | auto Existing = DC->lookup(Name); |
719 | for (auto *D : Existing) |
720 | if (D->isImplicit()) |
721 | return true; |
722 | return false; |
723 | } |
724 | |
725 | NamedDecl *transformTemplateParameter(Sema &SemaRef, DeclContext *DC, |
726 | NamedDecl *TemplateParam, |
727 | MultiLevelTemplateArgumentList &Args, |
728 | unsigned NewIndex, unsigned NewDepth) { |
729 | if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Val: TemplateParam)) |
730 | return transformTemplateTypeParam(SemaRef, DC, TTP, Args, NewDepth, |
731 | NewIndex); |
732 | if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Val: TemplateParam)) |
733 | return transformTemplateParam(SemaRef, DC, OldParam: TTP, Args, NewIndex, NewDepth); |
734 | if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Val: TemplateParam)) |
735 | return transformTemplateParam(SemaRef, DC, OldParam: NTTP, Args, NewIndex, NewDepth); |
736 | llvm_unreachable("Unhandled template parameter types" ); |
737 | } |
738 | |
739 | // Build the associated constraints for the alias deduction guides. |
740 | // C++ [over.match.class.deduct]p3.3: |
741 | // The associated constraints ([temp.constr.decl]) are the conjunction of the |
742 | // associated constraints of g and a constraint that is satisfied if and only |
743 | // if the arguments of A are deducible (see below) from the return type. |
744 | // |
745 | // The return result is expected to be the require-clause for the synthesized |
746 | // alias deduction guide. |
747 | Expr * |
748 | buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, |
749 | TypeAliasTemplateDecl *AliasTemplate, |
750 | ArrayRef<DeducedTemplateArgument> DeduceResults, |
751 | unsigned FirstUndeducedParamIdx, Expr *IsDeducible) { |
752 | Expr *RC = F->getTemplateParameters()->getRequiresClause(); |
753 | if (!RC) |
754 | return IsDeducible; |
755 | |
756 | ASTContext &Context = SemaRef.Context; |
757 | LocalInstantiationScope Scope(SemaRef); |
758 | |
759 | // In the clang AST, constraint nodes are deliberately not instantiated unless |
760 | // they are actively being evaluated. Consequently, occurrences of template |
761 | // parameters in the require-clause expression have a subtle "depth" |
762 | // difference compared to normal occurrences in places, such as function |
763 | // parameters. When transforming the require-clause, we must take this |
764 | // distinction into account: |
765 | // |
766 | // 1) In the transformed require-clause, occurrences of template parameters |
767 | // must use the "uninstantiated" depth; |
768 | // 2) When substituting on the require-clause expr of the underlying |
769 | // deduction guide, we must use the entire set of template argument lists; |
770 | // |
771 | // It's important to note that we're performing this transformation on an |
772 | // *instantiated* AliasTemplate. |
773 | |
774 | // For 1), if the alias template is nested within a class template, we |
775 | // calcualte the 'uninstantiated' depth by adding the substitution level back. |
776 | unsigned AdjustDepth = 0; |
777 | if (auto *PrimaryTemplate = |
778 | AliasTemplate->getInstantiatedFromMemberTemplate()) |
779 | AdjustDepth = PrimaryTemplate->getTemplateDepth(); |
780 | |
781 | // We rebuild all template parameters with the uninstantiated depth, and |
782 | // build template arguments refer to them. |
783 | SmallVector<TemplateArgument> AdjustedAliasTemplateArgs; |
784 | |
785 | for (auto *TP : *AliasTemplate->getTemplateParameters()) { |
786 | // Rebuild any internal references to earlier parameters and reindex |
787 | // as we go. |
788 | MultiLevelTemplateArgumentList Args; |
789 | Args.setKind(TemplateSubstitutionKind::Rewrite); |
790 | Args.addOuterTemplateArguments(Args: AdjustedAliasTemplateArgs); |
791 | NamedDecl *NewParam = transformTemplateParameter( |
792 | SemaRef, DC: AliasTemplate->getDeclContext(), TemplateParam: TP, Args, |
793 | /*NewIndex=*/AdjustedAliasTemplateArgs.size(), |
794 | NewDepth: getTemplateParameterDepth(TemplateParam: TP) + AdjustDepth); |
795 | |
796 | TemplateArgument NewTemplateArgument = |
797 | Context.getInjectedTemplateArg(ParamDecl: NewParam); |
798 | AdjustedAliasTemplateArgs.push_back(Elt: NewTemplateArgument); |
799 | } |
800 | // Template arguments used to transform the template arguments in |
801 | // DeducedResults. |
802 | SmallVector<TemplateArgument> TemplateArgsForBuildingRC( |
803 | F->getTemplateParameters()->size()); |
804 | // Transform the transformed template args |
805 | MultiLevelTemplateArgumentList Args; |
806 | Args.setKind(TemplateSubstitutionKind::Rewrite); |
807 | Args.addOuterTemplateArguments(Args: AdjustedAliasTemplateArgs); |
808 | |
809 | for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) { |
810 | const auto &D = DeduceResults[Index]; |
811 | if (D.isNull()) { // non-deduced template parameters of f |
812 | NamedDecl *TP = F->getTemplateParameters()->getParam(Idx: Index); |
813 | MultiLevelTemplateArgumentList Args; |
814 | Args.setKind(TemplateSubstitutionKind::Rewrite); |
815 | Args.addOuterTemplateArguments(Args: TemplateArgsForBuildingRC); |
816 | // Rebuild the template parameter with updated depth and index. |
817 | NamedDecl *NewParam = transformTemplateParameter( |
818 | SemaRef, DC: F->getDeclContext(), TemplateParam: TP, Args, |
819 | /*NewIndex=*/FirstUndeducedParamIdx, |
820 | NewDepth: getTemplateParameterDepth(TemplateParam: TP) + AdjustDepth); |
821 | FirstUndeducedParamIdx += 1; |
822 | assert(TemplateArgsForBuildingRC[Index].isNull()); |
823 | TemplateArgsForBuildingRC[Index] = |
824 | Context.getInjectedTemplateArg(ParamDecl: NewParam); |
825 | continue; |
826 | } |
827 | TemplateArgumentLoc Input = |
828 | SemaRef.getTrivialTemplateArgumentLoc(Arg: D, NTTPType: QualType(), Loc: SourceLocation{}); |
829 | TemplateArgumentLoc Output; |
830 | if (!SemaRef.SubstTemplateArgument(Input, TemplateArgs: Args, Output)) { |
831 | assert(TemplateArgsForBuildingRC[Index].isNull() && |
832 | "InstantiatedArgs must be null before setting" ); |
833 | TemplateArgsForBuildingRC[Index] = Output.getArgument(); |
834 | } |
835 | } |
836 | |
837 | // A list of template arguments for transforming the require-clause of F. |
838 | // It must contain the entire set of template argument lists. |
839 | MultiLevelTemplateArgumentList ArgsForBuildingRC; |
840 | ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite); |
841 | ArgsForBuildingRC.addOuterTemplateArguments(Args: TemplateArgsForBuildingRC); |
842 | // For 2), if the underlying deduction guide F is nested in a class template, |
843 | // we need the entire template argument list, as the constraint AST in the |
844 | // require-clause of F remains completely uninstantiated. |
845 | // |
846 | // For example: |
847 | // template <typename T> // depth 0 |
848 | // struct Outer { |
849 | // template <typename U> |
850 | // struct Foo { Foo(U); }; |
851 | // |
852 | // template <typename U> // depth 1 |
853 | // requires C<U> |
854 | // Foo(U) -> Foo<int>; |
855 | // }; |
856 | // template <typename U> |
857 | // using AFoo = Outer<int>::Foo<U>; |
858 | // |
859 | // In this scenario, the deduction guide for `Foo` inside `Outer<int>`: |
860 | // - The occurrence of U in the require-expression is [depth:1, index:0] |
861 | // - The occurrence of U in the function parameter is [depth:0, index:0] |
862 | // - The template parameter of U is [depth:0, index:0] |
863 | // |
864 | // We add the outer template arguments which is [int] to the multi-level arg |
865 | // list to ensure that the occurrence U in `C<U>` will be replaced with int |
866 | // during the substitution. |
867 | // |
868 | // NOTE: The underlying deduction guide F is instantiated -- either from an |
869 | // explicitly-written deduction guide member, or from a constructor. |
870 | // getInstantiatedFromMemberTemplate() can only handle the former case, so we |
871 | // check the DeclContext kind. |
872 | if (F->getLexicalDeclContext()->getDeclKind() == |
873 | clang::Decl::ClassTemplateSpecialization) { |
874 | auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs( |
875 | D: F, DC: F->getLexicalDeclContext(), |
876 | /*Final=*/false, /*Innermost=*/std::nullopt, |
877 | /*RelativeToPrimary=*/true, |
878 | /*Pattern=*/nullptr, |
879 | /*ForConstraintInstantiation=*/true); |
880 | for (auto It : OuterLevelArgs) |
881 | ArgsForBuildingRC.addOuterTemplateArguments(Args: It.Args); |
882 | } |
883 | |
884 | ExprResult E = SemaRef.SubstExpr(E: RC, TemplateArgs: ArgsForBuildingRC); |
885 | if (E.isInvalid()) |
886 | return nullptr; |
887 | |
888 | auto Conjunction = |
889 | SemaRef.BuildBinOp(S: SemaRef.getCurScope(), OpLoc: SourceLocation{}, |
890 | Opc: BinaryOperatorKind::BO_LAnd, LHSExpr: E.get(), RHSExpr: IsDeducible); |
891 | if (Conjunction.isInvalid()) |
892 | return nullptr; |
893 | return Conjunction.getAs<Expr>(); |
894 | } |
895 | // Build the is_deducible constraint for the alias deduction guides. |
896 | // [over.match.class.deduct]p3.3: |
897 | // ... and a constraint that is satisfied if and only if the arguments |
898 | // of A are deducible (see below) from the return type. |
899 | Expr *buildIsDeducibleConstraint(Sema &SemaRef, |
900 | TypeAliasTemplateDecl *AliasTemplate, |
901 | QualType ReturnType, |
902 | SmallVector<NamedDecl *> TemplateParams) { |
903 | ASTContext &Context = SemaRef.Context; |
904 | // Constraint AST nodes must use uninstantiated depth. |
905 | if (auto *PrimaryTemplate = |
906 | AliasTemplate->getInstantiatedFromMemberTemplate(); |
907 | PrimaryTemplate && TemplateParams.size() > 0) { |
908 | LocalInstantiationScope Scope(SemaRef); |
909 | |
910 | // Adjust the depth for TemplateParams. |
911 | unsigned AdjustDepth = PrimaryTemplate->getTemplateDepth(); |
912 | SmallVector<TemplateArgument> TransformedTemplateArgs; |
913 | for (auto *TP : TemplateParams) { |
914 | // Rebuild any internal references to earlier parameters and reindex |
915 | // as we go. |
916 | MultiLevelTemplateArgumentList Args; |
917 | Args.setKind(TemplateSubstitutionKind::Rewrite); |
918 | Args.addOuterTemplateArguments(Args: TransformedTemplateArgs); |
919 | NamedDecl *NewParam = transformTemplateParameter( |
920 | SemaRef, DC: AliasTemplate->getDeclContext(), TemplateParam: TP, Args, |
921 | /*NewIndex=*/TransformedTemplateArgs.size(), |
922 | NewDepth: getTemplateParameterDepth(TemplateParam: TP) + AdjustDepth); |
923 | |
924 | TemplateArgument NewTemplateArgument = |
925 | Context.getInjectedTemplateArg(ParamDecl: NewParam); |
926 | TransformedTemplateArgs.push_back(Elt: NewTemplateArgument); |
927 | } |
928 | // Transformed the ReturnType to restore the uninstantiated depth. |
929 | MultiLevelTemplateArgumentList Args; |
930 | Args.setKind(TemplateSubstitutionKind::Rewrite); |
931 | Args.addOuterTemplateArguments(Args: TransformedTemplateArgs); |
932 | ReturnType = SemaRef.SubstType( |
933 | T: ReturnType, TemplateArgs: Args, Loc: AliasTemplate->getLocation(), |
934 | Entity: Context.DeclarationNames.getCXXDeductionGuideName(TD: AliasTemplate)); |
935 | }; |
936 | |
937 | SmallVector<TypeSourceInfo *> IsDeducibleTypeTraitArgs = { |
938 | Context.getTrivialTypeSourceInfo( |
939 | T: Context.getDeducedTemplateSpecializationType( |
940 | Template: TemplateName(AliasTemplate), /*DeducedType=*/QualType(), |
941 | /*IsDependent=*/true)), // template specialization type whose |
942 | // arguments will be deduced. |
943 | Context.getTrivialTypeSourceInfo( |
944 | T: ReturnType), // type from which template arguments are deduced. |
945 | }; |
946 | return TypeTraitExpr::Create( |
947 | C: Context, T: Context.getLogicalOperationType(), Loc: AliasTemplate->getLocation(), |
948 | Kind: TypeTrait::BTT_IsDeducible, Args: IsDeducibleTypeTraitArgs, |
949 | RParenLoc: AliasTemplate->getLocation(), /*Value*/ false); |
950 | } |
951 | |
952 | std::pair<TemplateDecl *, llvm::ArrayRef<TemplateArgument>> |
953 | getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) { |
954 | // Unwrap the sugared ElaboratedType. |
955 | auto RhsType = AliasTemplate->getTemplatedDecl() |
956 | ->getUnderlyingType() |
957 | .getSingleStepDesugaredType(Context: SemaRef.Context); |
958 | TemplateDecl *Template = nullptr; |
959 | llvm::ArrayRef<TemplateArgument> AliasRhsTemplateArgs; |
960 | if (const auto *TST = RhsType->getAs<TemplateSpecializationType>()) { |
961 | // Cases where the RHS of the alias is dependent. e.g. |
962 | // template<typename T> |
963 | // using AliasFoo1 = Foo<T>; // a class/type alias template specialization |
964 | Template = TST->getTemplateName().getAsTemplateDecl(); |
965 | AliasRhsTemplateArgs = TST->template_arguments(); |
966 | } else if (const auto *RT = RhsType->getAs<RecordType>()) { |
967 | // Cases where template arguments in the RHS of the alias are not |
968 | // dependent. e.g. |
969 | // using AliasFoo = Foo<bool>; |
970 | if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>( |
971 | Val: RT->getAsCXXRecordDecl())) { |
972 | Template = CTSD->getSpecializedTemplate(); |
973 | AliasRhsTemplateArgs = CTSD->getTemplateArgs().asArray(); |
974 | } |
975 | } else { |
976 | assert(false && "unhandled RHS type of the alias" ); |
977 | } |
978 | return {Template, AliasRhsTemplateArgs}; |
979 | } |
980 | |
981 | // Build deduction guides for a type alias template from the given underlying |
982 | // deduction guide F. |
983 | FunctionTemplateDecl * |
984 | BuildDeductionGuideForTypeAlias(Sema &SemaRef, |
985 | TypeAliasTemplateDecl *AliasTemplate, |
986 | FunctionTemplateDecl *F, SourceLocation Loc) { |
987 | LocalInstantiationScope Scope(SemaRef); |
988 | Sema::InstantiatingTemplate BuildingDeductionGuides( |
989 | SemaRef, AliasTemplate->getLocation(), F, |
990 | Sema::InstantiatingTemplate::BuildingDeductionGuidesTag{}); |
991 | if (BuildingDeductionGuides.isInvalid()) |
992 | return nullptr; |
993 | |
994 | auto &Context = SemaRef.Context; |
995 | auto [Template, AliasRhsTemplateArgs] = |
996 | getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate); |
997 | |
998 | auto RType = F->getTemplatedDecl()->getReturnType(); |
999 | // The (trailing) return type of the deduction guide. |
1000 | const TemplateSpecializationType *FReturnType = |
1001 | RType->getAs<TemplateSpecializationType>(); |
1002 | if (const auto *InjectedCNT = RType->getAs<InjectedClassNameType>()) |
1003 | // implicitly-generated deduction guide. |
1004 | FReturnType = InjectedCNT->getInjectedTST(); |
1005 | else if (const auto *ET = RType->getAs<ElaboratedType>()) |
1006 | // explicit deduction guide. |
1007 | FReturnType = ET->getNamedType()->getAs<TemplateSpecializationType>(); |
1008 | assert(FReturnType && "expected to see a return type" ); |
1009 | // Deduce template arguments of the deduction guide f from the RHS of |
1010 | // the alias. |
1011 | // |
1012 | // C++ [over.match.class.deduct]p3: ...For each function or function |
1013 | // template f in the guides of the template named by the |
1014 | // simple-template-id of the defining-type-id, the template arguments |
1015 | // of the return type of f are deduced from the defining-type-id of A |
1016 | // according to the process in [temp.deduct.type] with the exception |
1017 | // that deduction does not fail if not all template arguments are |
1018 | // deduced. |
1019 | // |
1020 | // |
1021 | // template<typename X, typename Y> |
1022 | // f(X, Y) -> f<Y, X>; |
1023 | // |
1024 | // template<typename U> |
1025 | // using alias = f<int, U>; |
1026 | // |
1027 | // The RHS of alias is f<int, U>, we deduced the template arguments of |
1028 | // the return type of the deduction guide from it: Y->int, X->U |
1029 | sema::TemplateDeductionInfo TDeduceInfo(Loc); |
1030 | // Must initialize n elements, this is required by DeduceTemplateArguments. |
1031 | SmallVector<DeducedTemplateArgument> DeduceResults( |
1032 | F->getTemplateParameters()->size()); |
1033 | |
1034 | // FIXME: DeduceTemplateArguments stops immediately at the first |
1035 | // non-deducible template argument. However, this doesn't seem to casue |
1036 | // issues for practice cases, we probably need to extend it to continue |
1037 | // performing deduction for rest of arguments to align with the C++ |
1038 | // standard. |
1039 | SemaRef.DeduceTemplateArguments( |
1040 | TemplateParams: F->getTemplateParameters(), Ps: FReturnType->template_arguments(), |
1041 | As: AliasRhsTemplateArgs, Info&: TDeduceInfo, Deduced&: DeduceResults, |
1042 | /*NumberOfArgumentsMustMatch=*/false); |
1043 | |
1044 | SmallVector<TemplateArgument> DeducedArgs; |
1045 | SmallVector<unsigned> NonDeducedTemplateParamsInFIndex; |
1046 | // !!NOTE: DeduceResults respects the sequence of template parameters of |
1047 | // the deduction guide f. |
1048 | for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) { |
1049 | if (const auto &D = DeduceResults[Index]; !D.isNull()) // Deduced |
1050 | DeducedArgs.push_back(Elt: D); |
1051 | else |
1052 | NonDeducedTemplateParamsInFIndex.push_back(Elt: Index); |
1053 | } |
1054 | auto DeducedAliasTemplateParams = |
1055 | TemplateParamsReferencedInTemplateArgumentList( |
1056 | TemplateParamsList: AliasTemplate->getTemplateParameters(), DeducedArgs); |
1057 | // All template arguments null by default. |
1058 | SmallVector<TemplateArgument> TemplateArgsForBuildingFPrime( |
1059 | F->getTemplateParameters()->size()); |
1060 | |
1061 | // Create a template parameter list for the synthesized deduction guide f'. |
1062 | // |
1063 | // C++ [over.match.class.deduct]p3.2: |
1064 | // If f is a function template, f' is a function template whose template |
1065 | // parameter list consists of all the template parameters of A |
1066 | // (including their default template arguments) that appear in the above |
1067 | // deductions or (recursively) in their default template arguments |
1068 | SmallVector<NamedDecl *> FPrimeTemplateParams; |
1069 | // Store template arguments that refer to the newly-created template |
1070 | // parameters, used for building `TemplateArgsForBuildingFPrime`. |
1071 | SmallVector<TemplateArgument, 16> TransformedDeducedAliasArgs( |
1072 | AliasTemplate->getTemplateParameters()->size()); |
1073 | |
1074 | for (unsigned AliasTemplateParamIdx : DeducedAliasTemplateParams) { |
1075 | auto *TP = |
1076 | AliasTemplate->getTemplateParameters()->getParam(Idx: AliasTemplateParamIdx); |
1077 | // Rebuild any internal references to earlier parameters and reindex as |
1078 | // we go. |
1079 | MultiLevelTemplateArgumentList Args; |
1080 | Args.setKind(TemplateSubstitutionKind::Rewrite); |
1081 | Args.addOuterTemplateArguments(Args: TransformedDeducedAliasArgs); |
1082 | NamedDecl *NewParam = transformTemplateParameter( |
1083 | SemaRef, DC: AliasTemplate->getDeclContext(), TemplateParam: TP, Args, |
1084 | /*NewIndex=*/FPrimeTemplateParams.size(), |
1085 | NewDepth: getTemplateParameterDepth(TemplateParam: TP)); |
1086 | FPrimeTemplateParams.push_back(Elt: NewParam); |
1087 | |
1088 | TemplateArgument NewTemplateArgument = |
1089 | Context.getInjectedTemplateArg(ParamDecl: NewParam); |
1090 | TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument; |
1091 | } |
1092 | unsigned FirstUndeducedParamIdx = FPrimeTemplateParams.size(); |
1093 | // ...followed by the template parameters of f that were not deduced |
1094 | // (including their default template arguments) |
1095 | for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) { |
1096 | auto *TP = F->getTemplateParameters()->getParam(Idx: FTemplateParamIdx); |
1097 | MultiLevelTemplateArgumentList Args; |
1098 | Args.setKind(TemplateSubstitutionKind::Rewrite); |
1099 | // We take a shortcut here, it is ok to reuse the |
1100 | // TemplateArgsForBuildingFPrime. |
1101 | Args.addOuterTemplateArguments(Args: TemplateArgsForBuildingFPrime); |
1102 | NamedDecl *NewParam = transformTemplateParameter( |
1103 | SemaRef, DC: F->getDeclContext(), TemplateParam: TP, Args, NewIndex: FPrimeTemplateParams.size(), |
1104 | NewDepth: getTemplateParameterDepth(TemplateParam: TP)); |
1105 | FPrimeTemplateParams.push_back(Elt: NewParam); |
1106 | |
1107 | assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() && |
1108 | "The argument must be null before setting" ); |
1109 | TemplateArgsForBuildingFPrime[FTemplateParamIdx] = |
1110 | Context.getInjectedTemplateArg(ParamDecl: NewParam); |
1111 | } |
1112 | |
1113 | // To form a deduction guide f' from f, we leverage clang's instantiation |
1114 | // mechanism, we construct a template argument list where the template |
1115 | // arguments refer to the newly-created template parameters of f', and |
1116 | // then apply instantiation on this template argument list to instantiate |
1117 | // f, this ensures all template parameter occurrences are updated |
1118 | // correctly. |
1119 | // |
1120 | // The template argument list is formed from the `DeducedArgs`, two parts: |
1121 | // 1) appeared template parameters of alias: transfrom the deduced |
1122 | // template argument; |
1123 | // 2) non-deduced template parameters of f: rebuild a |
1124 | // template argument; |
1125 | // |
1126 | // 2) has been built already (when rebuilding the new template |
1127 | // parameters), we now perform 1). |
1128 | MultiLevelTemplateArgumentList Args; |
1129 | Args.setKind(TemplateSubstitutionKind::Rewrite); |
1130 | Args.addOuterTemplateArguments(Args: TransformedDeducedAliasArgs); |
1131 | for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) { |
1132 | const auto &D = DeduceResults[Index]; |
1133 | if (D.isNull()) { |
1134 | // 2): Non-deduced template parameter has been built already. |
1135 | assert(!TemplateArgsForBuildingFPrime[Index].isNull() && |
1136 | "template arguments for non-deduced template parameters should " |
1137 | "be been set!" ); |
1138 | continue; |
1139 | } |
1140 | TemplateArgumentLoc Input = |
1141 | SemaRef.getTrivialTemplateArgumentLoc(Arg: D, NTTPType: QualType(), Loc: SourceLocation{}); |
1142 | TemplateArgumentLoc Output; |
1143 | if (!SemaRef.SubstTemplateArgument(Input, TemplateArgs: Args, Output)) { |
1144 | assert(TemplateArgsForBuildingFPrime[Index].isNull() && |
1145 | "InstantiatedArgs must be null before setting" ); |
1146 | TemplateArgsForBuildingFPrime[Index] = Output.getArgument(); |
1147 | } |
1148 | } |
1149 | |
1150 | auto *TemplateArgListForBuildingFPrime = |
1151 | TemplateArgumentList::CreateCopy(Context, Args: TemplateArgsForBuildingFPrime); |
1152 | // Form the f' by substituting the template arguments into f. |
1153 | if (auto *FPrime = SemaRef.InstantiateFunctionDeclaration( |
1154 | FTD: F, Args: TemplateArgListForBuildingFPrime, Loc: AliasTemplate->getLocation(), |
1155 | CSC: Sema::CodeSynthesisContext::BuildingDeductionGuides)) { |
1156 | auto *GG = cast<CXXDeductionGuideDecl>(Val: FPrime); |
1157 | |
1158 | Expr *IsDeducible = buildIsDeducibleConstraint( |
1159 | SemaRef, AliasTemplate, ReturnType: FPrime->getReturnType(), TemplateParams: FPrimeTemplateParams); |
1160 | Expr *RequiresClause = |
1161 | buildAssociatedConstraints(SemaRef, F, AliasTemplate, DeduceResults, |
1162 | FirstUndeducedParamIdx, IsDeducible); |
1163 | |
1164 | auto *FPrimeTemplateParamList = TemplateParameterList::Create( |
1165 | C: Context, TemplateLoc: AliasTemplate->getTemplateParameters()->getTemplateLoc(), |
1166 | LAngleLoc: AliasTemplate->getTemplateParameters()->getLAngleLoc(), |
1167 | Params: FPrimeTemplateParams, |
1168 | RAngleLoc: AliasTemplate->getTemplateParameters()->getRAngleLoc(), |
1169 | /*RequiresClause=*/RequiresClause); |
1170 | auto *Result = cast<FunctionTemplateDecl>(Val: buildDeductionGuide( |
1171 | SemaRef, OriginalTemplate: AliasTemplate, TemplateParams: FPrimeTemplateParamList, |
1172 | Ctor: GG->getCorrespondingConstructor(), ES: GG->getExplicitSpecifier(), |
1173 | TInfo: GG->getTypeSourceInfo(), LocStart: AliasTemplate->getBeginLoc(), |
1174 | Loc: AliasTemplate->getLocation(), LocEnd: AliasTemplate->getEndLoc(), |
1175 | IsImplicit: F->isImplicit())); |
1176 | cast<CXXDeductionGuideDecl>(Val: Result->getTemplatedDecl()) |
1177 | ->setDeductionCandidateKind(GG->getDeductionCandidateKind()); |
1178 | return Result; |
1179 | } |
1180 | return nullptr; |
1181 | } |
1182 | |
1183 | void DeclareImplicitDeductionGuidesForTypeAlias( |
1184 | Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc) { |
1185 | if (AliasTemplate->isInvalidDecl()) |
1186 | return; |
1187 | auto &Context = SemaRef.Context; |
1188 | // FIXME: if there is an explicit deduction guide after the first use of the |
1189 | // type alias usage, we will not cover this explicit deduction guide. fix this |
1190 | // case. |
1191 | if (hasDeclaredDeductionGuides( |
1192 | Name: Context.DeclarationNames.getCXXDeductionGuideName(TD: AliasTemplate), |
1193 | DC: AliasTemplate->getDeclContext())) |
1194 | return; |
1195 | auto [Template, AliasRhsTemplateArgs] = |
1196 | getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate); |
1197 | if (!Template) |
1198 | return; |
1199 | DeclarationNameInfo NameInfo( |
1200 | Context.DeclarationNames.getCXXDeductionGuideName(TD: Template), Loc); |
1201 | LookupResult Guides(SemaRef, NameInfo, clang::Sema::LookupOrdinaryName); |
1202 | SemaRef.LookupQualifiedName(R&: Guides, LookupCtx: Template->getDeclContext()); |
1203 | Guides.suppressDiagnostics(); |
1204 | |
1205 | for (auto *G : Guides) { |
1206 | if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(Val: G)) { |
1207 | // The deduction guide is a non-template function decl, we just clone it. |
1208 | auto *FunctionType = |
1209 | SemaRef.Context.getTrivialTypeSourceInfo(T: DG->getType()); |
1210 | FunctionProtoTypeLoc FPTL = |
1211 | FunctionType->getTypeLoc().castAs<FunctionProtoTypeLoc>(); |
1212 | |
1213 | // Clone the parameters. |
1214 | for (unsigned I = 0, N = DG->getNumParams(); I != N; ++I) { |
1215 | const auto *P = DG->getParamDecl(i: I); |
1216 | auto *TSI = SemaRef.Context.getTrivialTypeSourceInfo(T: P->getType()); |
1217 | ParmVarDecl *NewParam = ParmVarDecl::Create( |
1218 | C&: SemaRef.Context, DC: G->getDeclContext(), |
1219 | StartLoc: DG->getParamDecl(i: I)->getBeginLoc(), IdLoc: P->getLocation(), Id: nullptr, |
1220 | T: TSI->getType(), TInfo: TSI, S: SC_None, DefArg: nullptr); |
1221 | NewParam->setScopeInfo(scopeDepth: 0, parameterIndex: I); |
1222 | FPTL.setParam(i: I, VD: NewParam); |
1223 | } |
1224 | auto *Transformed = cast<FunctionDecl>(Val: buildDeductionGuide( |
1225 | SemaRef, OriginalTemplate: AliasTemplate, /*TemplateParams=*/nullptr, |
1226 | /*Constructor=*/Ctor: nullptr, ES: DG->getExplicitSpecifier(), TInfo: FunctionType, |
1227 | LocStart: AliasTemplate->getBeginLoc(), Loc: AliasTemplate->getLocation(), |
1228 | LocEnd: AliasTemplate->getEndLoc(), IsImplicit: DG->isImplicit())); |
1229 | |
1230 | // FIXME: Here the synthesized deduction guide is not a templated |
1231 | // function. Per [dcl.decl]p4, the requires-clause shall be present only |
1232 | // if the declarator declares a templated function, a bug in standard? |
1233 | auto *Constraint = buildIsDeducibleConstraint( |
1234 | SemaRef, AliasTemplate, ReturnType: Transformed->getReturnType(), TemplateParams: {}); |
1235 | if (auto *RC = DG->getTrailingRequiresClause()) { |
1236 | auto Conjunction = |
1237 | SemaRef.BuildBinOp(S: SemaRef.getCurScope(), OpLoc: SourceLocation{}, |
1238 | Opc: BinaryOperatorKind::BO_LAnd, LHSExpr: RC, RHSExpr: Constraint); |
1239 | if (!Conjunction.isInvalid()) |
1240 | Constraint = Conjunction.getAs<Expr>(); |
1241 | } |
1242 | Transformed->setTrailingRequiresClause(Constraint); |
1243 | } |
1244 | FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(Val: G); |
1245 | if (!F) |
1246 | continue; |
1247 | // The **aggregate** deduction guides are handled in a different code path |
1248 | // (DeclareAggregateDeductionGuideFromInitList), which involves the tricky |
1249 | // cache. |
1250 | if (cast<CXXDeductionGuideDecl>(Val: F->getTemplatedDecl()) |
1251 | ->getDeductionCandidateKind() == DeductionCandidate::Aggregate) |
1252 | continue; |
1253 | |
1254 | BuildDeductionGuideForTypeAlias(SemaRef, AliasTemplate, F, Loc); |
1255 | } |
1256 | } |
1257 | |
1258 | // Build an aggregate deduction guide for a type alias template. |
1259 | FunctionTemplateDecl *DeclareAggregateDeductionGuideForTypeAlias( |
1260 | Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, |
1261 | MutableArrayRef<QualType> ParamTypes, SourceLocation Loc) { |
1262 | TemplateDecl *RHSTemplate = |
1263 | getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate).first; |
1264 | if (!RHSTemplate) |
1265 | return nullptr; |
1266 | auto *RHSDeductionGuide = SemaRef.DeclareAggregateDeductionGuideFromInitList( |
1267 | Template: RHSTemplate, ParamTypes, Loc); |
1268 | if (!RHSDeductionGuide) |
1269 | return nullptr; |
1270 | return BuildDeductionGuideForTypeAlias(SemaRef, AliasTemplate, |
1271 | F: RHSDeductionGuide, Loc); |
1272 | } |
1273 | |
1274 | } // namespace |
1275 | |
1276 | FunctionTemplateDecl *Sema::DeclareAggregateDeductionGuideFromInitList( |
1277 | TemplateDecl *Template, MutableArrayRef<QualType> ParamTypes, |
1278 | SourceLocation Loc) { |
1279 | llvm::FoldingSetNodeID ID; |
1280 | ID.AddPointer(Ptr: Template); |
1281 | for (auto &T : ParamTypes) |
1282 | T.getCanonicalType().Profile(ID); |
1283 | unsigned Hash = ID.ComputeHash(); |
1284 | |
1285 | auto Found = AggregateDeductionCandidates.find(Val: Hash); |
1286 | if (Found != AggregateDeductionCandidates.end()) { |
1287 | CXXDeductionGuideDecl *GD = Found->getSecond(); |
1288 | return GD->getDescribedFunctionTemplate(); |
1289 | } |
1290 | |
1291 | if (auto *AliasTemplate = llvm::dyn_cast<TypeAliasTemplateDecl>(Val: Template)) { |
1292 | if (auto *FTD = DeclareAggregateDeductionGuideForTypeAlias( |
1293 | SemaRef&: *this, AliasTemplate, ParamTypes, Loc)) { |
1294 | auto *GD = cast<CXXDeductionGuideDecl>(Val: FTD->getTemplatedDecl()); |
1295 | GD->setDeductionCandidateKind(DeductionCandidate::Aggregate); |
1296 | AggregateDeductionCandidates[Hash] = GD; |
1297 | return FTD; |
1298 | } |
1299 | } |
1300 | |
1301 | if (CXXRecordDecl *DefRecord = |
1302 | cast<CXXRecordDecl>(Val: Template->getTemplatedDecl())->getDefinition()) { |
1303 | if (TemplateDecl *DescribedTemplate = |
1304 | DefRecord->getDescribedClassTemplate()) |
1305 | Template = DescribedTemplate; |
1306 | } |
1307 | |
1308 | DeclContext *DC = Template->getDeclContext(); |
1309 | if (DC->isDependentContext()) |
1310 | return nullptr; |
1311 | |
1312 | ConvertConstructorToDeductionGuideTransform Transform( |
1313 | *this, cast<ClassTemplateDecl>(Val: Template)); |
1314 | if (!isCompleteType(Loc, T: Transform.DeducedType)) |
1315 | return nullptr; |
1316 | |
1317 | // In case we were expanding a pack when we attempted to declare deduction |
1318 | // guides, turn off pack expansion for everything we're about to do. |
1319 | ArgumentPackSubstitutionIndexRAII SubstIndex(*this, |
1320 | /*NewSubstitutionIndex=*/-1); |
1321 | // Create a template instantiation record to track the "instantiation" of |
1322 | // constructors into deduction guides. |
1323 | InstantiatingTemplate BuildingDeductionGuides( |
1324 | *this, Loc, Template, |
1325 | Sema::InstantiatingTemplate::BuildingDeductionGuidesTag{}); |
1326 | if (BuildingDeductionGuides.isInvalid()) |
1327 | return nullptr; |
1328 | |
1329 | ClassTemplateDecl *Pattern = |
1330 | Transform.NestedPattern ? Transform.NestedPattern : Transform.Template; |
1331 | ContextRAII SavedContext(*this, Pattern->getTemplatedDecl()); |
1332 | |
1333 | auto *FTD = cast<FunctionTemplateDecl>( |
1334 | Val: Transform.buildSimpleDeductionGuide(ParamTypes)); |
1335 | SavedContext.pop(); |
1336 | auto *GD = cast<CXXDeductionGuideDecl>(Val: FTD->getTemplatedDecl()); |
1337 | GD->setDeductionCandidateKind(DeductionCandidate::Aggregate); |
1338 | AggregateDeductionCandidates[Hash] = GD; |
1339 | return FTD; |
1340 | } |
1341 | |
1342 | void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, |
1343 | SourceLocation Loc) { |
1344 | if (auto *AliasTemplate = llvm::dyn_cast<TypeAliasTemplateDecl>(Val: Template)) { |
1345 | DeclareImplicitDeductionGuidesForTypeAlias(SemaRef&: *this, AliasTemplate, Loc); |
1346 | return; |
1347 | } |
1348 | if (CXXRecordDecl *DefRecord = |
1349 | cast<CXXRecordDecl>(Val: Template->getTemplatedDecl())->getDefinition()) { |
1350 | if (TemplateDecl *DescribedTemplate = |
1351 | DefRecord->getDescribedClassTemplate()) |
1352 | Template = DescribedTemplate; |
1353 | } |
1354 | |
1355 | DeclContext *DC = Template->getDeclContext(); |
1356 | if (DC->isDependentContext()) |
1357 | return; |
1358 | |
1359 | ConvertConstructorToDeductionGuideTransform Transform( |
1360 | *this, cast<ClassTemplateDecl>(Val: Template)); |
1361 | if (!isCompleteType(Loc, T: Transform.DeducedType)) |
1362 | return; |
1363 | |
1364 | if (hasDeclaredDeductionGuides(Name: Transform.DeductionGuideName, DC)) |
1365 | return; |
1366 | |
1367 | // In case we were expanding a pack when we attempted to declare deduction |
1368 | // guides, turn off pack expansion for everything we're about to do. |
1369 | ArgumentPackSubstitutionIndexRAII SubstIndex(*this, -1); |
1370 | // Create a template instantiation record to track the "instantiation" of |
1371 | // constructors into deduction guides. |
1372 | InstantiatingTemplate BuildingDeductionGuides( |
1373 | *this, Loc, Template, |
1374 | Sema::InstantiatingTemplate::BuildingDeductionGuidesTag{}); |
1375 | if (BuildingDeductionGuides.isInvalid()) |
1376 | return; |
1377 | |
1378 | // Convert declared constructors into deduction guide templates. |
1379 | // FIXME: Skip constructors for which deduction must necessarily fail (those |
1380 | // for which some class template parameter without a default argument never |
1381 | // appears in a deduced context). |
1382 | ClassTemplateDecl *Pattern = |
1383 | Transform.NestedPattern ? Transform.NestedPattern : Transform.Template; |
1384 | ContextRAII SavedContext(*this, Pattern->getTemplatedDecl()); |
1385 | llvm::SmallPtrSet<NamedDecl *, 8> ProcessedCtors; |
1386 | bool AddedAny = false; |
1387 | for (NamedDecl *D : LookupConstructors(Class: Pattern->getTemplatedDecl())) { |
1388 | D = D->getUnderlyingDecl(); |
1389 | if (D->isInvalidDecl() || D->isImplicit()) |
1390 | continue; |
1391 | |
1392 | D = cast<NamedDecl>(Val: D->getCanonicalDecl()); |
1393 | |
1394 | // Within C++20 modules, we may have multiple same constructors in |
1395 | // multiple same RecordDecls. And it doesn't make sense to create |
1396 | // duplicated deduction guides for the duplicated constructors. |
1397 | if (ProcessedCtors.count(Ptr: D)) |
1398 | continue; |
1399 | |
1400 | auto *FTD = dyn_cast<FunctionTemplateDecl>(Val: D); |
1401 | auto *CD = |
1402 | dyn_cast_or_null<CXXConstructorDecl>(Val: FTD ? FTD->getTemplatedDecl() : D); |
1403 | // Class-scope explicit specializations (MS extension) do not result in |
1404 | // deduction guides. |
1405 | if (!CD || (!FTD && CD->isFunctionTemplateSpecialization())) |
1406 | continue; |
1407 | |
1408 | // Cannot make a deduction guide when unparsed arguments are present. |
1409 | if (llvm::any_of(Range: CD->parameters(), P: [](ParmVarDecl *P) { |
1410 | return !P || P->hasUnparsedDefaultArg(); |
1411 | })) |
1412 | continue; |
1413 | |
1414 | ProcessedCtors.insert(Ptr: D); |
1415 | Transform.transformConstructor(FTD, CD); |
1416 | AddedAny = true; |
1417 | } |
1418 | |
1419 | // C++17 [over.match.class.deduct] |
1420 | // -- If C is not defined or does not declare any constructors, an |
1421 | // additional function template derived as above from a hypothetical |
1422 | // constructor C(). |
1423 | if (!AddedAny) |
1424 | Transform.buildSimpleDeductionGuide(ParamTypes: std::nullopt); |
1425 | |
1426 | // -- An additional function template derived as above from a hypothetical |
1427 | // constructor C(C), called the copy deduction candidate. |
1428 | cast<CXXDeductionGuideDecl>( |
1429 | Val: cast<FunctionTemplateDecl>( |
1430 | Val: Transform.buildSimpleDeductionGuide(ParamTypes: Transform.DeducedType)) |
1431 | ->getTemplatedDecl()) |
1432 | ->setDeductionCandidateKind(DeductionCandidate::Copy); |
1433 | |
1434 | SavedContext.pop(); |
1435 | } |
1436 | |