• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/Type.h"
19 #include "clang/AST/TemplateName.h"
20 #include "llvm/ADT/APSInt.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/Support/Compiler.h"
23 #include "llvm/Support/ErrorHandling.h"
24 
25 namespace llvm {
26   class FoldingSetNodeID;
27 }
28 
29 namespace clang {
30 
31 class Decl;
32 class DiagnosticBuilder;
33 class Expr;
34 struct PrintingPolicy;
35 class TypeSourceInfo;
36 
37 /// \brief Represents a template argument within a class template
38 /// specialization.
39 class TemplateArgument {
40 public:
41   /// \brief The kind of template argument we're storing.
42   enum ArgKind {
43     /// \brief Represents an empty template argument, e.g., one that has not
44     /// been deduced.
45     Null = 0,
46     /// The template argument is a type. Its value is stored in the
47     /// TypeOrValue field.
48     Type,
49     /// The template argument is a declaration that was provided for a pointer
50     /// or reference non-type template parameter.
51     Declaration,
52     /// The template argument is an integral value stored in an llvm::APSInt
53     /// that was provided for an integral non-type template parameter.
54     Integral,
55     /// The template argument is a template name that was provided for a
56     /// template template parameter.
57     Template,
58     /// The template argument is a pack expansion of a template name that was
59     /// provided for a template template parameter.
60     TemplateExpansion,
61     /// The template argument is a value- or type-dependent expression
62     /// stored in an Expr*.
63     Expression,
64     /// The template argument is actually a parameter pack. Arguments are stored
65     /// in the Args struct.
66     Pack
67   };
68 
69 private:
70   /// \brief The kind of template argument we're storing.
71   unsigned Kind;
72 
73   union {
74     uintptr_t TypeOrValue;
75     struct {
76       // We store a decomposed APSInt with the data allocated by ASTContext if
77       // BitWidth > 64. The memory may be shared between multiple
78       // TemplateArgument instances.
79       union {
80         uint64_t VAL;          ///< Used to store the <= 64 bits integer value.
81         const uint64_t *pVal;  ///< Used to store the >64 bits integer value.
82       };
83       unsigned BitWidth : 31;
84       unsigned IsUnsigned : 1;
85       void *Type;
86     } Integer;
87     struct {
88       const TemplateArgument *Args;
89       unsigned NumArgs;
90     } Args;
91     struct {
92       void *Name;
93       unsigned NumExpansions;
94     } TemplateArg;
95   };
96 
97   TemplateArgument(TemplateName, bool); // DO NOT USE
98 
99 public:
100   /// \brief Construct an empty, invalid template argument.
TemplateArgument()101   TemplateArgument() : Kind(Null), TypeOrValue(0) { }
102 
103   /// \brief Construct a template type argument.
TemplateArgument(QualType T)104   TemplateArgument(QualType T) : Kind(Type) {
105     TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
106   }
107 
108   /// \brief Construct a template argument that refers to a
109   /// declaration, which is either an external declaration or a
110   /// template declaration.
TemplateArgument(Decl * D)111   TemplateArgument(Decl *D) : Kind(Declaration) {
112     TypeOrValue = reinterpret_cast<uintptr_t>(D);
113   }
114 
115   /// \brief Construct an integral constant template argument. The memory to
116   /// store the value is allocated with Ctx.
117   TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type);
118 
119   /// \brief Construct an integral constant template argument with the same
120   /// value as Other but a different type.
TemplateArgument(const TemplateArgument & Other,QualType Type)121   TemplateArgument(const TemplateArgument &Other, QualType Type)
122     : Kind(Integral) {
123     Integer = Other.Integer;
124     Integer.Type = Type.getAsOpaquePtr();
125   }
126 
127   /// \brief Construct a template argument that is a template.
128   ///
129   /// This form of template argument is generally used for template template
130   /// parameters. However, the template name could be a dependent template
131   /// name that ends up being instantiated to a function template whose address
132   /// is taken.
133   ///
134   /// \param Name The template name.
TemplateArgument(TemplateName Name)135   TemplateArgument(TemplateName Name) : Kind(Template)
136   {
137     TemplateArg.Name = Name.getAsVoidPointer();
138     TemplateArg.NumExpansions = 0;
139   }
140 
141   /// \brief Construct a template argument that is a template pack expansion.
142   ///
143   /// This form of template argument is generally used for template template
144   /// parameters. However, the template name could be a dependent template
145   /// name that ends up being instantiated to a function template whose address
146   /// is taken.
147   ///
148   /// \param Name The template name.
149   ///
150   /// \param NumExpansions The number of expansions that will be generated by
151   /// instantiating
TemplateArgument(TemplateName Name,llvm::Optional<unsigned> NumExpansions)152   TemplateArgument(TemplateName Name, llvm::Optional<unsigned> NumExpansions)
153     : Kind(TemplateExpansion)
154   {
155     TemplateArg.Name = Name.getAsVoidPointer();
156     if (NumExpansions)
157       TemplateArg.NumExpansions = *NumExpansions + 1;
158     else
159       TemplateArg.NumExpansions = 0;
160   }
161 
162   /// \brief Construct a template argument that is an expression.
163   ///
164   /// This form of template argument only occurs in template argument
165   /// lists used for dependent types and for expression; it will not
166   /// occur in a non-dependent, canonical template argument list.
TemplateArgument(Expr * E)167   TemplateArgument(Expr *E) : Kind(Expression) {
168     TypeOrValue = reinterpret_cast<uintptr_t>(E);
169   }
170 
171   /// \brief Construct a template argument that is a template argument pack.
172   ///
173   /// We assume that storage for the template arguments provided
174   /// outlives the TemplateArgument itself.
TemplateArgument(const TemplateArgument * Args,unsigned NumArgs)175   TemplateArgument(const TemplateArgument *Args, unsigned NumArgs) : Kind(Pack){
176     this->Args.Args = Args;
177     this->Args.NumArgs = NumArgs;
178   }
179 
180   /// \brief Create a new template argument pack by copying the given set of
181   /// template arguments.
182   static TemplateArgument CreatePackCopy(ASTContext &Context,
183                                          const TemplateArgument *Args,
184                                          unsigned NumArgs);
185 
186   /// \brief Return the kind of stored template argument.
getKind()187   ArgKind getKind() const { return (ArgKind)Kind; }
188 
189   /// \brief Determine whether this template argument has no value.
isNull()190   bool isNull() const { return Kind == Null; }
191 
192   /// \brief Whether this template argument is dependent on a template
193   /// parameter such that its result can change from one instantiation to
194   /// another.
195   bool isDependent() const;
196 
197   /// \brief Whether this template argument is dependent on a template
198   /// parameter.
199   bool isInstantiationDependent() const;
200 
201   /// \brief Whether this template argument contains an unexpanded
202   /// parameter pack.
203   bool containsUnexpandedParameterPack() const;
204 
205   /// \brief Determine whether this template argument is a pack expansion.
206   bool isPackExpansion() const;
207 
208   /// \brief Retrieve the template argument as a type.
getAsType()209   QualType getAsType() const {
210     if (Kind != Type)
211       return QualType();
212 
213     return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue));
214   }
215 
216   /// \brief Retrieve the template argument as a declaration.
getAsDecl()217   Decl *getAsDecl() const {
218     if (Kind != Declaration)
219       return 0;
220     return reinterpret_cast<Decl *>(TypeOrValue);
221   }
222 
223   /// \brief Retrieve the template argument as a template name.
getAsTemplate()224   TemplateName getAsTemplate() const {
225     if (Kind != Template)
226       return TemplateName();
227 
228     return TemplateName::getFromVoidPointer(TemplateArg.Name);
229   }
230 
231   /// \brief Retrieve the template argument as a template name; if the argument
232   /// is a pack expansion, return the pattern as a template name.
getAsTemplateOrTemplatePattern()233   TemplateName getAsTemplateOrTemplatePattern() const {
234     if (Kind != Template && Kind != TemplateExpansion)
235       return TemplateName();
236 
237     return TemplateName::getFromVoidPointer(TemplateArg.Name);
238   }
239 
240   /// \brief Retrieve the number of expansions that a template template argument
241   /// expansion will produce, if known.
242   llvm::Optional<unsigned> getNumTemplateExpansions() const;
243 
244   /// \brief Retrieve the template argument as an integral value.
245   // FIXME: Provide a way to read the integral data without copying the value.
getAsIntegral()246   llvm::APSInt getAsIntegral() const {
247     using namespace llvm;
248     if (Integer.BitWidth <= 64)
249       return APSInt(APInt(Integer.BitWidth, Integer.VAL), Integer.IsUnsigned);
250 
251     unsigned NumWords = APInt::getNumWords(Integer.BitWidth);
252     return APSInt(APInt(Integer.BitWidth, makeArrayRef(Integer.pVal, NumWords)),
253                   Integer.IsUnsigned);
254   }
255 
256   /// \brief Retrieve the type of the integral value.
getIntegralType()257   QualType getIntegralType() const {
258     if (Kind != Integral)
259       return QualType();
260 
261     return QualType::getFromOpaquePtr(Integer.Type);
262   }
263 
setIntegralType(QualType T)264   void setIntegralType(QualType T) {
265     assert(Kind == Integral &&
266            "Cannot set the integral type of a non-integral template argument");
267     Integer.Type = T.getAsOpaquePtr();
268   }
269 
270   /// \brief Retrieve the template argument as an expression.
getAsExpr()271   Expr *getAsExpr() const {
272     if (Kind != Expression)
273       return 0;
274 
275     return reinterpret_cast<Expr *>(TypeOrValue);
276   }
277 
278   /// \brief Iterator that traverses the elements of a template argument pack.
279   typedef const TemplateArgument * pack_iterator;
280 
281   /// \brief Iterator referencing the first argument of a template argument
282   /// pack.
pack_begin()283   pack_iterator pack_begin() const {
284     assert(Kind == Pack);
285     return Args.Args;
286   }
287 
288   /// \brief Iterator referencing one past the last argument of a template
289   /// argument pack.
pack_end()290   pack_iterator pack_end() const {
291     assert(Kind == Pack);
292     return Args.Args + Args.NumArgs;
293   }
294 
295   /// \brief The number of template arguments in the given template argument
296   /// pack.
pack_size()297   unsigned pack_size() const {
298     assert(Kind == Pack);
299     return Args.NumArgs;
300   }
301 
302   /// \brief Determines whether two template arguments are superficially the
303   /// same.
304   bool structurallyEquals(const TemplateArgument &Other) const;
305 
306   /// \brief When the template argument is a pack expansion, returns
307   /// the pattern of the pack expansion.
308   TemplateArgument getPackExpansionPattern() const;
309 
310   /// \brief Print this template argument to the given output stream.
311   void print(const PrintingPolicy &Policy, raw_ostream &Out) const;
312 
313   /// \brief Used to insert TemplateArguments into FoldingSets.
314   void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;
315 };
316 
317 /// Location information for a TemplateArgument.
318 struct TemplateArgumentLocInfo {
319 private:
320   union {
321     Expr *Expression;
322     TypeSourceInfo *Declarator;
323     struct {
324       // FIXME: We'd like to just use the qualifier in the TemplateName,
325       // but template arguments get canonicalized too quickly.
326       NestedNameSpecifier *Qualifier;
327       void *QualifierLocData;
328       unsigned TemplateNameLoc;
329       unsigned EllipsisLoc;
330     } Template;
331   };
332 
333 public:
334   TemplateArgumentLocInfo();
335 
TemplateArgumentLocInfoTemplateArgumentLocInfo336   TemplateArgumentLocInfo(TypeSourceInfo *TInfo) : Declarator(TInfo) {}
337 
TemplateArgumentLocInfoTemplateArgumentLocInfo338   TemplateArgumentLocInfo(Expr *E) : Expression(E) {}
339 
TemplateArgumentLocInfoTemplateArgumentLocInfo340   TemplateArgumentLocInfo(NestedNameSpecifierLoc QualifierLoc,
341                           SourceLocation TemplateNameLoc,
342                           SourceLocation EllipsisLoc)
343   {
344     Template.Qualifier = QualifierLoc.getNestedNameSpecifier();
345     Template.QualifierLocData = QualifierLoc.getOpaqueData();
346     Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding();
347     Template.EllipsisLoc = EllipsisLoc.getRawEncoding();
348   }
349 
getAsTypeSourceInfoTemplateArgumentLocInfo350   TypeSourceInfo *getAsTypeSourceInfo() const {
351     return Declarator;
352   }
353 
getAsExprTemplateArgumentLocInfo354   Expr *getAsExpr() const {
355     return Expression;
356   }
357 
getTemplateQualifierLocTemplateArgumentLocInfo358   NestedNameSpecifierLoc getTemplateQualifierLoc() const {
359     return NestedNameSpecifierLoc(Template.Qualifier,
360                                   Template.QualifierLocData);
361   }
362 
getTemplateNameLocTemplateArgumentLocInfo363   SourceLocation getTemplateNameLoc() const {
364     return SourceLocation::getFromRawEncoding(Template.TemplateNameLoc);
365   }
366 
getTemplateEllipsisLocTemplateArgumentLocInfo367   SourceLocation getTemplateEllipsisLoc() const {
368     return SourceLocation::getFromRawEncoding(Template.EllipsisLoc);
369   }
370 };
371 
372 /// Location wrapper for a TemplateArgument.  TemplateArgument is to
373 /// TemplateArgumentLoc as Type is to TypeLoc.
374 class TemplateArgumentLoc {
375   TemplateArgument Argument;
376   TemplateArgumentLocInfo LocInfo;
377 
378 public:
TemplateArgumentLoc()379   TemplateArgumentLoc() {}
380 
TemplateArgumentLoc(const TemplateArgument & Argument,TemplateArgumentLocInfo Opaque)381   TemplateArgumentLoc(const TemplateArgument &Argument,
382                       TemplateArgumentLocInfo Opaque)
383     : Argument(Argument), LocInfo(Opaque) {
384   }
385 
TemplateArgumentLoc(const TemplateArgument & Argument,TypeSourceInfo * TInfo)386   TemplateArgumentLoc(const TemplateArgument &Argument, TypeSourceInfo *TInfo)
387     : Argument(Argument), LocInfo(TInfo) {
388     assert(Argument.getKind() == TemplateArgument::Type);
389   }
390 
TemplateArgumentLoc(const TemplateArgument & Argument,Expr * E)391   TemplateArgumentLoc(const TemplateArgument &Argument, Expr *E)
392     : Argument(Argument), LocInfo(E) {
393     assert(Argument.getKind() == TemplateArgument::Expression);
394   }
395 
396   TemplateArgumentLoc(const TemplateArgument &Argument,
397                       NestedNameSpecifierLoc QualifierLoc,
398                       SourceLocation TemplateNameLoc,
399                       SourceLocation EllipsisLoc = SourceLocation())
Argument(Argument)400     : Argument(Argument), LocInfo(QualifierLoc, TemplateNameLoc, EllipsisLoc) {
401     assert(Argument.getKind() == TemplateArgument::Template ||
402            Argument.getKind() == TemplateArgument::TemplateExpansion);
403   }
404 
405   /// \brief - Fetches the primary location of the argument.
getLocation()406   SourceLocation getLocation() const {
407     if (Argument.getKind() == TemplateArgument::Template ||
408         Argument.getKind() == TemplateArgument::TemplateExpansion)
409       return getTemplateNameLoc();
410 
411     return getSourceRange().getBegin();
412   }
413 
414   /// \brief - Fetches the full source range of the argument.
415   SourceRange getSourceRange() const LLVM_READONLY;
416 
getArgument()417   const TemplateArgument &getArgument() const {
418     return Argument;
419   }
420 
getLocInfo()421   TemplateArgumentLocInfo getLocInfo() const {
422     return LocInfo;
423   }
424 
getTypeSourceInfo()425   TypeSourceInfo *getTypeSourceInfo() const {
426     assert(Argument.getKind() == TemplateArgument::Type);
427     return LocInfo.getAsTypeSourceInfo();
428   }
429 
getSourceExpression()430   Expr *getSourceExpression() const {
431     assert(Argument.getKind() == TemplateArgument::Expression);
432     return LocInfo.getAsExpr();
433   }
434 
getSourceDeclExpression()435   Expr *getSourceDeclExpression() const {
436     assert(Argument.getKind() == TemplateArgument::Declaration);
437     return LocInfo.getAsExpr();
438   }
439 
getTemplateQualifierLoc()440   NestedNameSpecifierLoc getTemplateQualifierLoc() const {
441     assert(Argument.getKind() == TemplateArgument::Template ||
442            Argument.getKind() == TemplateArgument::TemplateExpansion);
443     return LocInfo.getTemplateQualifierLoc();
444   }
445 
getTemplateNameLoc()446   SourceLocation getTemplateNameLoc() const {
447     assert(Argument.getKind() == TemplateArgument::Template ||
448            Argument.getKind() == TemplateArgument::TemplateExpansion);
449     return LocInfo.getTemplateNameLoc();
450   }
451 
getTemplateEllipsisLoc()452   SourceLocation getTemplateEllipsisLoc() const {
453     assert(Argument.getKind() == TemplateArgument::TemplateExpansion);
454     return LocInfo.getTemplateEllipsisLoc();
455   }
456 
457   /// \brief When the template argument is a pack expansion, returns
458   /// the pattern of the pack expansion.
459   ///
460   /// \param Ellipsis Will be set to the location of the ellipsis.
461   ///
462   /// \param NumExpansions Will be set to the number of expansions that will
463   /// be generated from this pack expansion, if known a priori.
464   TemplateArgumentLoc getPackExpansionPattern(SourceLocation &Ellipsis,
465                                         llvm::Optional<unsigned> &NumExpansions,
466                                               ASTContext &Context) const;
467 };
468 
469 /// A convenient class for passing around template argument
470 /// information.  Designed to be passed by reference.
471 class TemplateArgumentListInfo {
472   SmallVector<TemplateArgumentLoc, 8> Arguments;
473   SourceLocation LAngleLoc;
474   SourceLocation RAngleLoc;
475 
476   // This can leak if used in an AST node, use ASTTemplateArgumentListInfo
477   // instead.
478   void* operator new(size_t bytes, ASTContext& C);
479 
480 public:
TemplateArgumentListInfo()481   TemplateArgumentListInfo() {}
482 
TemplateArgumentListInfo(SourceLocation LAngleLoc,SourceLocation RAngleLoc)483   TemplateArgumentListInfo(SourceLocation LAngleLoc,
484                            SourceLocation RAngleLoc)
485     : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {}
486 
getLAngleLoc()487   SourceLocation getLAngleLoc() const { return LAngleLoc; }
getRAngleLoc()488   SourceLocation getRAngleLoc() const { return RAngleLoc; }
489 
setLAngleLoc(SourceLocation Loc)490   void setLAngleLoc(SourceLocation Loc) { LAngleLoc = Loc; }
setRAngleLoc(SourceLocation Loc)491   void setRAngleLoc(SourceLocation Loc) { RAngleLoc = Loc; }
492 
size()493   unsigned size() const { return Arguments.size(); }
494 
getArgumentArray()495   const TemplateArgumentLoc *getArgumentArray() const {
496     return Arguments.data();
497   }
498 
499   const TemplateArgumentLoc &operator[](unsigned I) const {
500     return Arguments[I];
501   }
502 
addArgument(const TemplateArgumentLoc & Loc)503   void addArgument(const TemplateArgumentLoc &Loc) {
504     Arguments.push_back(Loc);
505   }
506 };
507 
508 /// \brief Represents an explicit template argument list in C++, e.g.,
509 /// the "<int>" in "sort<int>".
510 /// This is safe to be used inside an AST node, in contrast with
511 /// TemplateArgumentListInfo.
512 struct ASTTemplateArgumentListInfo {
513   /// \brief The source location of the left angle bracket ('<').
514   SourceLocation LAngleLoc;
515 
516   /// \brief The source location of the right angle bracket ('>').
517   SourceLocation RAngleLoc;
518 
519   union {
520     /// \brief The number of template arguments in TemplateArgs.
521     /// The actual template arguments (if any) are stored after the
522     /// ExplicitTemplateArgumentList structure.
523     unsigned NumTemplateArgs;
524 
525     /// Force ASTTemplateArgumentListInfo to the right alignment
526     /// for the following array of TemplateArgumentLocs.
527     void *Aligner;
528   };
529 
530   /// \brief Retrieve the template arguments
getTemplateArgsASTTemplateArgumentListInfo531   TemplateArgumentLoc *getTemplateArgs() {
532     return reinterpret_cast<TemplateArgumentLoc *> (this + 1);
533   }
534 
535   /// \brief Retrieve the template arguments
getTemplateArgsASTTemplateArgumentListInfo536   const TemplateArgumentLoc *getTemplateArgs() const {
537     return reinterpret_cast<const TemplateArgumentLoc *> (this + 1);
538   }
539 
540   const TemplateArgumentLoc &operator[](unsigned I) const {
541     return getTemplateArgs()[I];
542   }
543 
544   static const ASTTemplateArgumentListInfo *Create(ASTContext &C,
545                                           const TemplateArgumentListInfo &List);
546 
547   void initializeFrom(const TemplateArgumentListInfo &List);
548   void initializeFrom(const TemplateArgumentListInfo &List,
549                       bool &Dependent, bool &InstantiationDependent,
550                       bool &ContainsUnexpandedParameterPack);
551   void copyInto(TemplateArgumentListInfo &List) const;
552   static std::size_t sizeFor(unsigned NumTemplateArgs);
553 };
554 
555 /// \brief Extends ASTTemplateArgumentListInfo with the source location
556 /// information for the template keyword; this is used as part of the
557 /// representation of qualified identifiers, such as S<T>::template apply<T>.
558 struct ASTTemplateKWAndArgsInfo : public ASTTemplateArgumentListInfo {
559   typedef ASTTemplateArgumentListInfo Base;
560 
561   // NOTE: the source location of the (optional) template keyword is
562   // stored after all template arguments.
563 
564   /// \brief Get the source location of the template keyword.
getTemplateKeywordLocASTTemplateKWAndArgsInfo565   SourceLocation getTemplateKeywordLoc() const {
566     return *reinterpret_cast<const SourceLocation*>
567       (getTemplateArgs() + NumTemplateArgs);
568   }
569 
570   /// \brief Sets the source location of the template keyword.
setTemplateKeywordLocASTTemplateKWAndArgsInfo571   void setTemplateKeywordLoc(SourceLocation TemplateKWLoc) {
572     *reinterpret_cast<SourceLocation*>
573       (getTemplateArgs() + NumTemplateArgs) = TemplateKWLoc;
574   }
575 
576   static const ASTTemplateKWAndArgsInfo*
577   Create(ASTContext &C, SourceLocation TemplateKWLoc,
578          const TemplateArgumentListInfo &List);
579 
580   void initializeFrom(SourceLocation TemplateKWLoc,
581                       const TemplateArgumentListInfo &List);
582   void initializeFrom(SourceLocation TemplateKWLoc,
583                       const TemplateArgumentListInfo &List,
584                       bool &Dependent, bool &InstantiationDependent,
585                       bool &ContainsUnexpandedParameterPack);
586   void initializeFrom(SourceLocation TemplateKWLoc);
587 
588   static std::size_t sizeFor(unsigned NumTemplateArgs);
589 };
590 
591 const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
592                                     const TemplateArgument &Arg);
593 
594 inline TemplateSpecializationType::iterator
end()595     TemplateSpecializationType::end() const {
596   return getArgs() + getNumArgs();
597 }
598 
599 inline DependentTemplateSpecializationType::iterator
end()600     DependentTemplateSpecializationType::end() const {
601   return getArgs() + getNumArgs();
602 }
603 
604 inline const TemplateArgument &
getArg(unsigned Idx)605     TemplateSpecializationType::getArg(unsigned Idx) const {
606   assert(Idx < getNumArgs() && "Template argument out of range");
607   return getArgs()[Idx];
608 }
609 
610 inline const TemplateArgument &
getArg(unsigned Idx)611     DependentTemplateSpecializationType::getArg(unsigned Idx) const {
612   assert(Idx < getNumArgs() && "Template argument out of range");
613   return getArgs()[Idx];
614 }
615 
616 } // end namespace clang
617 
618 #endif
619