1//===--- AttributeList.cpp --------------------------------------*- 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 implementation 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/Sema/AttributeList.h" 15#include "clang/AST/ASTContext.h" 16#include "clang/AST/DeclCXX.h" 17#include "clang/AST/DeclTemplate.h" 18#include "clang/AST/Expr.h" 19#include "clang/Basic/IdentifierTable.h" 20#include "clang/Basic/TargetInfo.h" 21#include "clang/Sema/SemaInternal.h" 22#include "llvm/ADT/SmallString.h" 23#include "llvm/ADT/StringSwitch.h" 24using namespace clang; 25 26IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc, 27 IdentifierInfo *Ident) { 28 IdentifierLoc *Result = new (Ctx) IdentifierLoc; 29 Result->Loc = Loc; 30 Result->Ident = Ident; 31 return Result; 32} 33 34size_t AttributeList::allocated_size() const { 35 if (IsAvailability) return AttributeFactory::AvailabilityAllocSize; 36 else if (IsTypeTagForDatatype) 37 return AttributeFactory::TypeTagForDatatypeAllocSize; 38 else if (IsProperty) 39 return AttributeFactory::PropertyAllocSize; 40 return (sizeof(AttributeList) + NumArgs * sizeof(ArgsUnion)); 41} 42 43AttributeFactory::AttributeFactory() { 44 // Go ahead and configure all the inline capacity. This is just a memset. 45 FreeLists.resize(InlineFreeListsCapacity); 46} 47AttributeFactory::~AttributeFactory() {} 48 49static size_t getFreeListIndexForSize(size_t size) { 50 assert(size >= sizeof(AttributeList)); 51 assert((size % sizeof(void*)) == 0); 52 return ((size - sizeof(AttributeList)) / sizeof(void*)); 53} 54 55void *AttributeFactory::allocate(size_t size) { 56 // Check for a previously reclaimed attribute. 57 size_t index = getFreeListIndexForSize(size); 58 if (index < FreeLists.size()) { 59 if (AttributeList *attr = FreeLists[index]) { 60 FreeLists[index] = attr->NextInPool; 61 return attr; 62 } 63 } 64 65 // Otherwise, allocate something new. 66 return Alloc.Allocate(size, llvm::AlignOf<AttributeFactory>::Alignment); 67} 68 69void AttributeFactory::reclaimPool(AttributeList *cur) { 70 assert(cur && "reclaiming empty pool!"); 71 do { 72 // Read this here, because we're going to overwrite NextInPool 73 // when we toss 'cur' into the appropriate queue. 74 AttributeList *next = cur->NextInPool; 75 76 size_t size = cur->allocated_size(); 77 size_t freeListIndex = getFreeListIndexForSize(size); 78 79 // Expand FreeLists to the appropriate size, if required. 80 if (freeListIndex >= FreeLists.size()) 81 FreeLists.resize(freeListIndex+1); 82 83 // Add 'cur' to the appropriate free-list. 84 cur->NextInPool = FreeLists[freeListIndex]; 85 FreeLists[freeListIndex] = cur; 86 87 cur = next; 88 } while (cur); 89} 90 91void AttributePool::takePool(AttributeList *pool) { 92 assert(pool); 93 94 // Fast path: this pool is empty. 95 if (!Head) { 96 Head = pool; 97 return; 98 } 99 100 // Reverse the pool onto the current head. This optimizes for the 101 // pattern of pulling a lot of pools into a single pool. 102 do { 103 AttributeList *next = pool->NextInPool; 104 pool->NextInPool = Head; 105 Head = pool; 106 pool = next; 107 } while (pool); 108} 109 110#include "clang/Sema/AttrParsedAttrKinds.inc" 111 112static StringRef normalizeAttrName(StringRef AttrName, StringRef ScopeName, 113 AttributeList::Syntax SyntaxUsed) { 114 // Normalize the attribute name, __foo__ becomes foo. This is only allowable 115 // for GNU attributes. 116 bool IsGNU = SyntaxUsed == AttributeList::AS_GNU || 117 (SyntaxUsed == AttributeList::AS_CXX11 && ScopeName == "gnu"); 118 if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") && 119 AttrName.endswith("__")) 120 AttrName = AttrName.slice(2, AttrName.size() - 2); 121 122 return AttrName; 123} 124 125AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name, 126 const IdentifierInfo *ScopeName, 127 Syntax SyntaxUsed) { 128 StringRef AttrName = Name->getName(); 129 130 SmallString<64> FullName; 131 if (ScopeName) 132 FullName += ScopeName->getName(); 133 134 AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed); 135 136 // Ensure that in the case of C++11 attributes, we look for '::foo' if it is 137 // unscoped. 138 if (ScopeName || SyntaxUsed == AS_CXX11) 139 FullName += "::"; 140 FullName += AttrName; 141 142 return ::getAttrKind(FullName, SyntaxUsed); 143} 144 145unsigned AttributeList::getAttributeSpellingListIndex() const { 146 // Both variables will be used in tablegen generated 147 // attribute spell list index matching code. 148 StringRef Scope = ScopeName ? ScopeName->getName() : ""; 149 StringRef Name = normalizeAttrName(AttrName->getName(), Scope, 150 (AttributeList::Syntax)SyntaxUsed); 151 152#include "clang/Sema/AttrSpellingListIndex.inc" 153 154} 155 156struct ParsedAttrInfo { 157 unsigned NumArgs : 4; 158 unsigned OptArgs : 4; 159 unsigned HasCustomParsing : 1; 160 unsigned IsTargetSpecific : 1; 161 unsigned IsType : 1; 162 unsigned IsKnownToGCC : 1; 163 164 bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr, 165 const Decl *); 166 bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr); 167 bool (*ExistsInTarget)(const TargetInfo &Target); 168 unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr); 169}; 170 171namespace { 172 #include "clang/Sema/AttrParsedAttrImpl.inc" 173} 174 175static const ParsedAttrInfo &getInfo(const AttributeList &A) { 176 return AttrInfoMap[A.getKind()]; 177} 178 179unsigned AttributeList::getMinArgs() const { 180 return getInfo(*this).NumArgs; 181} 182 183unsigned AttributeList::getMaxArgs() const { 184 return getMinArgs() + getInfo(*this).OptArgs; 185} 186 187bool AttributeList::hasCustomParsing() const { 188 return getInfo(*this).HasCustomParsing; 189} 190 191bool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 192 return getInfo(*this).DiagAppertainsToDecl(S, *this, D); 193} 194 195bool AttributeList::diagnoseLangOpts(Sema &S) const { 196 return getInfo(*this).DiagLangOpts(S, *this); 197} 198 199bool AttributeList::isTargetSpecificAttr() const { 200 return getInfo(*this).IsTargetSpecific; 201} 202 203bool AttributeList::isTypeAttr() const { 204 return getInfo(*this).IsType; 205} 206 207bool AttributeList::existsInTarget(const TargetInfo &Target) const { 208 return getInfo(*this).ExistsInTarget(Target); 209} 210 211bool AttributeList::isKnownToGCC() const { 212 return getInfo(*this).IsKnownToGCC; 213} 214 215unsigned AttributeList::getSemanticSpelling() const { 216 return getInfo(*this).SpellingIndexToSemanticSpelling(*this); 217} 218 219bool AttributeList::hasVariadicArg() const { 220 // If the attribute has the maximum number of optional arguments, we will 221 // claim that as being variadic. If we someday get an attribute that 222 // legitimately bumps up against that maximum, we can use another bit to track 223 // whether it's truly variadic or not. 224 return getInfo(*this).OptArgs == 15; 225} 226