1//======- ParsedAttr.cpp --------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the ParsedAttr class implementation
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/Sema/ParsedAttr.h"
14#include "clang/AST/ASTContext.h"
15#include "clang/Basic/AttrSubjectMatchRules.h"
16#include "clang/Basic/IdentifierTable.h"
17#include "clang/Basic/TargetInfo.h"
18#include "clang/Sema/SemaInternal.h"
19#include "llvm/ADT/SmallString.h"
20#include "llvm/ADT/SmallVector.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/Support/ManagedStatic.h"
23#include <cassert>
24#include <cstddef>
25#include <utility>
26
27using namespace clang;
28
29LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry)
30
31IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc,
32                                     IdentifierInfo *Ident) {
33  IdentifierLoc *Result = new (Ctx) IdentifierLoc;
34  Result->Loc = Loc;
35  Result->Ident = Ident;
36  return Result;
37}
38
39size_t ParsedAttr::allocated_size() const {
40  if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;
41  else if (IsTypeTagForDatatype)
42    return AttributeFactory::TypeTagForDatatypeAllocSize;
43  else if (IsProperty)
44    return AttributeFactory::PropertyAllocSize;
45  else if (HasParsedType)
46    return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
47                            detail::TypeTagForDatatypeData, ParsedType,
48                            detail::PropertyData>(0, 0, 0, 1, 0);
49  return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
50                          detail::TypeTagForDatatypeData, ParsedType,
51                          detail::PropertyData>(NumArgs, 0, 0, 0, 0);
52}
53
54AttributeFactory::AttributeFactory() {
55  // Go ahead and configure all the inline capacity.  This is just a memset.
56  FreeLists.resize(InlineFreeListsCapacity);
57}
58AttributeFactory::~AttributeFactory() = default;
59
60static size_t getFreeListIndexForSize(size_t size) {
61  assert(size >= sizeof(ParsedAttr));
62  assert((size % sizeof(void*)) == 0);
63  return ((size - sizeof(ParsedAttr)) / sizeof(void *));
64}
65
66void *AttributeFactory::allocate(size_t size) {
67  // Check for a previously reclaimed attribute.
68  size_t index = getFreeListIndexForSize(size);
69  if (index < FreeLists.size() && !FreeLists[index].empty()) {
70    ParsedAttr *attr = FreeLists[index].back();
71    FreeLists[index].pop_back();
72    return attr;
73  }
74
75  // Otherwise, allocate something new.
76  return Alloc.Allocate(size, alignof(AttributeFactory));
77}
78
79void AttributeFactory::deallocate(ParsedAttr *Attr) {
80  size_t size = Attr->allocated_size();
81  size_t freeListIndex = getFreeListIndexForSize(size);
82
83  // Expand FreeLists to the appropriate size, if required.
84  if (freeListIndex >= FreeLists.size())
85    FreeLists.resize(freeListIndex + 1);
86
87#ifndef NDEBUG
88  // In debug mode, zero out the attribute to help find memory overwriting.
89  memset(Attr, 0, size);
90#endif
91
92  // Add 'Attr' to the appropriate free-list.
93  FreeLists[freeListIndex].push_back(Attr);
94}
95
96void AttributeFactory::reclaimPool(AttributePool &cur) {
97  for (ParsedAttr *AL : cur.Attrs)
98    deallocate(AL);
99}
100
101void AttributePool::takePool(AttributePool &pool) {
102  Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end());
103  pool.Attrs.clear();
104}
105
106namespace {
107
108#include "clang/Sema/AttrParsedAttrImpl.inc"
109
110} // namespace
111
112const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
113  // If we have a ParsedAttrInfo for this ParsedAttr then return that.
114  if ((size_t)A.getParsedKind() < llvm::array_lengthof(AttrInfoMap))
115    return *AttrInfoMap[A.getParsedKind()];
116
117  // If this is an ignored attribute then return an appropriate ParsedAttrInfo.
118  static const ParsedAttrInfo IgnoredParsedAttrInfo(
119      AttributeCommonInfo::IgnoredAttribute);
120  if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute)
121    return IgnoredParsedAttrInfo;
122
123  // Otherwise this may be an attribute defined by a plugin. First instantiate
124  // all plugin attributes if we haven't already done so.
125  static llvm::ManagedStatic<std::list<std::unique_ptr<ParsedAttrInfo>>>
126      PluginAttrInstances;
127  if (PluginAttrInstances->empty())
128    for (auto It : ParsedAttrInfoRegistry::entries())
129      PluginAttrInstances->emplace_back(It.instantiate());
130
131  // Search for a ParsedAttrInfo whose name and syntax match.
132  std::string FullName = A.getNormalizedFullName();
133  AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax();
134  if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword)
135    SyntaxUsed = AttributeCommonInfo::AS_Keyword;
136
137  for (auto &Ptr : *PluginAttrInstances)
138    for (auto &S : Ptr->Spellings)
139      if (S.Syntax == SyntaxUsed && S.NormalizedFullName == FullName)
140        return *Ptr;
141
142  // If we failed to find a match then return a default ParsedAttrInfo.
143  static const ParsedAttrInfo DefaultParsedAttrInfo(
144      AttributeCommonInfo::UnknownAttribute);
145  return DefaultParsedAttrInfo;
146}
147
148unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
149
150unsigned ParsedAttr::getMaxArgs() const {
151  return getMinArgs() + getInfo().OptArgs;
152}
153
154bool ParsedAttr::hasCustomParsing() const {
155  return getInfo().HasCustomParsing;
156}
157
158bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
159  return getInfo().diagAppertainsToDecl(S, *this, D);
160}
161
162bool ParsedAttr::appliesToDecl(const Decl *D,
163                               attr::SubjectMatchRule MatchRule) const {
164  return checkAttributeMatchRuleAppliesTo(D, MatchRule);
165}
166
167void ParsedAttr::getMatchRules(
168    const LangOptions &LangOpts,
169    SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
170    const {
171  return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts);
172}
173
174bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
175  return getInfo().diagLangOpts(S, *this);
176}
177
178bool ParsedAttr::isTargetSpecificAttr() const {
179  return getInfo().IsTargetSpecific;
180}
181
182bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; }
183
184bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; }
185
186bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {
187  return getInfo().existsInTarget(Target);
188}
189
190bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; }
191
192bool ParsedAttr::isSupportedByPragmaAttribute() const {
193  return getInfo().IsSupportedByPragmaAttribute;
194}
195
196unsigned ParsedAttr::getSemanticSpelling() const {
197  return getInfo().spellingIndexToSemanticSpelling(*this);
198}
199
200bool ParsedAttr::hasVariadicArg() const {
201  // If the attribute has the maximum number of optional arguments, we will
202  // claim that as being variadic. If we someday get an attribute that
203  // legitimately bumps up against that maximum, we can use another bit to track
204  // whether it's truly variadic or not.
205  return getInfo().OptArgs == 15;
206}
207