1212795Sdim//===--- AttributeList.cpp --------------------------------------*- C++ -*-===//
2212795Sdim//
3212795Sdim//                     The LLVM Compiler Infrastructure
4212795Sdim//
5212795Sdim// This file is distributed under the University of Illinois Open Source
6212795Sdim// License. See LICENSE.TXT for details.
7212795Sdim//
8212795Sdim//===----------------------------------------------------------------------===//
9212795Sdim//
10212795Sdim// This file defines the AttributeList class implementation
11212795Sdim//
12212795Sdim//===----------------------------------------------------------------------===//
13212795Sdim
14212795Sdim#include "clang/Sema/AttributeList.h"
15239462Sdim#include "clang/AST/ASTContext.h"
16276479Sdim#include "clang/AST/DeclCXX.h"
17276479Sdim#include "clang/AST/DeclTemplate.h"
18221345Sdim#include "clang/AST/Expr.h"
19212795Sdim#include "clang/Basic/IdentifierTable.h"
20296417Sdim#include "clang/Basic/TargetInfo.h"
21276479Sdim#include "clang/Sema/SemaInternal.h"
22249423Sdim#include "llvm/ADT/SmallString.h"
23212795Sdim#include "llvm/ADT/StringSwitch.h"
24212795Sdimusing namespace clang;
25212795Sdim
26261991SdimIdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc,
27261991Sdim                                     IdentifierInfo *Ident) {
28261991Sdim  IdentifierLoc *Result = new (Ctx) IdentifierLoc;
29261991Sdim  Result->Loc = Loc;
30261991Sdim  Result->Ident = Ident;
31261991Sdim  return Result;
32261991Sdim}
33261991Sdim
34221345Sdimsize_t AttributeList::allocated_size() const {
35221345Sdim  if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;
36239462Sdim  else if (IsTypeTagForDatatype)
37239462Sdim    return AttributeFactory::TypeTagForDatatypeAllocSize;
38251662Sdim  else if (IsProperty)
39251662Sdim    return AttributeFactory::PropertyAllocSize;
40261991Sdim  return (sizeof(AttributeList) + NumArgs * sizeof(ArgsUnion));
41221345Sdim}
42212795Sdim
43221345SdimAttributeFactory::AttributeFactory() {
44221345Sdim  // Go ahead and configure all the inline capacity.  This is just a memset.
45221345Sdim  FreeLists.resize(InlineFreeListsCapacity);
46221345Sdim}
47221345SdimAttributeFactory::~AttributeFactory() {}
48221345Sdim
49221345Sdimstatic size_t getFreeListIndexForSize(size_t size) {
50221345Sdim  assert(size >= sizeof(AttributeList));
51221345Sdim  assert((size % sizeof(void*)) == 0);
52221345Sdim  return ((size - sizeof(AttributeList)) / sizeof(void*));
53221345Sdim}
54221345Sdim
55221345Sdimvoid *AttributeFactory::allocate(size_t size) {
56221345Sdim  // Check for a previously reclaimed attribute.
57221345Sdim  size_t index = getFreeListIndexForSize(size);
58221345Sdim  if (index < FreeLists.size()) {
59221345Sdim    if (AttributeList *attr = FreeLists[index]) {
60221345Sdim      FreeLists[index] = attr->NextInPool;
61221345Sdim      return attr;
62221345Sdim    }
63212795Sdim  }
64221345Sdim
65221345Sdim  // Otherwise, allocate something new.
66221345Sdim  return Alloc.Allocate(size, llvm::AlignOf<AttributeFactory>::Alignment);
67212795Sdim}
68212795Sdim
69221345Sdimvoid AttributeFactory::reclaimPool(AttributeList *cur) {
70221345Sdim  assert(cur && "reclaiming empty pool!");
71221345Sdim  do {
72221345Sdim    // Read this here, because we're going to overwrite NextInPool
73221345Sdim    // when we toss 'cur' into the appropriate queue.
74221345Sdim    AttributeList *next = cur->NextInPool;
75221345Sdim
76221345Sdim    size_t size = cur->allocated_size();
77221345Sdim    size_t freeListIndex = getFreeListIndexForSize(size);
78221345Sdim
79221345Sdim    // Expand FreeLists to the appropriate size, if required.
80221345Sdim    if (freeListIndex >= FreeLists.size())
81221345Sdim      FreeLists.resize(freeListIndex+1);
82221345Sdim
83221345Sdim    // Add 'cur' to the appropriate free-list.
84221345Sdim    cur->NextInPool = FreeLists[freeListIndex];
85221345Sdim    FreeLists[freeListIndex] = cur;
86221345Sdim
87221345Sdim    cur = next;
88221345Sdim  } while (cur);
89221345Sdim}
90221345Sdim
91221345Sdimvoid AttributePool::takePool(AttributeList *pool) {
92221345Sdim  assert(pool);
93221345Sdim
94221345Sdim  // Fast path:  this pool is empty.
95221345Sdim  if (!Head) {
96221345Sdim    Head = pool;
97221345Sdim    return;
98221345Sdim  }
99221345Sdim
100221345Sdim  // Reverse the pool onto the current head.  This optimizes for the
101221345Sdim  // pattern of pulling a lot of pools into a single pool.
102221345Sdim  do {
103221345Sdim    AttributeList *next = pool->NextInPool;
104221345Sdim    pool->NextInPool = Head;
105221345Sdim    Head = pool;
106221345Sdim    pool = next;
107221345Sdim  } while (pool);
108221345Sdim}
109221345Sdim
110239462Sdim#include "clang/Sema/AttrParsedAttrKinds.inc"
111239462Sdim
112296417Sdimstatic StringRef normalizeAttrName(StringRef AttrName, StringRef ScopeName,
113296417Sdim                                   AttributeList::Syntax SyntaxUsed) {
114296417Sdim  // Normalize the attribute name, __foo__ becomes foo. This is only allowable
115296417Sdim  // for GNU attributes.
116296417Sdim  bool IsGNU = SyntaxUsed == AttributeList::AS_GNU ||
117296417Sdim               (SyntaxUsed == AttributeList::AS_CXX11 && ScopeName == "gnu");
118296417Sdim  if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") &&
119296417Sdim      AttrName.endswith("__"))
120296417Sdim    AttrName = AttrName.slice(2, AttrName.size() - 2);
121296417Sdim
122296417Sdim  return AttrName;
123296417Sdim}
124296417Sdim
125239462SdimAttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name,
126239462Sdim                                           const IdentifierInfo *ScopeName,
127239462Sdim                                           Syntax SyntaxUsed) {
128226633Sdim  StringRef AttrName = Name->getName();
129212795Sdim
130276479Sdim  SmallString<64> FullName;
131276479Sdim  if (ScopeName)
132276479Sdim    FullName += ScopeName->getName();
133212795Sdim
134296417Sdim  AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed);
135276479Sdim
136239462Sdim  // Ensure that in the case of C++11 attributes, we look for '::foo' if it is
137239462Sdim  // unscoped.
138239462Sdim  if (ScopeName || SyntaxUsed == AS_CXX11)
139276479Sdim    FullName += "::";
140276479Sdim  FullName += AttrName;
141239462Sdim
142276479Sdim  return ::getAttrKind(FullName, SyntaxUsed);
143212795Sdim}
144249423Sdim
145249423Sdimunsigned AttributeList::getAttributeSpellingListIndex() const {
146249423Sdim  // Both variables will be used in tablegen generated
147249423Sdim  // attribute spell list index matching code.
148249423Sdim  StringRef Scope = ScopeName ? ScopeName->getName() : "";
149296417Sdim  StringRef Name = normalizeAttrName(AttrName->getName(), Scope,
150296417Sdim                                     (AttributeList::Syntax)SyntaxUsed);
151249423Sdim
152249423Sdim#include "clang/Sema/AttrSpellingListIndex.inc"
153249423Sdim
154249423Sdim}
155249423Sdim
156261991Sdimstruct ParsedAttrInfo {
157261991Sdim  unsigned NumArgs : 4;
158261991Sdim  unsigned OptArgs : 4;
159261991Sdim  unsigned HasCustomParsing : 1;
160276479Sdim  unsigned IsTargetSpecific : 1;
161276479Sdim  unsigned IsType : 1;
162276479Sdim  unsigned IsKnownToGCC : 1;
163276479Sdim
164276479Sdim  bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
165276479Sdim                               const Decl *);
166276479Sdim  bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr);
167296417Sdim  bool (*ExistsInTarget)(const TargetInfo &Target);
168276479Sdim  unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr);
169261991Sdim};
170261991Sdim
171261991Sdimnamespace {
172261991Sdim  #include "clang/Sema/AttrParsedAttrImpl.inc"
173261991Sdim}
174261991Sdim
175261991Sdimstatic const ParsedAttrInfo &getInfo(const AttributeList &A) {
176261991Sdim  return AttrInfoMap[A.getKind()];
177261991Sdim}
178261991Sdim
179261991Sdimunsigned AttributeList::getMinArgs() const {
180261991Sdim  return getInfo(*this).NumArgs;
181261991Sdim}
182261991Sdim
183261991Sdimunsigned AttributeList::getMaxArgs() const {
184261991Sdim  return getMinArgs() + getInfo(*this).OptArgs;
185261991Sdim}
186261991Sdim
187261991Sdimbool AttributeList::hasCustomParsing() const {
188261991Sdim  return getInfo(*this).HasCustomParsing;
189261991Sdim}
190276479Sdim
191276479Sdimbool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
192276479Sdim  return getInfo(*this).DiagAppertainsToDecl(S, *this, D);
193276479Sdim}
194276479Sdim
195276479Sdimbool AttributeList::diagnoseLangOpts(Sema &S) const {
196276479Sdim  return getInfo(*this).DiagLangOpts(S, *this);
197276479Sdim}
198276479Sdim
199276479Sdimbool AttributeList::isTargetSpecificAttr() const {
200276479Sdim  return getInfo(*this).IsTargetSpecific;
201276479Sdim}
202276479Sdim
203276479Sdimbool AttributeList::isTypeAttr() const {
204276479Sdim  return getInfo(*this).IsType;
205276479Sdim}
206276479Sdim
207296417Sdimbool AttributeList::existsInTarget(const TargetInfo &Target) const {
208296417Sdim  return getInfo(*this).ExistsInTarget(Target);
209276479Sdim}
210276479Sdim
211276479Sdimbool AttributeList::isKnownToGCC() const {
212276479Sdim  return getInfo(*this).IsKnownToGCC;
213276479Sdim}
214276479Sdim
215276479Sdimunsigned AttributeList::getSemanticSpelling() const {
216276479Sdim  return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
217276479Sdim}
218280031Sdim
219280031Sdimbool AttributeList::hasVariadicArg() const {
220280031Sdim  // If the attribute has the maximum number of optional arguments, we will
221280031Sdim  // claim that as being variadic. If we someday get an attribute that
222280031Sdim  // legitimately bumps up against that maximum, we can use another bit to track
223280031Sdim  // whether it's truly variadic or not.
224280031Sdim  return getInfo(*this).OptArgs == 15;
225280031Sdim}
226