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