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