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 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 171 namespace { 172 #include "clang/Sema/AttrParsedAttrImpl.inc" 173 } 174 175 static const ParsedAttrInfo &getInfo(const AttributeList &A) { 176 return AttrInfoMap[A.getKind()]; 177 } 178 179 unsigned AttributeList::getMinArgs() const { 180 return getInfo(*this).NumArgs; 181 } 182 183 unsigned AttributeList::getMaxArgs() const { 184 return getMinArgs() + getInfo(*this).OptArgs; 185 } 186 187 bool AttributeList::hasCustomParsing() const { 188 return getInfo(*this).HasCustomParsing; 189 } 190 191 bool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 192 return getInfo(*this).DiagAppertainsToDecl(S, *this, D); 193 } 194 195 bool AttributeList::diagnoseLangOpts(Sema &S) const { 196 return getInfo(*this).DiagLangOpts(S, *this); 197 } 198 199 bool AttributeList::isTargetSpecificAttr() const { 200 return getInfo(*this).IsTargetSpecific; 201 } 202 203 bool AttributeList::isTypeAttr() const { 204 return getInfo(*this).IsType; 205 } 206 207 bool AttributeList::existsInTarget(const TargetInfo &Target) const { 208 return getInfo(*this).ExistsInTarget(Target); 209 } 210 211 bool AttributeList::isKnownToGCC() const { 212 return getInfo(*this).IsKnownToGCC; 213 } 214 215 unsigned AttributeList::getSemanticSpelling() const { 216 return getInfo(*this).SpellingIndexToSemanticSpelling(*this); 217 } 218 219 bool 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