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