1//===- TemplateBase.h - Core classes for C++ templates ----------*- 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 definitions which are common for all kinds of
10// template representation.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_AST_TEMPLATEBASE_H
15#define LLVM_CLANG_AST_TEMPLATEBASE_H
16
17#include "clang/AST/NestedNameSpecifier.h"
18#include "clang/AST/TemplateName.h"
19#include "clang/AST/Type.h"
20#include "clang/Basic/LLVM.h"
21#include "clang/Basic/SourceLocation.h"
22#include "llvm/ADT/APInt.h"
23#include "llvm/ADT/APSInt.h"
24#include "llvm/ADT/ArrayRef.h"
25#include "llvm/ADT/None.h"
26#include "llvm/ADT/Optional.h"
27#include "llvm/ADT/SmallVector.h"
28#include "llvm/Support/Compiler.h"
29#include "llvm/Support/TrailingObjects.h"
30#include <cassert>
31#include <cstddef>
32#include <cstdint>
33
34namespace llvm {
35
36class FoldingSetNodeID;
37
38} // namespace llvm
39
40namespace clang {
41
42class ASTContext;
43class DiagnosticBuilder;
44class Expr;
45struct PrintingPolicy;
46class TypeSourceInfo;
47class ValueDecl;
48
49/// Represents a template argument.
50class TemplateArgument {
51public:
52 /// The kind of template argument we're storing.
53 enum ArgKind {
54 /// Represents an empty template argument, e.g., one that has not
55 /// been deduced.
56 Null = 0,
57
58 /// The template argument is a type.
59 Type,
60
61 /// The template argument is a declaration that was provided for a pointer,
62 /// reference, or pointer to member non-type template parameter.
63 Declaration,
64
65 /// The template argument is a null pointer or null pointer to member that
66 /// was provided for a non-type template parameter.
67 NullPtr,
68
69 /// The template argument is an integral value stored in an llvm::APSInt
70 /// that was provided for an integral non-type template parameter.
71 Integral,
72
73 /// The template argument is a template name that was provided for a
74 /// template template parameter.
75 Template,
76
77 /// The template argument is a pack expansion of a template name that was
78 /// provided for a template template parameter.
79 TemplateExpansion,
80
81 /// The template argument is an expression, and we've not resolved it to one
82 /// of the other forms yet, either because it's dependent or because we're
83 /// representing a non-canonical template argument (for instance, in a
84 /// TemplateSpecializationType). Also used to represent a non-dependent
85 /// __uuidof expression (a Microsoft extension).
86 Expression,
87
88 /// The template argument is actually a parameter pack. Arguments are stored
89 /// in the Args struct.
90 Pack
91 };
92
93private:
94 /// The kind of template argument we're storing.
95
96 struct DA {
97 unsigned Kind;
98 void *QT;
99 ValueDecl *D;
100 };
101 struct I {
102 unsigned Kind;
103 // We store a decomposed APSInt with the data allocated by ASTContext if
104 // BitWidth > 64. The memory may be shared between multiple
105 // TemplateArgument instances.
106 unsigned BitWidth : 31;
107 unsigned IsUnsigned : 1;
108 union {
109 /// Used to store the <= 64 bits integer value.
110 uint64_t VAL;
111
112 /// Used to store the >64 bits integer value.
113 const uint64_t *pVal;
114 };
115 void *Type;
116 };
117 struct A {
118 unsigned Kind;
119 unsigned NumArgs;
120 const TemplateArgument *Args;
121 };
122 struct TA {
123 unsigned Kind;
124 unsigned NumExpansions;
125 void *Name;
126 };
127 struct TV {
128 unsigned Kind;
129 uintptr_t V;
130 };
131 union {
132 struct DA DeclArg;
133 struct I Integer;
134 struct A Args;
135 struct TA TemplateArg;
136 struct TV TypeOrValue;
137 };
138
139public:
140 /// Construct an empty, invalid template argument.
141 constexpr TemplateArgument() : TypeOrValue({Null, 0}) {}
142
143 /// Construct a template type argument.
144 TemplateArgument(QualType T, bool isNullPtr = false) {
145 TypeOrValue.Kind = isNullPtr ? NullPtr : Type;
146 TypeOrValue.V = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
147 }
148
149 /// Construct a template argument that refers to a
150 /// declaration, which is either an external declaration or a
151 /// template declaration.
152 TemplateArgument(ValueDecl *D, QualType QT) {
153 assert(D && "Expected decl");
154 DeclArg.Kind = Declaration;
155 DeclArg.QT = QT.getAsOpaquePtr();
156 DeclArg.D = D;
157 }
158
159 /// Construct an integral constant template argument. The memory to
160 /// store the value is allocated with Ctx.
161 TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type);
162
163 /// Construct an integral constant template argument with the same
164 /// value as Other but a different type.
165 TemplateArgument(const TemplateArgument &Other, QualType Type) {
166 Integer = Other.Integer;
167 Integer.Type = Type.getAsOpaquePtr();
168 }
169
170 /// Construct a template argument that is a template.
171 ///
172 /// This form of template argument is generally used for template template
173 /// parameters. However, the template name could be a dependent template
174 /// name that ends up being instantiated to a function template whose address
175 /// is taken.
176 ///
177 /// \param Name The template name.
178 TemplateArgument(TemplateName Name) {
179 TemplateArg.Kind = Template;
180 TemplateArg.Name = Name.getAsVoidPointer();
181 TemplateArg.NumExpansions = 0;
182 }
183
184 /// Construct a template argument that is a template pack expansion.
185 ///
186 /// This form of template argument is generally used for template template
187 /// parameters. However, the template name could be a dependent template
188 /// name that ends up being instantiated to a function template whose address
189 /// is taken.
190 ///
191 /// \param Name The template name.
192 ///
193 /// \param NumExpansions The number of expansions that will be generated by
194 /// instantiating
195 TemplateArgument(TemplateName Name, Optional<unsigned> NumExpansions) {
196 TemplateArg.Kind = TemplateExpansion;
197 TemplateArg.Name = Name.getAsVoidPointer();
198 if (NumExpansions)
199 TemplateArg.NumExpansions = *NumExpansions + 1;
200 else
201 TemplateArg.NumExpansions = 0;
202 }
203
204 /// Construct a template argument that is an expression.
205 ///
206 /// This form of template argument only occurs in template argument
207 /// lists used for dependent types and for expression; it will not
208 /// occur in a non-dependent, canonical template argument list.
209 TemplateArgument(Expr *E) {
210 TypeOrValue.Kind = Expression;
211 TypeOrValue.V = reinterpret_cast<uintptr_t>(E);
212 }
213
214 /// Construct a template argument that is a template argument pack.
215 ///
216 /// We assume that storage for the template arguments provided
217 /// outlives the TemplateArgument itself.
218 explicit TemplateArgument(ArrayRef<TemplateArgument> Args) {
219 this->Args.Kind = Pack;
220 this->Args.Args = Args.data();
221 this->Args.NumArgs = Args.size();
222 }
223
224 TemplateArgument(TemplateName, bool) = delete;
225
226 static TemplateArgument getEmptyPack() { return TemplateArgument(None); }
227
228 /// Create a new template argument pack by copying the given set of
229 /// template arguments.
230 static TemplateArgument CreatePackCopy(ASTContext &Context,
231 ArrayRef<TemplateArgument> Args);
232
233 /// Return the kind of stored template argument.
234 ArgKind getKind() const { return (ArgKind)TypeOrValue.Kind; }
235
236 /// Determine whether this template argument has no value.
237 bool isNull() const { return getKind() == Null; }
238
239 /// Whether this template argument is dependent on a template
240 /// parameter such that its result can change from one instantiation to
241 /// another.
242 bool isDependent() const;
243
244 /// Whether this template argument is dependent on a template
245 /// parameter.
246 bool isInstantiationDependent() const;
247
248 /// Whether this template argument contains an unexpanded
249 /// parameter pack.
250 bool containsUnexpandedParameterPack() const;
251
252 /// Determine whether this template argument is a pack expansion.
253 bool isPackExpansion() const;
254
255 /// Retrieve the type for a type template argument.
256 QualType getAsType() const {
257 assert(getKind() == Type && "Unexpected kind");
258 return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V));
259 }
260
261 /// Retrieve the declaration for a declaration non-type
262 /// template argument.
263 ValueDecl *getAsDecl() const {
264 assert(getKind() == Declaration && "Unexpected kind");
265 return DeclArg.D;
266 }
267
268 QualType getParamTypeForDecl() const {
269 assert(getKind() == Declaration && "Unexpected kind");
270 return QualType::getFromOpaquePtr(DeclArg.QT);
271 }
272
273 /// Retrieve the type for null non-type template argument.
274 QualType getNullPtrType() const {
275 assert(getKind() == NullPtr && "Unexpected kind");
276 return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V));
277 }
278
279 /// Retrieve the template name for a template name argument.
280 TemplateName getAsTemplate() const {
281 assert(getKind() == Template && "Unexpected kind");
282 return TemplateName::getFromVoidPointer(TemplateArg.Name);
283 }
284
285 /// Retrieve the template argument as a template name; if the argument
286 /// is a pack expansion, return the pattern as a template name.
287 TemplateName getAsTemplateOrTemplatePattern() const {
288 assert((getKind() == Template || getKind() == TemplateExpansion) &&
289 "Unexpected kind");
290
291 return TemplateName::getFromVoidPointer(TemplateArg.Name);
292 }
293
294 /// Retrieve the number of expansions that a template template argument
295 /// expansion will produce, if known.
296 Optional<unsigned> getNumTemplateExpansions() const;
297
298 /// Retrieve the template argument as an integral value.
299 // FIXME: Provide a way to read the integral data without copying the value.
300 llvm::APSInt getAsIntegral() const {
301 assert(getKind() == Integral && "Unexpected kind");
302
303 using namespace llvm;
304
305 if (Integer.BitWidth <= 64)
306 return APSInt(APInt(Integer.BitWidth, Integer.VAL), Integer.IsUnsigned);
307
308 unsigned NumWords = APInt::getNumWords(Integer.BitWidth);
309 return APSInt(APInt(Integer.BitWidth, makeArrayRef(Integer.pVal, NumWords)),
310 Integer.IsUnsigned);
311 }
312
313 /// Retrieve the type of the integral value.
314 QualType getIntegralType() const {
315 assert(getKind() == Integral && "Unexpected kind");
316 return QualType::getFromOpaquePtr(Integer.Type);
317 }
318
319 void setIntegralType(QualType T) {
320 assert(getKind() == Integral && "Unexpected kind");
321 Integer.Type = T.getAsOpaquePtr();
322 }
323
324 /// If this is a non-type template argument, get its type. Otherwise,
325 /// returns a null QualType.
326 QualType getNonTypeTemplateArgumentType() const;
327
328 /// Retrieve the template argument as an expression.
329 Expr *getAsExpr() const {
330 assert(getKind() == Expression && "Unexpected kind");
331 return reinterpret_cast<Expr *>(TypeOrValue.V);
332 }
333
334 /// Iterator that traverses the elements of a template argument pack.
335 using pack_iterator = const TemplateArgument *;
336
337 /// Iterator referencing the first argument of a template argument
338 /// pack.
339 pack_iterator pack_begin() const {
340 assert(getKind() == Pack);
341 return Args.Args;
342 }
343
344 /// Iterator referencing one past the last argument of a template
345 /// argument pack.
346 pack_iterator pack_end() const {
347 assert(getKind() == Pack);
348 return Args.Args + Args.NumArgs;
349 }
350
351 /// Iterator range referencing all of the elements of a template
352 /// argument pack.
353 ArrayRef<TemplateArgument> pack_elements() const {
354 return llvm::makeArrayRef(pack_begin(), pack_end());
355 }
356
357 /// The number of template arguments in the given template argument
358 /// pack.
359 unsigned pack_size() const {
360 assert(getKind() == Pack);
361 return Args.NumArgs;
362 }
363
364 /// Return the array of arguments in this template argument pack.
365 ArrayRef<TemplateArgument> getPackAsArray() const {
366 assert(getKind() == Pack);
367 return llvm::makeArrayRef(Args.Args, Args.NumArgs);
368 }
369
370 /// Determines whether two template arguments are superficially the
371 /// same.
372 bool structurallyEquals(const TemplateArgument &Other) const;
373
374 /// When the template argument is a pack expansion, returns
375 /// the pattern of the pack expansion.
376 TemplateArgument getPackExpansionPattern() const;
377
378 /// Print this template argument to the given output stream.
379 void print(const PrintingPolicy &Policy, raw_ostream &Out) const;
380
381 /// Debugging aid that dumps the template argument.
382 void dump(raw_ostream &Out) const;
383
384 /// Debugging aid that dumps the template argument to standard error.
385 void dump() const;
386
387 /// Used to insert TemplateArguments into FoldingSets.
388 void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;
389};
390
391/// Location information for a TemplateArgument.
392struct TemplateArgumentLocInfo {
393private:
394 struct T {
395 // FIXME: We'd like to just use the qualifier in the TemplateName,
396 // but template arguments get canonicalized too quickly.
397 NestedNameSpecifier *Qualifier;
398 void *QualifierLocData;
399 unsigned TemplateNameLoc;
400 unsigned EllipsisLoc;
401 };
402
403 union {
404 struct T Template;
405 Expr *Expression;
406 TypeSourceInfo *Declarator;
407 };
408
409public:
410 constexpr TemplateArgumentLocInfo() : Template({nullptr, nullptr, 0, 0}) {}
411
412 TemplateArgumentLocInfo(TypeSourceInfo *TInfo) : Declarator(TInfo) {}
413
414 TemplateArgumentLocInfo(Expr *E) : Expression(E) {}
415
416 TemplateArgumentLocInfo(NestedNameSpecifierLoc QualifierLoc,
417 SourceLocation TemplateNameLoc,
418 SourceLocation EllipsisLoc) {
419 Template.Qualifier = QualifierLoc.getNestedNameSpecifier();
420 Template.QualifierLocData = QualifierLoc.getOpaqueData();
421 Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding();
422 Template.EllipsisLoc = EllipsisLoc.getRawEncoding();
423 }
424
425 TypeSourceInfo *getAsTypeSourceInfo() const {
426 return Declarator;
427 }
428
429 Expr *getAsExpr() const {
430 return Expression;
431 }
432
433 NestedNameSpecifierLoc getTemplateQualifierLoc() const {
434 return NestedNameSpecifierLoc(Template.Qualifier,
435 Template.QualifierLocData);
436 }
437
438 SourceLocation getTemplateNameLoc() const {
439 return SourceLocation::getFromRawEncoding(Template.TemplateNameLoc);
440 }
441
442 SourceLocation getTemplateEllipsisLoc() const {
443 return SourceLocation::getFromRawEncoding(Template.EllipsisLoc);
444 }
445};
446
447/// Location wrapper for a TemplateArgument. TemplateArgument is to
448/// TemplateArgumentLoc as Type is to TypeLoc.
449class TemplateArgumentLoc {
450 TemplateArgument Argument;
451 TemplateArgumentLocInfo LocInfo;
452
453public:
454 constexpr TemplateArgumentLoc() {}
455
456 TemplateArgumentLoc(const TemplateArgument &Argument,
457 TemplateArgumentLocInfo Opaque)
458 : Argument(Argument), LocInfo(Opaque) {}
459
460 TemplateArgumentLoc(const TemplateArgument &Argument, TypeSourceInfo *TInfo)
461 : Argument(Argument), LocInfo(TInfo) {
462 assert(Argument.getKind() == TemplateArgument::Type);
463 }
464
465 TemplateArgumentLoc(const TemplateArgument &Argument, Expr *E)
466 : Argument(Argument), LocInfo(E) {
467
468 // Permit any kind of template argument that can be represented with an
469 // expression.
470 assert(Argument.getKind() == TemplateArgument::NullPtr ||
471 Argument.getKind() == TemplateArgument::Integral ||
472 Argument.getKind() == TemplateArgument::Declaration ||
473 Argument.getKind() == TemplateArgument::Expression);
474 }
475
476 TemplateArgumentLoc(const TemplateArgument &Argument,
477 NestedNameSpecifierLoc QualifierLoc,
478 SourceLocation TemplateNameLoc,
479 SourceLocation EllipsisLoc = SourceLocation())
480 : Argument(Argument),
481 LocInfo(QualifierLoc, TemplateNameLoc, EllipsisLoc) {
482 assert(Argument.getKind() == TemplateArgument::Template ||
483 Argument.getKind() == TemplateArgument::TemplateExpansion);
484 }
485
486 /// - Fetches the primary location of the argument.
487 SourceLocation getLocation() const {
488 if (Argument.getKind() == TemplateArgument::Template ||
489 Argument.getKind() == TemplateArgument::TemplateExpansion)
490 return getTemplateNameLoc();
491
492 return getSourceRange().getBegin();
493 }
494
495 /// - Fetches the full source range of the argument.
496 SourceRange getSourceRange() const LLVM_READONLY;
497
498 const TemplateArgument &getArgument() const {
499 return Argument;
500 }
501
502 TemplateArgumentLocInfo getLocInfo() const {
503 return LocInfo;
504 }
505
506 TypeSourceInfo *getTypeSourceInfo() const {
507 assert(Argument.getKind() == TemplateArgument::Type);
508 return LocInfo.getAsTypeSourceInfo();
509 }
510
511 Expr *getSourceExpression() const {
512 assert(Argument.getKind() == TemplateArgument::Expression);
513 return LocInfo.getAsExpr();
514 }
515
516 Expr *getSourceDeclExpression() const {
517 assert(Argument.getKind() == TemplateArgument::Declaration);
518 return LocInfo.getAsExpr();
519 }
520
521 Expr *getSourceNullPtrExpression() const {
522 assert(Argument.getKind() == TemplateArgument::NullPtr);
523 return LocInfo.getAsExpr();
524 }
525
526 Expr *getSourceIntegralExpression() const {
527 assert(Argument.getKind() == TemplateArgument::Integral);
528 return LocInfo.getAsExpr();
529 }
530
531 NestedNameSpecifierLoc getTemplateQualifierLoc() const {
532 if (Argument.getKind() != TemplateArgument::Template &&
533 Argument.getKind() != TemplateArgument::TemplateExpansion)
534 return NestedNameSpecifierLoc();
535 return LocInfo.getTemplateQualifierLoc();
536 }
537
538 SourceLocation getTemplateNameLoc() const {
539 if (Argument.getKind() != TemplateArgument::Template &&
540 Argument.getKind() != TemplateArgument::TemplateExpansion)
541 return SourceLocation();
542 return LocInfo.getTemplateNameLoc();
543 }
544
545 SourceLocation getTemplateEllipsisLoc() const {
546 if (Argument.getKind() != TemplateArgument::TemplateExpansion)
547 return SourceLocation();
548 return LocInfo.getTemplateEllipsisLoc();
549 }
550};
551
552/// A convenient class for passing around template argument
553/// information. Designed to be passed by reference.
554class TemplateArgumentListInfo {
555 SmallVector<TemplateArgumentLoc, 8> Arguments;
556 SourceLocation LAngleLoc;
557 SourceLocation RAngleLoc;
558
559public:
560 TemplateArgumentListInfo() = default;
561
562 TemplateArgumentListInfo(SourceLocation LAngleLoc,
563 SourceLocation RAngleLoc)
564 : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {}
565
566 // This can leak if used in an AST node, use ASTTemplateArgumentListInfo
567 // instead.
568 void *operator new(size_t bytes, ASTContext &C) = delete;
569
570 SourceLocation getLAngleLoc() const { return LAngleLoc; }
571 SourceLocation getRAngleLoc() const { return RAngleLoc; }
572
573 void setLAngleLoc(SourceLocation Loc) { LAngleLoc = Loc; }
574 void setRAngleLoc(SourceLocation Loc) { RAngleLoc = Loc; }
575
576 unsigned size() const { return Arguments.size(); }
577
578 const TemplateArgumentLoc *getArgumentArray() const {
579 return Arguments.data();
580 }
581
582 llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
583 return Arguments;
584 }
585
586 const TemplateArgumentLoc &operator[](unsigned I) const {
587 return Arguments[I];
588 }
589
590 TemplateArgumentLoc &operator[](unsigned I) {
591 return Arguments[I];
592 }
593
594 void addArgument(const TemplateArgumentLoc &Loc) {
595 Arguments.push_back(Loc);
596 }
597};
598
599/// Represents an explicit template argument list in C++, e.g.,
600/// the "<int>" in "sort<int>".
601/// This is safe to be used inside an AST node, in contrast with
602/// TemplateArgumentListInfo.
603struct ASTTemplateArgumentListInfo final
604 : private llvm::TrailingObjects<ASTTemplateArgumentListInfo,
605 TemplateArgumentLoc> {
606private:
607 friend class ASTNodeImporter;
608 friend TrailingObjects;
609
610 ASTTemplateArgumentListInfo(const TemplateArgumentListInfo &List);
611
612public:
613 /// The source location of the left angle bracket ('<').
614 SourceLocation LAngleLoc;
615
616 /// The source location of the right angle bracket ('>').
617 SourceLocation RAngleLoc;
618
619 /// The number of template arguments in TemplateArgs.
620 unsigned NumTemplateArgs;
621
622 SourceLocation getLAngleLoc() const { return LAngleLoc; }
623 SourceLocation getRAngleLoc() const { return RAngleLoc; }
624
625 /// Retrieve the template arguments
626 const TemplateArgumentLoc *getTemplateArgs() const {
627 return getTrailingObjects<TemplateArgumentLoc>();
628 }
629 unsigned getNumTemplateArgs() const { return NumTemplateArgs; }
630
631 llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
632 return llvm::makeArrayRef(getTemplateArgs(), getNumTemplateArgs());
633 }
634
635 const TemplateArgumentLoc &operator[](unsigned I) const {
636 return getTemplateArgs()[I];
637 }
638
639 static const ASTTemplateArgumentListInfo *
640 Create(ASTContext &C, const TemplateArgumentListInfo &List);
641};
642
643/// Represents an explicit template argument list in C++, e.g.,
644/// the "<int>" in "sort<int>".
645///
646/// It is intended to be used as a trailing object on AST nodes, and
647/// as such, doesn't contain the array of TemplateArgumentLoc itself,
648/// but expects the containing object to also provide storage for
649/// that.
650struct alignas(void *) ASTTemplateKWAndArgsInfo {
651 /// The source location of the left angle bracket ('<').
652 SourceLocation LAngleLoc;
653
654 /// The source location of the right angle bracket ('>').
655 SourceLocation RAngleLoc;
656
657 /// The source location of the template keyword; this is used
658 /// as part of the representation of qualified identifiers, such as
659 /// S<T>::template apply<T>. Will be empty if this expression does
660 /// not have a template keyword.
661 SourceLocation TemplateKWLoc;
662
663 /// The number of template arguments in TemplateArgs.
664 unsigned NumTemplateArgs;
665
666 void initializeFrom(SourceLocation TemplateKWLoc,
667 const TemplateArgumentListInfo &List,
668 TemplateArgumentLoc *OutArgArray);
669 void initializeFrom(SourceLocation TemplateKWLoc,
670 const TemplateArgumentListInfo &List,
671 TemplateArgumentLoc *OutArgArray, bool &Dependent,
672 bool &InstantiationDependent,
673 bool &ContainsUnexpandedParameterPack);
674 void initializeFrom(SourceLocation TemplateKWLoc);
675
676 void copyInto(const TemplateArgumentLoc *ArgArray,
677 TemplateArgumentListInfo &List) const;
678};
679
680const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
681 const TemplateArgument &Arg);
682
683inline TemplateSpecializationType::iterator
684 TemplateSpecializationType::end() const {
685 return getArgs() + getNumArgs();
686}
687
688inline DependentTemplateSpecializationType::iterator
689 DependentTemplateSpecializationType::end() const {
690 return getArgs() + getNumArgs();
691}
692
693inline const TemplateArgument &
694 TemplateSpecializationType::getArg(unsigned Idx) const {
695 assert(Idx < getNumArgs() && "Template argument out of range");
696 return getArgs()[Idx];
697}
698
699inline const TemplateArgument &
700 DependentTemplateSpecializationType::getArg(unsigned Idx) const {
701 assert(Idx < getNumArgs() && "Template argument out of range");
702 return getArgs()[Idx];
703}
704
705} // namespace clang
706
707#endif // LLVM_CLANG_AST_TEMPLATEBASE_H
708