AttributeList.h revision 5cd532ca0bc1cb8110e24586d064f72332d8b767
1//===--- AttributeList.h - Parsed attribute sets ----------------*- 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 defines the AttributeList class, which is used to collect 11// parsed attributes. 12// 13//===----------------------------------------------------------------------===// 14 15#ifndef LLVM_CLANG_SEMA_ATTRLIST_H 16#define LLVM_CLANG_SEMA_ATTRLIST_H 17 18#include "clang/Basic/SourceLocation.h" 19#include "clang/Basic/VersionTuple.h" 20#include "clang/Sema/Ownership.h" 21#include "llvm/ADT/SmallVector.h" 22#include "llvm/Support/Allocator.h" 23#include <cassert> 24 25namespace clang { 26 class ASTContext; 27 class IdentifierInfo; 28 class Expr; 29 30/// \brief Represents information about a change in availability for 31/// an entity, which is part of the encoding of the 'availability' 32/// attribute. 33struct AvailabilityChange { 34 /// \brief The location of the keyword indicating the kind of change. 35 SourceLocation KeywordLoc; 36 37 /// \brief The version number at which the change occurred. 38 VersionTuple Version; 39 40 /// \brief The source range covering the version number. 41 SourceRange VersionRange; 42 43 /// \brief Determine whether this availability change is valid. 44 bool isValid() const { return !Version.empty(); } 45}; 46 47/// AttributeList - Represents GCC's __attribute__ declaration. There are 48/// 4 forms of this construct...they are: 49/// 50/// 1: __attribute__(( const )). ParmName/Args/NumArgs will all be unused. 51/// 2: __attribute__(( mode(byte) )). ParmName used, Args/NumArgs unused. 52/// 3: __attribute__(( format(printf, 1, 2) )). ParmName/Args/NumArgs all used. 53/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used. 54/// 55class AttributeList { // TODO: This should really be called ParsedAttribute 56public: 57 /// The style used to specify an attribute. 58 enum Syntax { 59 /// __attribute__((...)) 60 AS_GNU, 61 /// [[...]] 62 AS_CXX11, 63 /// __declspec(...) 64 AS_Declspec, 65 /// __ptr16, alignas(...), etc. 66 AS_Keyword 67 }; 68private: 69 IdentifierInfo *AttrName; 70 IdentifierInfo *ScopeName; 71 IdentifierInfo *ParmName; 72 SourceRange AttrRange; 73 SourceLocation ScopeLoc; 74 SourceLocation ParmLoc; 75 76 /// The number of expression arguments this attribute has. 77 /// The expressions themselves are stored after the object. 78 unsigned NumArgs : 16; 79 80 /// Corresponds to the Syntax enum. 81 unsigned SyntaxUsed : 2; 82 83 /// True if already diagnosed as invalid. 84 mutable unsigned Invalid : 1; 85 86 /// True if this attribute was used as a type attribute. 87 mutable unsigned UsedAsTypeAttr : 1; 88 89 /// True if this has the extra information associated with an 90 /// availability attribute. 91 unsigned IsAvailability : 1; 92 93 /// True if this has extra information associated with a 94 /// type_tag_for_datatype attribute. 95 unsigned IsTypeTagForDatatype : 1; 96 97 unsigned AttrKind : 8; 98 99 /// \brief The location of the 'unavailable' keyword in an 100 /// availability attribute. 101 SourceLocation UnavailableLoc; 102 103 const Expr *MessageExpr; 104 105 /// The next attribute in the current position. 106 AttributeList *NextInPosition; 107 108 /// The next attribute allocated in the current Pool. 109 AttributeList *NextInPool; 110 111 Expr **getArgsBuffer() { 112 return reinterpret_cast<Expr**>(this+1); 113 } 114 Expr * const *getArgsBuffer() const { 115 return reinterpret_cast<Expr* const *>(this+1); 116 } 117 118 enum AvailabilitySlot { 119 IntroducedSlot, DeprecatedSlot, ObsoletedSlot 120 }; 121 122 AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) { 123 return reinterpret_cast<AvailabilityChange*>(this+1)[index]; 124 } 125 const AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) const { 126 return reinterpret_cast<const AvailabilityChange*>(this+1)[index]; 127 } 128 129public: 130 struct TypeTagForDatatypeData { 131 ParsedType *MatchingCType; 132 unsigned LayoutCompatible : 1; 133 unsigned MustBeNull : 1; 134 }; 135 136private: 137 TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() { 138 return *reinterpret_cast<TypeTagForDatatypeData *>(this + 1); 139 } 140 141 const TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() const { 142 return *reinterpret_cast<const TypeTagForDatatypeData *>(this + 1); 143 } 144 145 AttributeList(const AttributeList &) LLVM_DELETED_FUNCTION; 146 void operator=(const AttributeList &) LLVM_DELETED_FUNCTION; 147 void operator delete(void *) LLVM_DELETED_FUNCTION; 148 ~AttributeList() LLVM_DELETED_FUNCTION; 149 150 size_t allocated_size() const; 151 152 /// Constructor for attributes with expression arguments. 153 AttributeList(IdentifierInfo *attrName, SourceRange attrRange, 154 IdentifierInfo *scopeName, SourceLocation scopeLoc, 155 IdentifierInfo *parmName, SourceLocation parmLoc, 156 Expr **args, unsigned numArgs, 157 Syntax syntaxUsed) 158 : AttrName(attrName), ScopeName(scopeName), ParmName(parmName), 159 AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), 160 NumArgs(numArgs), SyntaxUsed(syntaxUsed), Invalid(false), 161 UsedAsTypeAttr(false), IsAvailability(false), 162 IsTypeTagForDatatype(false), NextInPosition(0), NextInPool(0) { 163 if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*)); 164 AttrKind = getKind(getName(), getScopeName(), syntaxUsed); 165 } 166 167 /// Constructor for availability attributes. 168 AttributeList(IdentifierInfo *attrName, SourceRange attrRange, 169 IdentifierInfo *scopeName, SourceLocation scopeLoc, 170 IdentifierInfo *parmName, SourceLocation parmLoc, 171 const AvailabilityChange &introduced, 172 const AvailabilityChange &deprecated, 173 const AvailabilityChange &obsoleted, 174 SourceLocation unavailable, 175 const Expr *messageExpr, 176 Syntax syntaxUsed) 177 : AttrName(attrName), ScopeName(scopeName), ParmName(parmName), 178 AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), 179 NumArgs(0), SyntaxUsed(syntaxUsed), 180 Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), 181 IsTypeTagForDatatype(false), 182 UnavailableLoc(unavailable), MessageExpr(messageExpr), 183 NextInPosition(0), NextInPool(0) { 184 new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced); 185 new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated); 186 new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted); 187 AttrKind = getKind(getName(), getScopeName(), syntaxUsed); 188 } 189 190 /// Constructor for type_tag_for_datatype attribute. 191 AttributeList(IdentifierInfo *attrName, SourceRange attrRange, 192 IdentifierInfo *scopeName, SourceLocation scopeLoc, 193 IdentifierInfo *argumentKindName, 194 SourceLocation argumentKindLoc, 195 ParsedType matchingCType, bool layoutCompatible, 196 bool mustBeNull, Syntax syntaxUsed) 197 : AttrName(attrName), ScopeName(scopeName), ParmName(argumentKindName), 198 AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(argumentKindLoc), 199 NumArgs(0), SyntaxUsed(syntaxUsed), 200 Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), 201 IsTypeTagForDatatype(true), NextInPosition(NULL), NextInPool(NULL) { 202 TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot(); 203 new (&ExtraData.MatchingCType) ParsedType(matchingCType); 204 ExtraData.LayoutCompatible = layoutCompatible; 205 ExtraData.MustBeNull = mustBeNull; 206 AttrKind = getKind(getName(), getScopeName(), syntaxUsed); 207 } 208 209 friend class AttributePool; 210 friend class AttributeFactory; 211 212public: 213 enum Kind { 214 #define PARSED_ATTR(NAME) AT_##NAME, 215 #include "clang/Sema/AttrParsedAttrList.inc" 216 #undef PARSED_ATTR 217 IgnoredAttribute, 218 UnknownAttribute 219 }; 220 221 IdentifierInfo *getName() const { return AttrName; } 222 SourceLocation getLoc() const { return AttrRange.getBegin(); } 223 SourceRange getRange() const { return AttrRange; } 224 225 bool hasScope() const { return ScopeName; } 226 IdentifierInfo *getScopeName() const { return ScopeName; } 227 SourceLocation getScopeLoc() const { return ScopeLoc; } 228 229 IdentifierInfo *getParameterName() const { return ParmName; } 230 SourceLocation getParameterLoc() const { return ParmLoc; } 231 232 bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; } 233 bool isCXX11Attribute() const { return SyntaxUsed == AS_CXX11; } 234 bool isKeywordAttribute() const { return SyntaxUsed == AS_Keyword; } 235 236 bool isInvalid() const { return Invalid; } 237 void setInvalid(bool b = true) const { Invalid = b; } 238 239 bool isUsedAsTypeAttr() const { return UsedAsTypeAttr; } 240 void setUsedAsTypeAttr() { UsedAsTypeAttr = true; } 241 242 Kind getKind() const { return Kind(AttrKind); } 243 static Kind getKind(const IdentifierInfo *Name, const IdentifierInfo *Scope, 244 Syntax SyntaxUsed); 245 246 AttributeList *getNext() const { return NextInPosition; } 247 void setNext(AttributeList *N) { NextInPosition = N; } 248 249 /// getNumArgs - Return the number of actual arguments to this attribute. 250 unsigned getNumArgs() const { return NumArgs; } 251 252 /// hasParameterOrArguments - Return true if this attribute has a parameter, 253 /// or has a non empty argument expression list. 254 bool hasParameterOrArguments() const { return ParmName || NumArgs; } 255 256 /// getArg - Return the specified argument. 257 Expr *getArg(unsigned Arg) const { 258 assert(Arg < NumArgs && "Arg access out of range!"); 259 return getArgsBuffer()[Arg]; 260 } 261 262 class arg_iterator { 263 Expr * const *X; 264 unsigned Idx; 265 public: 266 arg_iterator(Expr * const *x, unsigned idx) : X(x), Idx(idx) {} 267 268 arg_iterator& operator++() { 269 ++Idx; 270 return *this; 271 } 272 273 bool operator==(const arg_iterator& I) const { 274 assert (X == I.X && 275 "compared arg_iterators are for different argument lists"); 276 return Idx == I.Idx; 277 } 278 279 bool operator!=(const arg_iterator& I) const { 280 return !operator==(I); 281 } 282 283 Expr* operator*() const { 284 return X[Idx]; 285 } 286 287 unsigned getArgNum() const { 288 return Idx+1; 289 } 290 }; 291 292 arg_iterator arg_begin() const { 293 return arg_iterator(getArgsBuffer(), 0); 294 } 295 296 arg_iterator arg_end() const { 297 return arg_iterator(getArgsBuffer(), NumArgs); 298 } 299 300 const AvailabilityChange &getAvailabilityIntroduced() const { 301 assert(getKind() == AT_Availability && "Not an availability attribute"); 302 return getAvailabilitySlot(IntroducedSlot); 303 } 304 305 const AvailabilityChange &getAvailabilityDeprecated() const { 306 assert(getKind() == AT_Availability && "Not an availability attribute"); 307 return getAvailabilitySlot(DeprecatedSlot); 308 } 309 310 const AvailabilityChange &getAvailabilityObsoleted() const { 311 assert(getKind() == AT_Availability && "Not an availability attribute"); 312 return getAvailabilitySlot(ObsoletedSlot); 313 } 314 315 SourceLocation getUnavailableLoc() const { 316 assert(getKind() == AT_Availability && "Not an availability attribute"); 317 return UnavailableLoc; 318 } 319 320 const Expr * getMessageExpr() const { 321 assert(getKind() == AT_Availability && "Not an availability attribute"); 322 return MessageExpr; 323 } 324 325 const ParsedType &getMatchingCType() const { 326 assert(getKind() == AT_TypeTagForDatatype && 327 "Not a type_tag_for_datatype attribute"); 328 return *getTypeTagForDatatypeDataSlot().MatchingCType; 329 } 330 331 bool getLayoutCompatible() const { 332 assert(getKind() == AT_TypeTagForDatatype && 333 "Not a type_tag_for_datatype attribute"); 334 return getTypeTagForDatatypeDataSlot().LayoutCompatible; 335 } 336 337 bool getMustBeNull() const { 338 assert(getKind() == AT_TypeTagForDatatype && 339 "Not a type_tag_for_datatype attribute"); 340 return getTypeTagForDatatypeDataSlot().MustBeNull; 341 } 342 343 /// \brief Get an index into the attribute spelling list 344 /// defined in Attr.td. This index is used by an attribute 345 /// to pretty print itself. 346 unsigned getAttributeSpellingListIndex() const; 347}; 348 349/// A factory, from which one makes pools, from which one creates 350/// individual attributes which are deallocated with the pool. 351/// 352/// Note that it's tolerably cheap to create and destroy one of 353/// these as long as you don't actually allocate anything in it. 354class AttributeFactory { 355public: 356 enum { 357 /// The required allocation size of an availability attribute, 358 /// which we want to ensure is a multiple of sizeof(void*). 359 AvailabilityAllocSize = 360 sizeof(AttributeList) 361 + ((3 * sizeof(AvailabilityChange) + sizeof(void*) - 1) 362 / sizeof(void*) * sizeof(void*)), 363 TypeTagForDatatypeAllocSize = 364 sizeof(AttributeList) 365 + (sizeof(AttributeList::TypeTagForDatatypeData) + sizeof(void *) - 1) 366 / sizeof(void*) * sizeof(void*) 367 }; 368 369private: 370 enum { 371 /// The number of free lists we want to be sure to support 372 /// inline. This is just enough that availability attributes 373 /// don't surpass it. It's actually very unlikely we'll see an 374 /// attribute that needs more than that; on x86-64 you'd need 10 375 /// expression arguments, and on i386 you'd need 19. 376 InlineFreeListsCapacity = 377 1 + (AvailabilityAllocSize - sizeof(AttributeList)) / sizeof(void*) 378 }; 379 380 llvm::BumpPtrAllocator Alloc; 381 382 /// Free lists. The index is determined by the following formula: 383 /// (size - sizeof(AttributeList)) / sizeof(void*) 384 SmallVector<AttributeList*, InlineFreeListsCapacity> FreeLists; 385 386 // The following are the private interface used by AttributePool. 387 friend class AttributePool; 388 389 /// Allocate an attribute of the given size. 390 void *allocate(size_t size); 391 392 /// Reclaim all the attributes in the given pool chain, which is 393 /// non-empty. Note that the current implementation is safe 394 /// against reclaiming things which were not actually allocated 395 /// with the allocator, although of course it's important to make 396 /// sure that their allocator lives at least as long as this one. 397 void reclaimPool(AttributeList *head); 398 399public: 400 AttributeFactory(); 401 ~AttributeFactory(); 402}; 403 404class AttributePool { 405 AttributeFactory &Factory; 406 AttributeList *Head; 407 408 void *allocate(size_t size) { 409 return Factory.allocate(size); 410 } 411 412 AttributeList *add(AttributeList *attr) { 413 // We don't care about the order of the pool. 414 attr->NextInPool = Head; 415 Head = attr; 416 return attr; 417 } 418 419 void takePool(AttributeList *pool); 420 421public: 422 /// Create a new pool for a factory. 423 AttributePool(AttributeFactory &factory) : Factory(factory), Head(0) {} 424 425 /// Move the given pool's allocations to this pool. 426 AttributePool(AttributePool &pool) : Factory(pool.Factory), Head(pool.Head) { 427 pool.Head = 0; 428 } 429 430 AttributeFactory &getFactory() const { return Factory; } 431 432 void clear() { 433 if (Head) { 434 Factory.reclaimPool(Head); 435 Head = 0; 436 } 437 } 438 439 /// Take the given pool's allocations and add them to this pool. 440 void takeAllFrom(AttributePool &pool) { 441 if (pool.Head) { 442 takePool(pool.Head); 443 pool.Head = 0; 444 } 445 } 446 447 ~AttributePool() { 448 if (Head) Factory.reclaimPool(Head); 449 } 450 451 AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange, 452 IdentifierInfo *scopeName, SourceLocation scopeLoc, 453 IdentifierInfo *parmName, SourceLocation parmLoc, 454 Expr **args, unsigned numArgs, 455 AttributeList::Syntax syntax) { 456 void *memory = allocate(sizeof(AttributeList) 457 + numArgs * sizeof(Expr*)); 458 return add(new (memory) AttributeList(attrName, attrRange, 459 scopeName, scopeLoc, 460 parmName, parmLoc, 461 args, numArgs, syntax)); 462 } 463 464 AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange, 465 IdentifierInfo *scopeName, SourceLocation scopeLoc, 466 IdentifierInfo *parmName, SourceLocation parmLoc, 467 const AvailabilityChange &introduced, 468 const AvailabilityChange &deprecated, 469 const AvailabilityChange &obsoleted, 470 SourceLocation unavailable, 471 const Expr *MessageExpr, 472 AttributeList::Syntax syntax) { 473 void *memory = allocate(AttributeFactory::AvailabilityAllocSize); 474 return add(new (memory) AttributeList(attrName, attrRange, 475 scopeName, scopeLoc, 476 parmName, parmLoc, 477 introduced, deprecated, obsoleted, 478 unavailable, MessageExpr, syntax)); 479 } 480 481 AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name, 482 SourceLocation TokLoc, int Arg); 483 484 AttributeList *createTypeTagForDatatype( 485 IdentifierInfo *attrName, SourceRange attrRange, 486 IdentifierInfo *scopeName, SourceLocation scopeLoc, 487 IdentifierInfo *argumentKindName, 488 SourceLocation argumentKindLoc, 489 ParsedType matchingCType, bool layoutCompatible, 490 bool mustBeNull, AttributeList::Syntax syntax) { 491 void *memory = allocate(AttributeFactory::TypeTagForDatatypeAllocSize); 492 return add(new (memory) AttributeList(attrName, attrRange, 493 scopeName, scopeLoc, 494 argumentKindName, argumentKindLoc, 495 matchingCType, layoutCompatible, 496 mustBeNull, syntax)); 497 } 498}; 499 500/// addAttributeLists - Add two AttributeLists together 501/// The right-hand list is appended to the left-hand list, if any 502/// A pointer to the joined list is returned. 503/// Note: the lists are not left unmodified. 504inline AttributeList *addAttributeLists(AttributeList *Left, 505 AttributeList *Right) { 506 if (!Left) 507 return Right; 508 509 AttributeList *next = Left, *prev; 510 do { 511 prev = next; 512 next = next->getNext(); 513 } while (next); 514 prev->setNext(Right); 515 return Left; 516} 517 518/// CXX11AttributeList - A wrapper around a C++11 attribute list. 519/// Stores, in addition to the list proper, whether or not an actual list was 520/// (as opposed to an empty list, which may be ill-formed in some places) and 521/// the source range of the list. 522struct CXX11AttributeList { 523 AttributeList *AttrList; 524 SourceRange Range; 525 bool HasAttr; 526 CXX11AttributeList (AttributeList *attrList, SourceRange range, bool hasAttr) 527 : AttrList(attrList), Range(range), HasAttr (hasAttr) { 528 } 529 CXX11AttributeList () 530 : AttrList(0), Range(), HasAttr(false) { 531 } 532}; 533 534/// ParsedAttributes - A collection of parsed attributes. Currently 535/// we don't differentiate between the various attribute syntaxes, 536/// which is basically silly. 537/// 538/// Right now this is a very lightweight container, but the expectation 539/// is that this will become significantly more serious. 540class ParsedAttributes { 541public: 542 ParsedAttributes(AttributeFactory &factory) 543 : pool(factory), list(0) { 544 } 545 546 ParsedAttributes(ParsedAttributes &attrs) 547 : pool(attrs.pool), list(attrs.list) { 548 attrs.list = 0; 549 } 550 551 AttributePool &getPool() const { return pool; } 552 553 bool empty() const { return list == 0; } 554 555 void add(AttributeList *newAttr) { 556 assert(newAttr); 557 assert(newAttr->getNext() == 0); 558 newAttr->setNext(list); 559 list = newAttr; 560 } 561 562 void addAll(AttributeList *newList) { 563 if (!newList) return; 564 565 AttributeList *lastInNewList = newList; 566 while (AttributeList *next = lastInNewList->getNext()) 567 lastInNewList = next; 568 569 lastInNewList->setNext(list); 570 list = newList; 571 } 572 573 void set(AttributeList *newList) { 574 list = newList; 575 } 576 577 void takeAllFrom(ParsedAttributes &attrs) { 578 addAll(attrs.list); 579 attrs.list = 0; 580 pool.takeAllFrom(attrs.pool); 581 } 582 583 void clear() { list = 0; pool.clear(); } 584 AttributeList *getList() const { return list; } 585 586 /// Returns a reference to the attribute list. Try not to introduce 587 /// dependencies on this method, it may not be long-lived. 588 AttributeList *&getListRef() { return list; } 589 590 /// Add attribute with expression arguments. 591 AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, 592 IdentifierInfo *scopeName, SourceLocation scopeLoc, 593 IdentifierInfo *parmName, SourceLocation parmLoc, 594 Expr **args, unsigned numArgs, 595 AttributeList::Syntax syntax) { 596 AttributeList *attr = 597 pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, 598 args, numArgs, syntax); 599 add(attr); 600 return attr; 601 } 602 603 /// Add availability attribute. 604 AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, 605 IdentifierInfo *scopeName, SourceLocation scopeLoc, 606 IdentifierInfo *parmName, SourceLocation parmLoc, 607 const AvailabilityChange &introduced, 608 const AvailabilityChange &deprecated, 609 const AvailabilityChange &obsoleted, 610 SourceLocation unavailable, 611 const Expr *MessageExpr, 612 AttributeList::Syntax syntax) { 613 AttributeList *attr = 614 pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, 615 introduced, deprecated, obsoleted, unavailable, 616 MessageExpr, syntax); 617 add(attr); 618 return attr; 619 } 620 621 /// Add type_tag_for_datatype attribute. 622 AttributeList *addNewTypeTagForDatatype( 623 IdentifierInfo *attrName, SourceRange attrRange, 624 IdentifierInfo *scopeName, SourceLocation scopeLoc, 625 IdentifierInfo *argumentKindName, 626 SourceLocation argumentKindLoc, 627 ParsedType matchingCType, bool layoutCompatible, 628 bool mustBeNull, AttributeList::Syntax syntax) { 629 AttributeList *attr = 630 pool.createTypeTagForDatatype(attrName, attrRange, 631 scopeName, scopeLoc, 632 argumentKindName, argumentKindLoc, 633 matchingCType, layoutCompatible, 634 mustBeNull, syntax); 635 add(attr); 636 return attr; 637 } 638 639 AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name, 640 SourceLocation loc, int arg) { 641 AttributeList *attr = 642 pool.createIntegerAttribute(C, name, loc, arg); 643 add(attr); 644 return attr; 645 } 646 647 648private: 649 mutable AttributePool pool; 650 AttributeList *list; 651}; 652 653} // end namespace clang 654 655#endif 656