1//===- TemplateDeduction.h - C++ template argument deduction ----*- C++ -*-===//
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 provides types used with Sema's template argument deduction
10// routines.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H
15#define LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H
16
17#include "clang/Sema/Ownership.h"
18#include "clang/Sema/SemaConcept.h"
19#include "clang/AST/ASTConcept.h"
20#include "clang/AST/DeclAccessPair.h"
21#include "clang/AST/DeclTemplate.h"
22#include "clang/AST/TemplateBase.h"
23#include "clang/Basic/PartialDiagnostic.h"
24#include "clang/Basic/SourceLocation.h"
25#include "llvm/ADT/SmallVector.h"
26#include <cassert>
27#include <cstddef>
28#include <optional>
29#include <utility>
30
31namespace clang {
32
33class Decl;
34struct DeducedPack;
35class Sema;
36enum class TemplateDeductionResult;
37
38namespace sema {
39
40/// Provides information about an attempted template argument
41/// deduction, whose success or failure was described by a
42/// TemplateDeductionResult value.
43class TemplateDeductionInfo {
44 /// The deduced template argument list.
45 TemplateArgumentList *DeducedSugared = nullptr, *DeducedCanonical = nullptr;
46
47 /// The source location at which template argument
48 /// deduction is occurring.
49 SourceLocation Loc;
50
51 /// Have we suppressed an error during deduction?
52 bool HasSFINAEDiagnostic = false;
53
54 /// The template parameter depth for which we're performing deduction.
55 unsigned DeducedDepth;
56
57 /// The number of parameters with explicitly-specified template arguments,
58 /// up to and including the partially-specified pack (if any).
59 unsigned ExplicitArgs = 0;
60
61 /// Warnings (and follow-on notes) that were suppressed due to
62 /// SFINAE while performing template argument deduction.
63 SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics;
64
65public:
66 TemplateDeductionInfo(SourceLocation Loc, unsigned DeducedDepth = 0)
67 : Loc(Loc), DeducedDepth(DeducedDepth) {}
68 TemplateDeductionInfo(const TemplateDeductionInfo &) = delete;
69 TemplateDeductionInfo &operator=(const TemplateDeductionInfo &) = delete;
70
71 enum ForBaseTag { ForBase };
72 /// Create temporary template deduction info for speculatively deducing
73 /// against a base class of an argument's type.
74 TemplateDeductionInfo(ForBaseTag, const TemplateDeductionInfo &Info)
75 : DeducedSugared(Info.DeducedSugared), Loc(Info.Loc),
76 DeducedDepth(Info.DeducedDepth), ExplicitArgs(Info.ExplicitArgs) {}
77
78 /// Returns the location at which template argument is
79 /// occurring.
80 SourceLocation getLocation() const {
81 return Loc;
82 }
83
84 /// The depth of template parameters for which deduction is being
85 /// performed.
86 unsigned getDeducedDepth() const {
87 return DeducedDepth;
88 }
89
90 /// Get the number of explicitly-specified arguments.
91 unsigned getNumExplicitArgs() const {
92 return ExplicitArgs;
93 }
94
95 /// Take ownership of the deduced template argument lists.
96 TemplateArgumentList *takeSugared() {
97 TemplateArgumentList *Result = DeducedSugared;
98 DeducedSugared = nullptr;
99 return Result;
100 }
101 TemplateArgumentList *takeCanonical() {
102 TemplateArgumentList *Result = DeducedCanonical;
103 DeducedCanonical = nullptr;
104 return Result;
105 }
106
107 /// Take ownership of the SFINAE diagnostic.
108 void takeSFINAEDiagnostic(PartialDiagnosticAt &PD) {
109 assert(HasSFINAEDiagnostic);
110 PD.first = SuppressedDiagnostics.front().first;
111 PD.second.swap(PD&: SuppressedDiagnostics.front().second);
112 clearSFINAEDiagnostic();
113 }
114
115 /// Discard any SFINAE diagnostics.
116 void clearSFINAEDiagnostic() {
117 SuppressedDiagnostics.clear();
118 HasSFINAEDiagnostic = false;
119 }
120
121 /// Peek at the SFINAE diagnostic.
122 const PartialDiagnosticAt &peekSFINAEDiagnostic() const {
123 assert(HasSFINAEDiagnostic);
124 return SuppressedDiagnostics.front();
125 }
126
127 /// Provide an initial template argument list that contains the
128 /// explicitly-specified arguments.
129 void setExplicitArgs(TemplateArgumentList *NewDeducedSugared,
130 TemplateArgumentList *NewDeducedCanonical) {
131 assert(NewDeducedSugared->size() == NewDeducedCanonical->size());
132 DeducedSugared = NewDeducedSugared;
133 DeducedCanonical = NewDeducedCanonical;
134 ExplicitArgs = DeducedSugared->size();
135 }
136
137 /// Provide a new template argument list that contains the
138 /// results of template argument deduction.
139 void reset(TemplateArgumentList *NewDeducedSugared,
140 TemplateArgumentList *NewDeducedCanonical) {
141 DeducedSugared = NewDeducedSugared;
142 DeducedCanonical = NewDeducedCanonical;
143 }
144
145 /// Is a SFINAE diagnostic available?
146 bool hasSFINAEDiagnostic() const {
147 return HasSFINAEDiagnostic;
148 }
149
150 /// Set the diagnostic which caused the SFINAE failure.
151 void addSFINAEDiagnostic(SourceLocation Loc, PartialDiagnostic PD) {
152 // Only collect the first diagnostic.
153 if (HasSFINAEDiagnostic)
154 return;
155 SuppressedDiagnostics.clear();
156 SuppressedDiagnostics.emplace_back(Args&: Loc, Args: std::move(PD));
157 HasSFINAEDiagnostic = true;
158 }
159
160 /// Add a new diagnostic to the set of diagnostics
161 void addSuppressedDiagnostic(SourceLocation Loc,
162 PartialDiagnostic PD) {
163 if (HasSFINAEDiagnostic)
164 return;
165 SuppressedDiagnostics.emplace_back(Args&: Loc, Args: std::move(PD));
166 }
167
168 /// Iterator over the set of suppressed diagnostics.
169 using diag_iterator = SmallVectorImpl<PartialDiagnosticAt>::const_iterator;
170
171 /// Returns an iterator at the beginning of the sequence of suppressed
172 /// diagnostics.
173 diag_iterator diag_begin() const { return SuppressedDiagnostics.begin(); }
174
175 /// Returns an iterator at the end of the sequence of suppressed
176 /// diagnostics.
177 diag_iterator diag_end() const { return SuppressedDiagnostics.end(); }
178
179 /// The template parameter to which a template argument
180 /// deduction failure refers.
181 ///
182 /// Depending on the result of template argument deduction, this
183 /// template parameter may have different meanings:
184 ///
185 /// TDK_Incomplete: this is the first template parameter whose
186 /// corresponding template argument was not deduced.
187 ///
188 /// TDK_IncompletePack: this is the expanded parameter pack for
189 /// which we deduced too few arguments.
190 ///
191 /// TDK_Inconsistent: this is the template parameter for which
192 /// two different template argument values were deduced.
193 TemplateParameter Param;
194
195 /// The first template argument to which the template
196 /// argument deduction failure refers.
197 ///
198 /// Depending on the result of the template argument deduction,
199 /// this template argument may have different meanings:
200 ///
201 /// TDK_IncompletePack: this is the number of arguments we deduced
202 /// for the pack.
203 ///
204 /// TDK_Inconsistent: this argument is the first value deduced
205 /// for the corresponding template parameter.
206 ///
207 /// TDK_SubstitutionFailure: this argument is the template
208 /// argument we were instantiating when we encountered an error.
209 ///
210 /// TDK_DeducedMismatch: this is the parameter type, after substituting
211 /// deduced arguments.
212 ///
213 /// TDK_NonDeducedMismatch: this is the component of the 'parameter'
214 /// of the deduction, directly provided in the source code.
215 TemplateArgument FirstArg;
216
217 /// The second template argument to which the template
218 /// argument deduction failure refers.
219 ///
220 /// TDK_Inconsistent: this argument is the second value deduced
221 /// for the corresponding template parameter.
222 ///
223 /// TDK_DeducedMismatch: this is the (adjusted) call argument type.
224 ///
225 /// TDK_NonDeducedMismatch: this is the mismatching component of the
226 /// 'argument' of the deduction, from which we are deducing arguments.
227 ///
228 /// FIXME: Finish documenting this.
229 TemplateArgument SecondArg;
230
231 /// The index of the function argument that caused a deduction
232 /// failure.
233 ///
234 /// TDK_DeducedMismatch: this is the index of the argument that had a
235 /// different argument type from its substituted parameter type.
236 unsigned CallArgIndex = 0;
237
238 // C++20 [over.match.class.deduct]p5.2:
239 // During template argument deduction for the aggregate deduction
240 // candidate, the number of elements in a trailing parameter pack is only
241 // deduced from the number of remaining function arguments if it is not
242 // otherwise deduced.
243 bool AggregateDeductionCandidateHasMismatchedArity = false;
244
245 /// Information on packs that we're currently expanding.
246 ///
247 /// FIXME: This should be kept internal to SemaTemplateDeduction.
248 SmallVector<DeducedPack *, 8> PendingDeducedPacks;
249
250 /// \brief The constraint satisfaction details resulting from the associated
251 /// constraints satisfaction tests.
252 ConstraintSatisfaction AssociatedConstraintsSatisfaction;
253};
254
255} // namespace sema
256
257/// A structure used to record information about a failed
258/// template argument deduction, for diagnosis.
259struct DeductionFailureInfo {
260 /// A Sema::TemplateDeductionResult.
261 unsigned Result : 8;
262
263 /// Indicates whether a diagnostic is stored in Diagnostic.
264 unsigned HasDiagnostic : 1;
265
266 /// Opaque pointer containing additional data about
267 /// this deduction failure.
268 void *Data;
269
270 /// A diagnostic indicating why deduction failed.
271 alignas(PartialDiagnosticAt) char Diagnostic[sizeof(PartialDiagnosticAt)];
272
273 /// Retrieve the diagnostic which caused this deduction failure,
274 /// if any.
275 PartialDiagnosticAt *getSFINAEDiagnostic();
276
277 /// Retrieve the template parameter this deduction failure
278 /// refers to, if any.
279 TemplateParameter getTemplateParameter();
280
281 /// Retrieve the template argument list associated with this
282 /// deduction failure, if any.
283 TemplateArgumentList *getTemplateArgumentList();
284
285 /// Return the first template argument this deduction failure
286 /// refers to, if any.
287 const TemplateArgument *getFirstArg();
288
289 /// Return the second template argument this deduction failure
290 /// refers to, if any.
291 const TemplateArgument *getSecondArg();
292
293 /// Return the index of the call argument that this deduction
294 /// failure refers to, if any.
295 std::optional<unsigned> getCallArgIndex();
296
297 /// Free any memory associated with this deduction failure.
298 void Destroy();
299
300 TemplateDeductionResult getResult() const {
301 return static_cast<TemplateDeductionResult>(Result);
302 }
303};
304
305/// TemplateSpecCandidate - This is a generalization of OverloadCandidate
306/// which keeps track of template argument deduction failure info, when
307/// handling explicit specializations (and instantiations) of templates
308/// beyond function overloading.
309/// For now, assume that the candidates are non-matching specializations.
310/// TODO: In the future, we may need to unify/generalize this with
311/// OverloadCandidate.
312struct TemplateSpecCandidate {
313 /// The declaration that was looked up, together with its access.
314 /// Might be a UsingShadowDecl, but usually a FunctionTemplateDecl.
315 DeclAccessPair FoundDecl;
316
317 /// Specialization - The actual specialization that this candidate
318 /// represents. When NULL, this may be a built-in candidate.
319 Decl *Specialization;
320
321 /// Template argument deduction info
322 DeductionFailureInfo DeductionFailure;
323
324 void set(DeclAccessPair Found, Decl *Spec, DeductionFailureInfo Info) {
325 FoundDecl = Found;
326 Specialization = Spec;
327 DeductionFailure = Info;
328 }
329
330 /// Diagnose a template argument deduction failure.
331 void NoteDeductionFailure(Sema &S, bool ForTakingAddress);
332};
333
334/// TemplateSpecCandidateSet - A set of generalized overload candidates,
335/// used in template specializations.
336/// TODO: In the future, we may need to unify/generalize this with
337/// OverloadCandidateSet.
338class TemplateSpecCandidateSet {
339 SmallVector<TemplateSpecCandidate, 16> Candidates;
340 SourceLocation Loc;
341
342 // Stores whether we're taking the address of these candidates. This helps us
343 // produce better error messages when dealing with the pass_object_size
344 // attribute on parameters.
345 bool ForTakingAddress;
346
347 void destroyCandidates();
348
349public:
350 TemplateSpecCandidateSet(SourceLocation Loc, bool ForTakingAddress = false)
351 : Loc(Loc), ForTakingAddress(ForTakingAddress) {}
352 TemplateSpecCandidateSet(const TemplateSpecCandidateSet &) = delete;
353 TemplateSpecCandidateSet &
354 operator=(const TemplateSpecCandidateSet &) = delete;
355 ~TemplateSpecCandidateSet() { destroyCandidates(); }
356
357 SourceLocation getLocation() const { return Loc; }
358
359 /// Clear out all of the candidates.
360 /// TODO: This may be unnecessary.
361 void clear();
362
363 using iterator = SmallVector<TemplateSpecCandidate, 16>::iterator;
364
365 iterator begin() { return Candidates.begin(); }
366 iterator end() { return Candidates.end(); }
367
368 size_t size() const { return Candidates.size(); }
369 bool empty() const { return Candidates.empty(); }
370
371 /// Add a new candidate with NumConversions conversion sequence slots
372 /// to the overload set.
373 TemplateSpecCandidate &addCandidate() {
374 Candidates.emplace_back();
375 return Candidates.back();
376 }
377
378 void NoteCandidates(Sema &S, SourceLocation Loc);
379
380 void NoteCandidates(Sema &S, SourceLocation Loc) const {
381 const_cast<TemplateSpecCandidateSet *>(this)->NoteCandidates(S, Loc);
382 }
383};
384
385} // namespace clang
386
387#endif // LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H
388

source code of clang/include/clang/Sema/TemplateDeduction.h