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 31 namespace clang { 32 33 class Decl; 34 struct DeducedPack; 35 class Sema; 36 enum class TemplateDeductionResult; 37 38 namespace sema { 39 40 /// Provides information about an attempted template argument 41 /// deduction, whose success or failure was described by a 42 /// TemplateDeductionResult value. 43 class 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 65 public: 66 TemplateDeductionInfo(SourceLocation Loc, unsigned DeducedDepth = 0) Loc(Loc)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. TemplateDeductionInfo(ForBaseTag,const TemplateDeductionInfo & Info)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. getLocation()80 SourceLocation getLocation() const { 81 return Loc; 82 } 83 84 /// The depth of template parameters for which deduction is being 85 /// performed. getDeducedDepth()86 unsigned getDeducedDepth() const { 87 return DeducedDepth; 88 } 89 90 /// Get the number of explicitly-specified arguments. getNumExplicitArgs()91 unsigned getNumExplicitArgs() const { 92 return ExplicitArgs; 93 } 94 95 /// Take ownership of the deduced template argument lists. takeSugared()96 TemplateArgumentList *takeSugared() { 97 TemplateArgumentList *Result = DeducedSugared; 98 DeducedSugared = nullptr; 99 return Result; 100 } takeCanonical()101 TemplateArgumentList *takeCanonical() { 102 TemplateArgumentList *Result = DeducedCanonical; 103 DeducedCanonical = nullptr; 104 return Result; 105 } 106 107 /// Take ownership of the SFINAE diagnostic. takeSFINAEDiagnostic(PartialDiagnosticAt & PD)108 void takeSFINAEDiagnostic(PartialDiagnosticAt &PD) { 109 assert(HasSFINAEDiagnostic); 110 PD.first = SuppressedDiagnostics.front().first; 111 PD.second.swap(SuppressedDiagnostics.front().second); 112 clearSFINAEDiagnostic(); 113 } 114 115 /// Discard any SFINAE diagnostics. clearSFINAEDiagnostic()116 void clearSFINAEDiagnostic() { 117 SuppressedDiagnostics.clear(); 118 HasSFINAEDiagnostic = false; 119 } 120 121 /// Peek at the SFINAE diagnostic. peekSFINAEDiagnostic()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. setExplicitArgs(TemplateArgumentList * NewDeducedSugared,TemplateArgumentList * NewDeducedCanonical)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. reset(TemplateArgumentList * NewDeducedSugared,TemplateArgumentList * NewDeducedCanonical)139 void reset(TemplateArgumentList *NewDeducedSugared, 140 TemplateArgumentList *NewDeducedCanonical) { 141 DeducedSugared = NewDeducedSugared; 142 DeducedCanonical = NewDeducedCanonical; 143 } 144 145 /// Is a SFINAE diagnostic available? hasSFINAEDiagnostic()146 bool hasSFINAEDiagnostic() const { 147 return HasSFINAEDiagnostic; 148 } 149 150 /// Set the diagnostic which caused the SFINAE failure. addSFINAEDiagnostic(SourceLocation Loc,PartialDiagnostic PD)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(Loc, std::move(PD)); 157 HasSFINAEDiagnostic = true; 158 } 159 160 /// Add a new diagnostic to the set of diagnostics addSuppressedDiagnostic(SourceLocation Loc,PartialDiagnostic PD)161 void addSuppressedDiagnostic(SourceLocation Loc, 162 PartialDiagnostic PD) { 163 if (HasSFINAEDiagnostic) 164 return; 165 SuppressedDiagnostics.emplace_back(Loc, 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. diag_begin()173 diag_iterator diag_begin() const { return SuppressedDiagnostics.begin(); } 174 175 /// Returns an iterator at the end of the sequence of suppressed 176 /// diagnostics. diag_end()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. 259 struct 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 getResultDeductionFailureInfo300 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. 312 struct 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 setTemplateSpecCandidate324 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. 338 class 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 349 public: 350 TemplateSpecCandidateSet(SourceLocation Loc, bool ForTakingAddress = false) Loc(Loc)351 : Loc(Loc), ForTakingAddress(ForTakingAddress) {} 352 TemplateSpecCandidateSet(const TemplateSpecCandidateSet &) = delete; 353 TemplateSpecCandidateSet & 354 operator=(const TemplateSpecCandidateSet &) = delete; ~TemplateSpecCandidateSet()355 ~TemplateSpecCandidateSet() { destroyCandidates(); } 356 getLocation()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 begin()365 iterator begin() { return Candidates.begin(); } end()366 iterator end() { return Candidates.end(); } 367 size()368 size_t size() const { return Candidates.size(); } empty()369 bool empty() const { return Candidates.empty(); } 370 371 /// Add a new candidate with NumConversions conversion sequence slots 372 /// to the overload set. addCandidate()373 TemplateSpecCandidate &addCandidate() { 374 Candidates.emplace_back(); 375 return Candidates.back(); 376 } 377 378 void NoteCandidates(Sema &S, SourceLocation Loc); 379 NoteCandidates(Sema & S,SourceLocation Loc)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