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