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 Kind K = getParsedKind(); 197 198 // If the attribute has a target-specific spelling, check that it exists. 199 // Only call this if the attr is not ignored/unknown. For most targets, this 200 // function just returns true. 201 bool HasSpelling = K != IgnoredAttribute && K != UnknownAttribute && 202 K != NoSemaHandlerAttribute; 203 bool TargetSpecificSpellingExists = 204 !HasSpelling || 205 getInfo().spellingExistsInTarget(Target, getAttributeSpellingListIndex()); 206 207 return getInfo().existsInTarget(Target) && TargetSpecificSpellingExists; 208 } 209 210 bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; } 211 212 bool ParsedAttr::isSupportedByPragmaAttribute() const { 213 return getInfo().IsSupportedByPragmaAttribute; 214 } 215 216 bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const { 217 if (isRegularKeywordAttribute()) 218 // The appurtenance rules are applied strictly for all regular keyword 219 // atributes. 220 return false; 221 222 assert(isStandardAttributeSyntax()); 223 224 // We have historically allowed some type attributes with standard attribute 225 // syntax to slide to the decl-specifier-seq, so we have to keep supporting 226 // it. This property is consciously not defined as a flag in Attr.td because 227 // we don't want new attributes to specify it. 228 // 229 // Note: No new entries should be added to this list. Entries should be 230 // removed from this list after a suitable deprecation period, provided that 231 // there are no compatibility considerations with other compilers. If 232 // possible, we would like this list to go away entirely. 233 switch (getParsedKind()) { 234 case AT_AddressSpace: 235 case AT_OpenCLPrivateAddressSpace: 236 case AT_OpenCLGlobalAddressSpace: 237 case AT_OpenCLGlobalDeviceAddressSpace: 238 case AT_OpenCLGlobalHostAddressSpace: 239 case AT_OpenCLLocalAddressSpace: 240 case AT_OpenCLConstantAddressSpace: 241 case AT_OpenCLGenericAddressSpace: 242 case AT_NeonPolyVectorType: 243 case AT_NeonVectorType: 244 case AT_ArmMveStrictPolymorphism: 245 case AT_BTFTypeTag: 246 case AT_ObjCGC: 247 case AT_MatrixType: 248 return true; 249 default: 250 return false; 251 } 252 } 253 254 bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; } 255 256 unsigned ParsedAttr::getSemanticSpelling() const { 257 return getInfo().spellingIndexToSemanticSpelling(*this); 258 } 259 260 bool ParsedAttr::hasVariadicArg() const { 261 // If the attribute has the maximum number of optional arguments, we will 262 // claim that as being variadic. If we someday get an attribute that 263 // legitimately bumps up against that maximum, we can use another bit to track 264 // whether it's truly variadic or not. 265 return getInfo().OptArgs == 15; 266 } 267 268 bool ParsedAttr::isParamExpr(size_t N) const { 269 return getInfo().isParamExpr(N); 270 } 271 272 void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const { 273 ::handleAttrWithDelayedArgs(S, D, *this); 274 } 275 276 static unsigned getNumAttributeArgs(const ParsedAttr &AL) { 277 // FIXME: Include the type in the argument list. 278 return AL.getNumArgs() + AL.hasParsedType(); 279 } 280 281 template <typename Compare> 282 static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, 283 unsigned Num, unsigned Diag, 284 Compare Comp) { 285 if (Comp(getNumAttributeArgs(AL), Num)) { 286 S.Diag(AL.getLoc(), Diag) << AL << Num; 287 return false; 288 } 289 return true; 290 } 291 292 bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const { 293 return checkAttributeNumArgsImpl(S, *this, Num, 294 diag::err_attribute_wrong_number_arguments, 295 std::not_equal_to<unsigned>()); 296 } 297 bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const { 298 return checkAttributeNumArgsImpl(S, *this, Num, 299 diag::err_attribute_too_few_arguments, 300 std::less<unsigned>()); 301 } 302 bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const { 303 return checkAttributeNumArgsImpl(S, *this, Num, 304 diag::err_attribute_too_many_arguments, 305 std::greater<unsigned>()); 306 } 307 308 void clang::takeAndConcatenateAttrs(ParsedAttributes &First, 309 ParsedAttributes &Second, 310 ParsedAttributes &Result) { 311 // Note that takeAllFrom() puts the attributes at the beginning of the list, 312 // so to obtain the correct ordering, we add `Second`, then `First`. 313 Result.takeAllFrom(Second); 314 Result.takeAllFrom(First); 315 if (First.Range.getBegin().isValid()) 316 Result.Range.setBegin(First.Range.getBegin()); 317 else 318 Result.Range.setBegin(Second.Range.getBegin()); 319 if (Second.Range.getEnd().isValid()) 320 Result.Range.setEnd(Second.Range.getEnd()); 321 else 322 Result.Range.setEnd(First.Range.getEnd()); 323 } 324