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 27 using namespace clang; 28 29 LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry) 30 31 IdentifierLoc *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 39 size_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 54 AttributeFactory::AttributeFactory() { 55 // Go ahead and configure all the inline capacity. This is just a memset. 56 FreeLists.resize(InlineFreeListsCapacity); 57 } 58 AttributeFactory::~AttributeFactory() = default; 59 60 static 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 66 void *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 79 void 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 96 void AttributeFactory::reclaimPool(AttributePool &cur) { 97 for (ParsedAttr *AL : cur.Attrs) 98 deallocate(AL); 99 } 100 101 void AttributePool::takePool(AttributePool &pool) { 102 Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end()); 103 pool.Attrs.clear(); 104 } 105 106 namespace { 107 108 #include "clang/Sema/AttrParsedAttrImpl.inc" 109 110 } // namespace 111 112 const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { 113 // If we have a ParsedAttrInfo for this ParsedAttr then return that. 114 if ((size_t)A.getParsedKind() < std::size(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 148 ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() { 149 return llvm::ArrayRef(AttrInfoMap); 150 } 151 152 unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } 153 154 unsigned ParsedAttr::getMaxArgs() const { 155 return getMinArgs() + getInfo().OptArgs; 156 } 157 158 unsigned ParsedAttr::getNumArgMembers() const { 159 return getInfo().NumArgMembers; 160 } 161 162 bool ParsedAttr::hasCustomParsing() const { 163 return getInfo().HasCustomParsing; 164 } 165 166 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 167 return getInfo().diagAppertainsToDecl(S, *this, D); 168 } 169 170 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const { 171 return getInfo().diagAppertainsToStmt(S, *this, St); 172 } 173 174 bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const { 175 return getInfo().diagMutualExclusion(S, *this, D); 176 } 177 178 bool ParsedAttr::appliesToDecl(const Decl *D, 179 attr::SubjectMatchRule MatchRule) const { 180 return checkAttributeMatchRuleAppliesTo(D, MatchRule); 181 } 182 183 void ParsedAttr::getMatchRules( 184 const LangOptions &LangOpts, 185 SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules) 186 const { 187 return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts); 188 } 189 190 bool ParsedAttr::diagnoseLangOpts(Sema &S) const { 191 if (getInfo().acceptsLangOpts(S.getLangOpts())) 192 return true; 193 S.Diag(getLoc(), diag::warn_attribute_ignored) << *this; 194 return false; 195 } 196 197 bool ParsedAttr::isTargetSpecificAttr() const { 198 return getInfo().IsTargetSpecific; 199 } 200 201 bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; } 202 203 bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; } 204 205 bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { 206 return getInfo().existsInTarget(Target); 207 } 208 209 bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; } 210 211 bool ParsedAttr::isSupportedByPragmaAttribute() const { 212 return getInfo().IsSupportedByPragmaAttribute; 213 } 214 215 bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const { 216 assert(isStandardAttributeSyntax()); 217 218 // We have historically allowed some type attributes with standard attribute 219 // syntax to slide to the decl-specifier-seq, so we have to keep supporting 220 // it. This property is consciously not defined as a flag in Attr.td because 221 // we don't want new attributes to specify it. 222 // 223 // Note: No new entries should be added to this list. Entries should be 224 // removed from this list after a suitable deprecation period, provided that 225 // there are no compatibility considerations with other compilers. If 226 // possible, we would like this list to go away entirely. 227 switch (getParsedKind()) { 228 case AT_AddressSpace: 229 case AT_OpenCLPrivateAddressSpace: 230 case AT_OpenCLGlobalAddressSpace: 231 case AT_OpenCLGlobalDeviceAddressSpace: 232 case AT_OpenCLGlobalHostAddressSpace: 233 case AT_OpenCLLocalAddressSpace: 234 case AT_OpenCLConstantAddressSpace: 235 case AT_OpenCLGenericAddressSpace: 236 case AT_NeonPolyVectorType: 237 case AT_NeonVectorType: 238 case AT_ArmMveStrictPolymorphism: 239 case AT_BTFTypeTag: 240 case AT_ObjCGC: 241 case AT_MatrixType: 242 return true; 243 default: 244 return false; 245 } 246 } 247 248 bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; } 249 250 unsigned ParsedAttr::getSemanticSpelling() const { 251 return getInfo().spellingIndexToSemanticSpelling(*this); 252 } 253 254 bool ParsedAttr::hasVariadicArg() const { 255 // If the attribute has the maximum number of optional arguments, we will 256 // claim that as being variadic. If we someday get an attribute that 257 // legitimately bumps up against that maximum, we can use another bit to track 258 // whether it's truly variadic or not. 259 return getInfo().OptArgs == 15; 260 } 261 262 bool ParsedAttr::isParamExpr(size_t N) const { 263 return getInfo().isParamExpr(N); 264 } 265 266 void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const { 267 ::handleAttrWithDelayedArgs(S, D, *this); 268 } 269 270 static unsigned getNumAttributeArgs(const ParsedAttr &AL) { 271 // FIXME: Include the type in the argument list. 272 return AL.getNumArgs() + AL.hasParsedType(); 273 } 274 275 template <typename Compare> 276 static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, 277 unsigned Num, unsigned Diag, 278 Compare Comp) { 279 if (Comp(getNumAttributeArgs(AL), Num)) { 280 S.Diag(AL.getLoc(), Diag) << AL << Num; 281 return false; 282 } 283 return true; 284 } 285 286 bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const { 287 return checkAttributeNumArgsImpl(S, *this, Num, 288 diag::err_attribute_wrong_number_arguments, 289 std::not_equal_to<unsigned>()); 290 } 291 bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const { 292 return checkAttributeNumArgsImpl(S, *this, Num, 293 diag::err_attribute_too_few_arguments, 294 std::less<unsigned>()); 295 } 296 bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const { 297 return checkAttributeNumArgsImpl(S, *this, Num, 298 diag::err_attribute_too_many_arguments, 299 std::greater<unsigned>()); 300 } 301 302 void clang::takeAndConcatenateAttrs(ParsedAttributes &First, 303 ParsedAttributes &Second, 304 ParsedAttributes &Result) { 305 // Note that takeAllFrom() puts the attributes at the beginning of the list, 306 // so to obtain the correct ordering, we add `Second`, then `First`. 307 Result.takeAllFrom(Second); 308 Result.takeAllFrom(First); 309 if (First.Range.getBegin().isValid()) 310 Result.Range.setBegin(First.Range.getBegin()); 311 else 312 Result.Range.setBegin(Second.Range.getBegin()); 313 if (Second.Range.getEnd().isValid()) 314 Result.Range.setEnd(Second.Range.getEnd()); 315 else 316 Result.Range.setEnd(First.Range.getEnd()); 317 } 318