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