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