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" 24 using namespace clang; 25 26 IdentifierLoc *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 34 size_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 43 AttributeFactory::AttributeFactory() { 44 // Go ahead and configure all the inline capacity. This is just a memset. 45 FreeLists.resize(InlineFreeListsCapacity); 46 } 47 AttributeFactory::~AttributeFactory() {} 48 49 static 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 55 void *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 69 void 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 91 void 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 112 static 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 125 AttributeList::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 145 unsigned 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 156 struct ParsedAttrInfo { 157 unsigned NumArgs : 4; 158 unsigned OptArgs : 4; 159 unsigned HasCustomParsing : 1; 160 unsigned IsTargetSpecific : 1; 161 unsigned IsType : 1; 162 unsigned IsStmt : 1; 163 unsigned IsKnownToGCC : 1; 164 165 bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr, 166 const Decl *); 167 bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr); 168 bool (*ExistsInTarget)(const TargetInfo &Target); 169 unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr); 170 }; 171 172 namespace { 173 #include "clang/Sema/AttrParsedAttrImpl.inc" 174 } 175 176 static const ParsedAttrInfo &getInfo(const AttributeList &A) { 177 return AttrInfoMap[A.getKind()]; 178 } 179 180 unsigned AttributeList::getMinArgs() const { 181 return getInfo(*this).NumArgs; 182 } 183 184 unsigned AttributeList::getMaxArgs() const { 185 return getMinArgs() + getInfo(*this).OptArgs; 186 } 187 188 bool AttributeList::hasCustomParsing() const { 189 return getInfo(*this).HasCustomParsing; 190 } 191 192 bool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 193 return getInfo(*this).DiagAppertainsToDecl(S, *this, D); 194 } 195 196 bool AttributeList::diagnoseLangOpts(Sema &S) const { 197 return getInfo(*this).DiagLangOpts(S, *this); 198 } 199 200 bool AttributeList::isTargetSpecificAttr() const { 201 return getInfo(*this).IsTargetSpecific; 202 } 203 204 bool AttributeList::isTypeAttr() const { 205 return getInfo(*this).IsType; 206 } 207 208 bool AttributeList::isStmtAttr() const { 209 return getInfo(*this).IsStmt; 210 } 211 212 bool AttributeList::existsInTarget(const TargetInfo &Target) const { 213 return getInfo(*this).ExistsInTarget(Target); 214 } 215 216 bool AttributeList::isKnownToGCC() const { 217 return getInfo(*this).IsKnownToGCC; 218 } 219 220 unsigned AttributeList::getSemanticSpelling() const { 221 return getInfo(*this).SpellingIndexToSemanticSpelling(*this); 222 } 223 224 bool AttributeList::hasVariadicArg() const { 225 // If the attribute has the maximum number of optional arguments, we will 226 // claim that as being variadic. If we someday get an attribute that 227 // legitimately bumps up against that maximum, we can use another bit to track 228 // whether it's truly variadic or not. 229 return getInfo(*this).OptArgs == 15; 230 } 231