AttributeList.h revision 51d8c52ad36129760eaa586f85176037e2cd0d0e
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 isCXX11Attribute() 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 /// \brief Get an index into the attribute spelling list 345 /// defined in Attr.td. This index is used by an attribute 346 /// to pretty print itself. 347 unsigned getAttributeSpellingListIndex() const; 348}; 349 350/// A factory, from which one makes pools, from which one creates 351/// individual attributes which are deallocated with the pool. 352/// 353/// Note that it's tolerably cheap to create and destroy one of 354/// these as long as you don't actually allocate anything in it. 355class AttributeFactory { 356public: 357 enum { 358 /// The required allocation size of an availability attribute, 359 /// which we want to ensure is a multiple of sizeof(void*). 360 AvailabilityAllocSize = 361 sizeof(AttributeList) 362 + ((3 * sizeof(AvailabilityChange) + sizeof(void*) - 1) 363 / sizeof(void*) * sizeof(void*)), 364 TypeTagForDatatypeAllocSize = 365 sizeof(AttributeList) 366 + (sizeof(AttributeList::TypeTagForDatatypeData) + sizeof(void *) - 1) 367 / sizeof(void*) * sizeof(void*) 368 }; 369 370private: 371 enum { 372 /// The number of free lists we want to be sure to support 373 /// inline. This is just enough that availability attributes 374 /// don't surpass it. It's actually very unlikely we'll see an 375 /// attribute that needs more than that; on x86-64 you'd need 10 376 /// expression arguments, and on i386 you'd need 19. 377 InlineFreeListsCapacity = 378 1 + (AvailabilityAllocSize - sizeof(AttributeList)) / sizeof(void*) 379 }; 380 381 llvm::BumpPtrAllocator Alloc; 382 383 /// Free lists. The index is determined by the following formula: 384 /// (size - sizeof(AttributeList)) / sizeof(void*) 385 SmallVector<AttributeList*, InlineFreeListsCapacity> FreeLists; 386 387 // The following are the private interface used by AttributePool. 388 friend class AttributePool; 389 390 /// Allocate an attribute of the given size. 391 void *allocate(size_t size); 392 393 /// Reclaim all the attributes in the given pool chain, which is 394 /// non-empty. Note that the current implementation is safe 395 /// against reclaiming things which were not actually allocated 396 /// with the allocator, although of course it's important to make 397 /// sure that their allocator lives at least as long as this one. 398 void reclaimPool(AttributeList *head); 399 400public: 401 AttributeFactory(); 402 ~AttributeFactory(); 403}; 404 405class AttributePool { 406 AttributeFactory &Factory; 407 AttributeList *Head; 408 409 void *allocate(size_t size) { 410 return Factory.allocate(size); 411 } 412 413 AttributeList *add(AttributeList *attr) { 414 // We don't care about the order of the pool. 415 attr->NextInPool = Head; 416 Head = attr; 417 return attr; 418 } 419 420 void takePool(AttributeList *pool); 421 422public: 423 /// Create a new pool for a factory. 424 AttributePool(AttributeFactory &factory) : Factory(factory), Head(0) {} 425 426 /// Move the given pool's allocations to this pool. 427 AttributePool(AttributePool &pool) : Factory(pool.Factory), Head(pool.Head) { 428 pool.Head = 0; 429 } 430 431 AttributeFactory &getFactory() const { return Factory; } 432 433 void clear() { 434 if (Head) { 435 Factory.reclaimPool(Head); 436 Head = 0; 437 } 438 } 439 440 /// Take the given pool's allocations and add them to this pool. 441 void takeAllFrom(AttributePool &pool) { 442 if (pool.Head) { 443 takePool(pool.Head); 444 pool.Head = 0; 445 } 446 } 447 448 ~AttributePool() { 449 if (Head) Factory.reclaimPool(Head); 450 } 451 452 AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange, 453 IdentifierInfo *scopeName, SourceLocation scopeLoc, 454 IdentifierInfo *parmName, SourceLocation parmLoc, 455 Expr **args, unsigned numArgs, 456 AttributeList::Syntax syntax) { 457 void *memory = allocate(sizeof(AttributeList) 458 + numArgs * sizeof(Expr*)); 459 return add(new (memory) AttributeList(attrName, attrRange, 460 scopeName, scopeLoc, 461 parmName, parmLoc, 462 args, numArgs, syntax)); 463 } 464 465 AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange, 466 IdentifierInfo *scopeName, SourceLocation scopeLoc, 467 IdentifierInfo *parmName, SourceLocation parmLoc, 468 const AvailabilityChange &introduced, 469 const AvailabilityChange &deprecated, 470 const AvailabilityChange &obsoleted, 471 SourceLocation unavailable, 472 const Expr *MessageExpr, 473 AttributeList::Syntax syntax) { 474 void *memory = allocate(AttributeFactory::AvailabilityAllocSize); 475 return add(new (memory) AttributeList(attrName, attrRange, 476 scopeName, scopeLoc, 477 parmName, parmLoc, 478 introduced, deprecated, obsoleted, 479 unavailable, MessageExpr, syntax)); 480 } 481 482 AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name, 483 SourceLocation TokLoc, int Arg); 484 485 AttributeList *createTypeTagForDatatype( 486 IdentifierInfo *attrName, SourceRange attrRange, 487 IdentifierInfo *scopeName, SourceLocation scopeLoc, 488 IdentifierInfo *argumentKindName, 489 SourceLocation argumentKindLoc, 490 ParsedType matchingCType, bool layoutCompatible, 491 bool mustBeNull, AttributeList::Syntax syntax) { 492 void *memory = allocate(AttributeFactory::TypeTagForDatatypeAllocSize); 493 return add(new (memory) AttributeList(attrName, attrRange, 494 scopeName, scopeLoc, 495 argumentKindName, argumentKindLoc, 496 matchingCType, layoutCompatible, 497 mustBeNull, syntax)); 498 } 499}; 500 501/// addAttributeLists - Add two AttributeLists together 502/// The right-hand list is appended to the left-hand list, if any 503/// A pointer to the joined list is returned. 504/// Note: the lists are not left unmodified. 505inline AttributeList *addAttributeLists(AttributeList *Left, 506 AttributeList *Right) { 507 if (!Left) 508 return Right; 509 510 AttributeList *next = Left, *prev; 511 do { 512 prev = next; 513 next = next->getNext(); 514 } while (next); 515 prev->setNext(Right); 516 return Left; 517} 518 519/// CXX11AttributeList - A wrapper around a C++11 attribute list. 520/// Stores, in addition to the list proper, whether or not an actual list was 521/// (as opposed to an empty list, which may be ill-formed in some places) and 522/// the source range of the list. 523struct CXX11AttributeList { 524 AttributeList *AttrList; 525 SourceRange Range; 526 bool HasAttr; 527 CXX11AttributeList (AttributeList *attrList, SourceRange range, bool hasAttr) 528 : AttrList(attrList), Range(range), HasAttr (hasAttr) { 529 } 530 CXX11AttributeList () 531 : AttrList(0), Range(), HasAttr(false) { 532 } 533}; 534 535/// ParsedAttributes - A collection of parsed attributes. Currently 536/// we don't differentiate between the various attribute syntaxes, 537/// which is basically silly. 538/// 539/// Right now this is a very lightweight container, but the expectation 540/// is that this will become significantly more serious. 541class ParsedAttributes { 542public: 543 ParsedAttributes(AttributeFactory &factory) 544 : pool(factory), list(0) { 545 } 546 547 ParsedAttributes(ParsedAttributes &attrs) 548 : pool(attrs.pool), list(attrs.list) { 549 attrs.list = 0; 550 } 551 552 AttributePool &getPool() const { return pool; } 553 554 bool empty() const { return list == 0; } 555 556 void add(AttributeList *newAttr) { 557 assert(newAttr); 558 assert(newAttr->getNext() == 0); 559 newAttr->setNext(list); 560 list = newAttr; 561 } 562 563 void addAll(AttributeList *newList) { 564 if (!newList) return; 565 566 AttributeList *lastInNewList = newList; 567 while (AttributeList *next = lastInNewList->getNext()) 568 lastInNewList = next; 569 570 lastInNewList->setNext(list); 571 list = newList; 572 } 573 574 void set(AttributeList *newList) { 575 list = newList; 576 } 577 578 void takeAllFrom(ParsedAttributes &attrs) { 579 addAll(attrs.list); 580 attrs.list = 0; 581 pool.takeAllFrom(attrs.pool); 582 } 583 584 void clear() { list = 0; pool.clear(); } 585 AttributeList *getList() const { return list; } 586 587 /// Returns a reference to the attribute list. Try not to introduce 588 /// dependencies on this method, it may not be long-lived. 589 AttributeList *&getListRef() { return list; } 590 591 /// Add attribute with expression arguments. 592 AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, 593 IdentifierInfo *scopeName, SourceLocation scopeLoc, 594 IdentifierInfo *parmName, SourceLocation parmLoc, 595 Expr **args, unsigned numArgs, 596 AttributeList::Syntax syntax) { 597 AttributeList *attr = 598 pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, 599 args, numArgs, syntax); 600 add(attr); 601 return attr; 602 } 603 604 /// Add availability attribute. 605 AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, 606 IdentifierInfo *scopeName, SourceLocation scopeLoc, 607 IdentifierInfo *parmName, SourceLocation parmLoc, 608 const AvailabilityChange &introduced, 609 const AvailabilityChange &deprecated, 610 const AvailabilityChange &obsoleted, 611 SourceLocation unavailable, 612 const Expr *MessageExpr, 613 AttributeList::Syntax syntax) { 614 AttributeList *attr = 615 pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, 616 introduced, deprecated, obsoleted, unavailable, 617 MessageExpr, syntax); 618 add(attr); 619 return attr; 620 } 621 622 /// Add type_tag_for_datatype attribute. 623 AttributeList *addNewTypeTagForDatatype( 624 IdentifierInfo *attrName, SourceRange attrRange, 625 IdentifierInfo *scopeName, SourceLocation scopeLoc, 626 IdentifierInfo *argumentKindName, 627 SourceLocation argumentKindLoc, 628 ParsedType matchingCType, bool layoutCompatible, 629 bool mustBeNull, AttributeList::Syntax syntax) { 630 AttributeList *attr = 631 pool.createTypeTagForDatatype(attrName, attrRange, 632 scopeName, scopeLoc, 633 argumentKindName, argumentKindLoc, 634 matchingCType, layoutCompatible, 635 mustBeNull, syntax); 636 add(attr); 637 return attr; 638 } 639 640 AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name, 641 SourceLocation loc, int arg) { 642 AttributeList *attr = 643 pool.createIntegerAttribute(C, name, loc, arg); 644 add(attr); 645 return attr; 646 } 647 648 649private: 650 mutable AttributePool pool; 651 AttributeList *list; 652}; 653 654} // end namespace clang 655 656#endif 657