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