TemplateBase.h revision 360784
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(const 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
705inline const TemplateArgument &AutoType::getArg(unsigned Idx) const {
706  assert(Idx < getNumArgs() && "Template argument out of range");
707  return getArgs()[Idx];
708}
709
710} // namespace clang
711
712#endif // LLVM_CLANG_AST_TEMPLATEBASE_H
713