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 <cassert> 23 #include <cstddef> 24 #include <utility> 25 26 using namespace clang; 27 28 IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc, 29 IdentifierInfo *Ident) { 30 IdentifierLoc *Result = new (Ctx) IdentifierLoc; 31 Result->Loc = Loc; 32 Result->Ident = Ident; 33 return Result; 34 } 35 36 size_t ParsedAttr::allocated_size() const { 37 if (IsAvailability) return AttributeFactory::AvailabilityAllocSize; 38 else if (IsTypeTagForDatatype) 39 return AttributeFactory::TypeTagForDatatypeAllocSize; 40 else if (IsProperty) 41 return AttributeFactory::PropertyAllocSize; 42 else if (HasParsedType) 43 return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, 44 detail::TypeTagForDatatypeData, ParsedType, 45 detail::PropertyData>(0, 0, 0, 1, 0); 46 return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, 47 detail::TypeTagForDatatypeData, ParsedType, 48 detail::PropertyData>(NumArgs, 0, 0, 0, 0); 49 } 50 51 AttributeFactory::AttributeFactory() { 52 // Go ahead and configure all the inline capacity. This is just a memset. 53 FreeLists.resize(InlineFreeListsCapacity); 54 } 55 AttributeFactory::~AttributeFactory() = default; 56 57 static size_t getFreeListIndexForSize(size_t size) { 58 assert(size >= sizeof(ParsedAttr)); 59 assert((size % sizeof(void*)) == 0); 60 return ((size - sizeof(ParsedAttr)) / sizeof(void *)); 61 } 62 63 void *AttributeFactory::allocate(size_t size) { 64 // Check for a previously reclaimed attribute. 65 size_t index = getFreeListIndexForSize(size); 66 if (index < FreeLists.size() && !FreeLists[index].empty()) { 67 ParsedAttr *attr = FreeLists[index].back(); 68 FreeLists[index].pop_back(); 69 return attr; 70 } 71 72 // Otherwise, allocate something new. 73 return Alloc.Allocate(size, alignof(AttributeFactory)); 74 } 75 76 void AttributeFactory::deallocate(ParsedAttr *Attr) { 77 size_t size = Attr->allocated_size(); 78 size_t freeListIndex = getFreeListIndexForSize(size); 79 80 // Expand FreeLists to the appropriate size, if required. 81 if (freeListIndex >= FreeLists.size()) 82 FreeLists.resize(freeListIndex + 1); 83 84 #ifndef NDEBUG 85 // In debug mode, zero out the attribute to help find memory overwriting. 86 memset(Attr, 0, size); 87 #endif 88 89 // Add 'Attr' to the appropriate free-list. 90 FreeLists[freeListIndex].push_back(Attr); 91 } 92 93 void AttributeFactory::reclaimPool(AttributePool &cur) { 94 for (ParsedAttr *AL : cur.Attrs) 95 deallocate(AL); 96 } 97 98 void AttributePool::takePool(AttributePool &pool) { 99 Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end()); 100 pool.Attrs.clear(); 101 } 102 103 namespace { 104 105 #include "clang/Sema/AttrParsedAttrImpl.inc" 106 107 } // namespace 108 109 const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { 110 // If we have a ParsedAttrInfo for this ParsedAttr then return that. 111 if ((size_t)A.getParsedKind() < std::size(AttrInfoMap)) 112 return *AttrInfoMap[A.getParsedKind()]; 113 114 // If this is an ignored attribute then return an appropriate ParsedAttrInfo. 115 static const ParsedAttrInfo IgnoredParsedAttrInfo( 116 AttributeCommonInfo::IgnoredAttribute); 117 if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute) 118 return IgnoredParsedAttrInfo; 119 120 // Otherwise this may be an attribute defined by a plugin. 121 122 // Search for a ParsedAttrInfo whose name and syntax match. 123 std::string FullName = A.getNormalizedFullName(); 124 AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax(); 125 if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword) 126 SyntaxUsed = AttributeCommonInfo::AS_Keyword; 127 128 for (auto &Ptr : getAttributePluginInstances()) 129 if (Ptr->hasSpelling(SyntaxUsed, FullName)) 130 return *Ptr; 131 132 // If we failed to find a match then return a default ParsedAttrInfo. 133 static const ParsedAttrInfo DefaultParsedAttrInfo( 134 AttributeCommonInfo::UnknownAttribute); 135 return DefaultParsedAttrInfo; 136 } 137 138 ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() { 139 return llvm::ArrayRef(AttrInfoMap); 140 } 141 142 unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } 143 144 unsigned ParsedAttr::getMaxArgs() const { 145 return getMinArgs() + getInfo().OptArgs; 146 } 147 148 unsigned ParsedAttr::getNumArgMembers() const { 149 return getInfo().NumArgMembers; 150 } 151 152 bool ParsedAttr::hasCustomParsing() const { 153 return getInfo().HasCustomParsing; 154 } 155 156 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 157 return getInfo().diagAppertainsToDecl(S, *this, D); 158 } 159 160 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const { 161 return getInfo().diagAppertainsToStmt(S, *this, St); 162 } 163 164 bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const { 165 return getInfo().diagMutualExclusion(S, *this, D); 166 } 167 168 bool ParsedAttr::appliesToDecl(const Decl *D, 169 attr::SubjectMatchRule MatchRule) const { 170 return checkAttributeMatchRuleAppliesTo(D, MatchRule); 171 } 172 173 void ParsedAttr::getMatchRules( 174 const LangOptions &LangOpts, 175 SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules) 176 const { 177 return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts); 178 } 179 180 bool ParsedAttr::diagnoseLangOpts(Sema &S) const { 181 if (getInfo().acceptsLangOpts(S.getLangOpts())) 182 return true; 183 S.Diag(getLoc(), diag::warn_attribute_ignored) << *this; 184 return false; 185 } 186 187 bool ParsedAttr::isTargetSpecificAttr() const { 188 return getInfo().IsTargetSpecific; 189 } 190 191 bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; } 192 193 bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; } 194 195 bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { 196 return getInfo().existsInTarget(Target); 197 } 198 199 bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; } 200 201 bool ParsedAttr::isSupportedByPragmaAttribute() const { 202 return getInfo().IsSupportedByPragmaAttribute; 203 } 204 205 bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const { 206 if (isRegularKeywordAttribute()) 207 // The appurtenance rules are applied strictly for all regular keyword 208 // atributes. 209 return false; 210 211 assert(isStandardAttributeSyntax()); 212 213 // We have historically allowed some type attributes with standard attribute 214 // syntax to slide to the decl-specifier-seq, so we have to keep supporting 215 // it. This property is consciously not defined as a flag in Attr.td because 216 // we don't want new attributes to specify it. 217 // 218 // Note: No new entries should be added to this list. Entries should be 219 // removed from this list after a suitable deprecation period, provided that 220 // there are no compatibility considerations with other compilers. If 221 // possible, we would like this list to go away entirely. 222 switch (getParsedKind()) { 223 case AT_AddressSpace: 224 case AT_OpenCLPrivateAddressSpace: 225 case AT_OpenCLGlobalAddressSpace: 226 case AT_OpenCLGlobalDeviceAddressSpace: 227 case AT_OpenCLGlobalHostAddressSpace: 228 case AT_OpenCLLocalAddressSpace: 229 case AT_OpenCLConstantAddressSpace: 230 case AT_OpenCLGenericAddressSpace: 231 case AT_NeonPolyVectorType: 232 case AT_NeonVectorType: 233 case AT_ArmMveStrictPolymorphism: 234 case AT_BTFTypeTag: 235 case AT_ObjCGC: 236 case AT_MatrixType: 237 return true; 238 default: 239 return false; 240 } 241 } 242 243 bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; } 244 245 unsigned ParsedAttr::getSemanticSpelling() const { 246 return getInfo().spellingIndexToSemanticSpelling(*this); 247 } 248 249 bool ParsedAttr::hasVariadicArg() const { 250 // If the attribute has the maximum number of optional arguments, we will 251 // claim that as being variadic. If we someday get an attribute that 252 // legitimately bumps up against that maximum, we can use another bit to track 253 // whether it's truly variadic or not. 254 return getInfo().OptArgs == 15; 255 } 256 257 bool ParsedAttr::isParamExpr(size_t N) const { 258 return getInfo().isParamExpr(N); 259 } 260 261 void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const { 262 ::handleAttrWithDelayedArgs(S, D, *this); 263 } 264 265 static unsigned getNumAttributeArgs(const ParsedAttr &AL) { 266 // FIXME: Include the type in the argument list. 267 return AL.getNumArgs() + AL.hasParsedType(); 268 } 269 270 template <typename Compare> 271 static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, 272 unsigned Num, unsigned Diag, 273 Compare Comp) { 274 if (Comp(getNumAttributeArgs(AL), Num)) { 275 S.Diag(AL.getLoc(), Diag) << AL << Num; 276 return false; 277 } 278 return true; 279 } 280 281 bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const { 282 return checkAttributeNumArgsImpl(S, *this, Num, 283 diag::err_attribute_wrong_number_arguments, 284 std::not_equal_to<unsigned>()); 285 } 286 bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const { 287 return checkAttributeNumArgsImpl(S, *this, Num, 288 diag::err_attribute_too_few_arguments, 289 std::less<unsigned>()); 290 } 291 bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const { 292 return checkAttributeNumArgsImpl(S, *this, Num, 293 diag::err_attribute_too_many_arguments, 294 std::greater<unsigned>()); 295 } 296 297 void clang::takeAndConcatenateAttrs(ParsedAttributes &First, 298 ParsedAttributes &Second, 299 ParsedAttributes &Result) { 300 // Note that takeAllFrom() puts the attributes at the beginning of the list, 301 // so to obtain the correct ordering, we add `Second`, then `First`. 302 Result.takeAllFrom(Second); 303 Result.takeAllFrom(First); 304 if (First.Range.getBegin().isValid()) 305 Result.Range.setBegin(First.Range.getBegin()); 306 else 307 Result.Range.setBegin(Second.Range.getBegin()); 308 if (Second.Range.getEnd().isValid()) 309 Result.Range.setEnd(Second.Range.getEnd()); 310 else 311 Result.Range.setEnd(First.Range.getEnd()); 312 } 313