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 void AttributePool::takeFrom(ParsedAttributesView &List, AttributePool &Pool) { 104 assert(&Pool != this && "AttributePool can't take attributes from itself"); 105 llvm::for_each(List.AttrList, [&Pool](ParsedAttr *A) { Pool.remove(A); }); 106 Attrs.insert(Attrs.end(), List.AttrList.begin(), List.AttrList.end()); 107 } 108 109 namespace { 110 111 #include "clang/Sema/AttrParsedAttrImpl.inc" 112 113 } // namespace 114 115 const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { 116 // If we have a ParsedAttrInfo for this ParsedAttr then return that. 117 if ((size_t)A.getParsedKind() < std::size(AttrInfoMap)) 118 return *AttrInfoMap[A.getParsedKind()]; 119 120 // If this is an ignored attribute then return an appropriate ParsedAttrInfo. 121 static const ParsedAttrInfo IgnoredParsedAttrInfo( 122 AttributeCommonInfo::IgnoredAttribute); 123 if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute) 124 return IgnoredParsedAttrInfo; 125 126 // Otherwise this may be an attribute defined by a plugin. 127 128 // Search for a ParsedAttrInfo whose name and syntax match. 129 std::string FullName = A.getNormalizedFullName(); 130 AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax(); 131 if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword) 132 SyntaxUsed = AttributeCommonInfo::AS_Keyword; 133 134 for (auto &Ptr : getAttributePluginInstances()) 135 if (Ptr->hasSpelling(SyntaxUsed, FullName)) 136 return *Ptr; 137 138 // If we failed to find a match then return a default ParsedAttrInfo. 139 static const ParsedAttrInfo DefaultParsedAttrInfo( 140 AttributeCommonInfo::UnknownAttribute); 141 return DefaultParsedAttrInfo; 142 } 143 144 ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() { 145 return llvm::ArrayRef(AttrInfoMap); 146 } 147 148 unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } 149 150 unsigned ParsedAttr::getMaxArgs() const { 151 return getMinArgs() + getInfo().OptArgs; 152 } 153 154 unsigned ParsedAttr::getNumArgMembers() const { 155 return getInfo().NumArgMembers; 156 } 157 158 bool ParsedAttr::hasCustomParsing() const { 159 return getInfo().HasCustomParsing; 160 } 161 162 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 163 return getInfo().diagAppertainsToDecl(S, *this, D); 164 } 165 166 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const { 167 return getInfo().diagAppertainsToStmt(S, *this, St); 168 } 169 170 bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const { 171 return getInfo().diagMutualExclusion(S, *this, D); 172 } 173 174 bool ParsedAttr::appliesToDecl(const Decl *D, 175 attr::SubjectMatchRule MatchRule) const { 176 return checkAttributeMatchRuleAppliesTo(D, MatchRule); 177 } 178 179 void ParsedAttr::getMatchRules( 180 const LangOptions &LangOpts, 181 SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules) 182 const { 183 return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts); 184 } 185 186 bool ParsedAttr::diagnoseLangOpts(Sema &S) const { 187 if (getInfo().acceptsLangOpts(S.getLangOpts())) 188 return true; 189 S.Diag(getLoc(), diag::warn_attribute_ignored) << *this; 190 return false; 191 } 192 193 bool ParsedAttr::isTargetSpecificAttr() const { 194 return getInfo().IsTargetSpecific; 195 } 196 197 bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; } 198 199 bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; } 200 201 bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { 202 Kind K = getParsedKind(); 203 204 // If the attribute has a target-specific spelling, check that it exists. 205 // Only call this if the attr is not ignored/unknown. For most targets, this 206 // function just returns true. 207 bool HasSpelling = K != IgnoredAttribute && K != UnknownAttribute && 208 K != NoSemaHandlerAttribute; 209 bool TargetSpecificSpellingExists = 210 !HasSpelling || 211 getInfo().spellingExistsInTarget(Target, getAttributeSpellingListIndex()); 212 213 return getInfo().existsInTarget(Target) && TargetSpecificSpellingExists; 214 } 215 216 bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; } 217 218 bool ParsedAttr::isSupportedByPragmaAttribute() const { 219 return getInfo().IsSupportedByPragmaAttribute; 220 } 221 222 bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const { 223 if (isRegularKeywordAttribute()) 224 // The appurtenance rules are applied strictly for all regular keyword 225 // atributes. 226 return false; 227 228 assert(isStandardAttributeSyntax() || isAlignas()); 229 230 // We have historically allowed some type attributes with standard attribute 231 // syntax to slide to the decl-specifier-seq, so we have to keep supporting 232 // it. This property is consciously not defined as a flag in Attr.td because 233 // we don't want new attributes to specify it. 234 // 235 // Note: No new entries should be added to this list. Entries should be 236 // removed from this list after a suitable deprecation period, provided that 237 // there are no compatibility considerations with other compilers. If 238 // possible, we would like this list to go away entirely. 239 switch (getParsedKind()) { 240 case AT_AddressSpace: 241 case AT_OpenCLPrivateAddressSpace: 242 case AT_OpenCLGlobalAddressSpace: 243 case AT_OpenCLGlobalDeviceAddressSpace: 244 case AT_OpenCLGlobalHostAddressSpace: 245 case AT_OpenCLLocalAddressSpace: 246 case AT_OpenCLConstantAddressSpace: 247 case AT_OpenCLGenericAddressSpace: 248 case AT_NeonPolyVectorType: 249 case AT_NeonVectorType: 250 case AT_ArmMveStrictPolymorphism: 251 case AT_BTFTypeTag: 252 case AT_ObjCGC: 253 case AT_MatrixType: 254 return true; 255 default: 256 return false; 257 } 258 } 259 260 bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; } 261 262 unsigned ParsedAttr::getSemanticSpelling() const { 263 return getInfo().spellingIndexToSemanticSpelling(*this); 264 } 265 266 bool ParsedAttr::hasVariadicArg() const { 267 // If the attribute has the maximum number of optional arguments, we will 268 // claim that as being variadic. If we someday get an attribute that 269 // legitimately bumps up against that maximum, we can use another bit to track 270 // whether it's truly variadic or not. 271 return getInfo().OptArgs == 15; 272 } 273 274 bool ParsedAttr::isParamExpr(size_t N) const { 275 return getInfo().isParamExpr(N); 276 } 277 278 void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const { 279 ::handleAttrWithDelayedArgs(S, D, *this); 280 } 281 282 static unsigned getNumAttributeArgs(const ParsedAttr &AL) { 283 // FIXME: Include the type in the argument list. 284 return AL.getNumArgs() + AL.hasParsedType(); 285 } 286 287 template <typename Compare> 288 static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, 289 unsigned Num, unsigned Diag, 290 Compare Comp) { 291 if (Comp(getNumAttributeArgs(AL), Num)) { 292 S.Diag(AL.getLoc(), Diag) << AL << Num; 293 return false; 294 } 295 return true; 296 } 297 298 bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const { 299 return checkAttributeNumArgsImpl(S, *this, Num, 300 diag::err_attribute_wrong_number_arguments, 301 std::not_equal_to<unsigned>()); 302 } 303 bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const { 304 return checkAttributeNumArgsImpl(S, *this, Num, 305 diag::err_attribute_too_few_arguments, 306 std::less<unsigned>()); 307 } 308 bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const { 309 return checkAttributeNumArgsImpl(S, *this, Num, 310 diag::err_attribute_too_many_arguments, 311 std::greater<unsigned>()); 312 } 313 314 void clang::takeAndConcatenateAttrs(ParsedAttributes &First, 315 ParsedAttributes &Second, 316 ParsedAttributes &Result) { 317 // Note that takeAllFrom() puts the attributes at the beginning of the list, 318 // so to obtain the correct ordering, we add `Second`, then `First`. 319 Result.takeAllFrom(Second); 320 Result.takeAllFrom(First); 321 if (First.Range.getBegin().isValid()) 322 Result.Range.setBegin(First.Range.getBegin()); 323 else 324 Result.Range.setBegin(Second.Range.getBegin()); 325 if (Second.Range.getEnd().isValid()) 326 Result.Range.setEnd(Second.Range.getEnd()); 327 else 328 Result.Range.setEnd(First.Range.getEnd()); 329 } 330