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