1 //===--- Attr.h - Classes for representing attributes ----------*- C++ -*-===// 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 Attr interface and subclasses. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CLANG_AST_ATTR_H 14 #define LLVM_CLANG_AST_ATTR_H 15 16 #include "clang/AST/ASTFwd.h" 17 #include "clang/AST/AttrIterator.h" 18 #include "clang/AST/Decl.h" 19 #include "clang/AST/Type.h" 20 #include "clang/Basic/AttrKinds.h" 21 #include "clang/Basic/AttributeCommonInfo.h" 22 #include "clang/Basic/LangOptions.h" 23 #include "clang/Basic/LLVM.h" 24 #include "clang/Basic/OpenMPKinds.h" 25 #include "clang/Basic/Sanitizers.h" 26 #include "clang/Basic/SourceLocation.h" 27 #include "llvm/ADT/StringSwitch.h" 28 #include "llvm/Support/ErrorHandling.h" 29 #include "llvm/Support/VersionTuple.h" 30 #include "llvm/Support/raw_ostream.h" 31 #include <algorithm> 32 #include <cassert> 33 34 namespace clang { 35 class ASTContext; 36 class AttributeCommonInfo; 37 class FunctionDecl; 38 class OMPTraitInfo; 39 40 /// Attr - This represents one attribute. 41 class Attr : public AttributeCommonInfo { 42 private: 43 unsigned AttrKind : 16; 44 45 protected: 46 /// An index into the spelling list of an 47 /// attribute defined in Attr.td file. 48 unsigned Inherited : 1; 49 unsigned IsPackExpansion : 1; 50 unsigned Implicit : 1; 51 // FIXME: These are properties of the attribute kind, not state for this 52 // instance of the attribute. 53 unsigned IsLateParsed : 1; 54 unsigned InheritEvenIfAlreadyPresent : 1; 55 56 void *operator new(size_t bytes) noexcept { 57 llvm_unreachable("Attrs cannot be allocated with regular 'new'."); 58 } 59 void operator delete(void *data) noexcept { 60 llvm_unreachable("Attrs cannot be released with regular 'delete'."); 61 } 62 63 public: 64 // Forward so that the regular new and delete do not hide global ones. 65 void *operator new(size_t Bytes, ASTContext &C, 66 size_t Alignment = 8) noexcept { 67 return ::operator new(Bytes, C, Alignment); 68 } 69 void operator delete(void *Ptr, ASTContext &C, size_t Alignment) noexcept { 70 return ::operator delete(Ptr, C, Alignment); 71 } 72 73 protected: 74 Attr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, 75 attr::Kind AK, bool IsLateParsed) 76 : AttributeCommonInfo(CommonInfo), AttrKind(AK), Inherited(false), 77 IsPackExpansion(false), Implicit(false), IsLateParsed(IsLateParsed), 78 InheritEvenIfAlreadyPresent(false) {} 79 80 public: 81 attr::Kind getKind() const { return static_cast<attr::Kind>(AttrKind); } 82 83 unsigned getSpellingListIndex() const { 84 return getAttributeSpellingListIndex(); 85 } 86 const char *getSpelling() const; 87 88 SourceLocation getLocation() const { return getRange().getBegin(); } 89 90 bool isInherited() const { return Inherited; } 91 92 /// Returns true if the attribute has been implicitly created instead 93 /// of explicitly written by the user. 94 bool isImplicit() const { return Implicit; } 95 void setImplicit(bool I) { Implicit = I; } 96 97 void setPackExpansion(bool PE) { IsPackExpansion = PE; } 98 bool isPackExpansion() const { return IsPackExpansion; } 99 100 // Clone this attribute. 101 Attr *clone(ASTContext &C) const; 102 103 bool isLateParsed() const { return IsLateParsed; } 104 105 // Pretty print this attribute. 106 void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const; 107 108 static StringRef getDocumentation(attr::Kind); 109 }; 110 111 class TypeAttr : public Attr { 112 protected: 113 TypeAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, 114 attr::Kind AK, bool IsLateParsed) 115 : Attr(Context, CommonInfo, AK, IsLateParsed) {} 116 117 public: 118 static bool classof(const Attr *A) { 119 return A->getKind() >= attr::FirstTypeAttr && 120 A->getKind() <= attr::LastTypeAttr; 121 } 122 }; 123 124 class StmtAttr : public Attr { 125 protected: 126 StmtAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, 127 attr::Kind AK, bool IsLateParsed) 128 : Attr(Context, CommonInfo, AK, IsLateParsed) {} 129 130 public: 131 static bool classof(const Attr *A) { 132 return A->getKind() >= attr::FirstStmtAttr && 133 A->getKind() <= attr::LastStmtAttr; 134 } 135 }; 136 137 class InheritableAttr : public Attr { 138 protected: 139 InheritableAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, 140 attr::Kind AK, bool IsLateParsed, 141 bool InheritEvenIfAlreadyPresent) 142 : Attr(Context, CommonInfo, AK, IsLateParsed) { 143 this->InheritEvenIfAlreadyPresent = InheritEvenIfAlreadyPresent; 144 } 145 146 public: 147 void setInherited(bool I) { Inherited = I; } 148 149 /// Should this attribute be inherited from a prior declaration even if it's 150 /// explicitly provided in the current declaration? 151 bool shouldInheritEvenIfAlreadyPresent() const { 152 return InheritEvenIfAlreadyPresent; 153 } 154 155 // Implement isa/cast/dyncast/etc. 156 static bool classof(const Attr *A) { 157 return A->getKind() >= attr::FirstInheritableAttr && 158 A->getKind() <= attr::LastInheritableAttr; 159 } 160 }; 161 162 class DeclOrStmtAttr : public InheritableAttr { 163 protected: 164 DeclOrStmtAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, 165 attr::Kind AK, bool IsLateParsed, 166 bool InheritEvenIfAlreadyPresent) 167 : InheritableAttr(Context, CommonInfo, AK, IsLateParsed, 168 InheritEvenIfAlreadyPresent) {} 169 170 public: 171 static bool classof(const Attr *A) { 172 return A->getKind() >= attr::FirstDeclOrStmtAttr && 173 A->getKind() <= attr::LastDeclOrStmtAttr; 174 } 175 }; 176 177 class InheritableParamAttr : public InheritableAttr { 178 protected: 179 InheritableParamAttr(ASTContext &Context, 180 const AttributeCommonInfo &CommonInfo, attr::Kind AK, 181 bool IsLateParsed, bool InheritEvenIfAlreadyPresent) 182 : InheritableAttr(Context, CommonInfo, AK, IsLateParsed, 183 InheritEvenIfAlreadyPresent) {} 184 185 public: 186 // Implement isa/cast/dyncast/etc. 187 static bool classof(const Attr *A) { 188 return A->getKind() >= attr::FirstInheritableParamAttr && 189 A->getKind() <= attr::LastInheritableParamAttr; 190 } 191 }; 192 193 /// A parameter attribute which changes the argument-passing ABI rule 194 /// for the parameter. 195 class ParameterABIAttr : public InheritableParamAttr { 196 protected: 197 ParameterABIAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, 198 attr::Kind AK, bool IsLateParsed, 199 bool InheritEvenIfAlreadyPresent) 200 : InheritableParamAttr(Context, CommonInfo, AK, IsLateParsed, 201 InheritEvenIfAlreadyPresent) {} 202 203 public: 204 ParameterABI getABI() const { 205 switch (getKind()) { 206 case attr::SwiftContext: 207 return ParameterABI::SwiftContext; 208 case attr::SwiftAsyncContext: 209 return ParameterABI::SwiftAsyncContext; 210 case attr::SwiftErrorResult: 211 return ParameterABI::SwiftErrorResult; 212 case attr::SwiftIndirectResult: 213 return ParameterABI::SwiftIndirectResult; 214 default: 215 llvm_unreachable("bad parameter ABI attribute kind"); 216 } 217 } 218 219 static bool classof(const Attr *A) { 220 return A->getKind() >= attr::FirstParameterABIAttr && 221 A->getKind() <= attr::LastParameterABIAttr; 222 } 223 }; 224 225 /// A single parameter index whose accessors require each use to make explicit 226 /// the parameter index encoding needed. 227 class ParamIdx { 228 // Idx is exposed only via accessors that specify specific encodings. 229 unsigned Idx : 30; 230 unsigned HasThis : 1; 231 unsigned IsValid : 1; 232 233 void assertComparable(const ParamIdx &I) const { 234 assert(isValid() && I.isValid() && 235 "ParamIdx must be valid to be compared"); 236 // It's possible to compare indices from separate functions, but so far 237 // it's not proven useful. Moreover, it might be confusing because a 238 // comparison on the results of getASTIndex might be inconsistent with a 239 // comparison on the ParamIdx objects themselves. 240 assert(HasThis == I.HasThis && 241 "ParamIdx must be for the same function to be compared"); 242 } 243 244 public: 245 /// Construct an invalid parameter index (\c isValid returns false and 246 /// accessors fail an assert). 247 ParamIdx() : Idx(0), HasThis(false), IsValid(false) {} 248 249 /// \param Idx is the parameter index as it is normally specified in 250 /// attributes in the source: one-origin including any C++ implicit this 251 /// parameter. 252 /// 253 /// \param D is the declaration containing the parameters. It is used to 254 /// determine if there is a C++ implicit this parameter. 255 ParamIdx(unsigned Idx, const Decl *D) 256 : Idx(Idx), HasThis(false), IsValid(true) { 257 assert(Idx >= 1 && "Idx must be one-origin"); 258 if (const auto *FD = dyn_cast<FunctionDecl>(D)) 259 HasThis = FD->isCXXInstanceMember(); 260 } 261 262 /// A type into which \c ParamIdx can be serialized. 263 /// 264 /// A static assertion that it's of the correct size follows the \c ParamIdx 265 /// class definition. 266 typedef uint32_t SerialType; 267 268 /// Produce a representation that can later be passed to \c deserialize to 269 /// construct an equivalent \c ParamIdx. 270 SerialType serialize() const { 271 return *reinterpret_cast<const SerialType *>(this); 272 } 273 274 /// Construct from a result from \c serialize. 275 static ParamIdx deserialize(SerialType S) { 276 // Using this two-step static_cast via void * instead of reinterpret_cast 277 // silences a -Wstrict-aliasing false positive from GCC7 and earlier. 278 void *ParamIdxPtr = static_cast<void *>(&S); 279 ParamIdx P(*static_cast<ParamIdx *>(ParamIdxPtr)); 280 assert((!P.IsValid || P.Idx >= 1) && "valid Idx must be one-origin"); 281 return P; 282 } 283 284 /// Is this parameter index valid? 285 bool isValid() const { return IsValid; } 286 287 /// Get the parameter index as it would normally be encoded for attributes at 288 /// the source level of representation: one-origin including any C++ implicit 289 /// this parameter. 290 /// 291 /// This encoding thus makes sense for diagnostics, pretty printing, and 292 /// constructing new attributes from a source-like specification. 293 unsigned getSourceIndex() const { 294 assert(isValid() && "ParamIdx must be valid"); 295 return Idx; 296 } 297 298 /// Get the parameter index as it would normally be encoded at the AST level 299 /// of representation: zero-origin not including any C++ implicit this 300 /// parameter. 301 /// 302 /// This is the encoding primarily used in Sema. However, in diagnostics, 303 /// Sema uses \c getSourceIndex instead. 304 unsigned getASTIndex() const { 305 assert(isValid() && "ParamIdx must be valid"); 306 assert(Idx >= 1 + HasThis && 307 "stored index must be base-1 and not specify C++ implicit this"); 308 return Idx - 1 - HasThis; 309 } 310 311 /// Get the parameter index as it would normally be encoded at the LLVM level 312 /// of representation: zero-origin including any C++ implicit this parameter. 313 /// 314 /// This is the encoding primarily used in CodeGen. 315 unsigned getLLVMIndex() const { 316 assert(isValid() && "ParamIdx must be valid"); 317 assert(Idx >= 1 && "stored index must be base-1"); 318 return Idx - 1; 319 } 320 321 bool operator==(const ParamIdx &I) const { 322 assertComparable(I); 323 return Idx == I.Idx; 324 } 325 bool operator!=(const ParamIdx &I) const { 326 assertComparable(I); 327 return Idx != I.Idx; 328 } 329 bool operator<(const ParamIdx &I) const { 330 assertComparable(I); 331 return Idx < I.Idx; 332 } 333 bool operator>(const ParamIdx &I) const { 334 assertComparable(I); 335 return Idx > I.Idx; 336 } 337 bool operator<=(const ParamIdx &I) const { 338 assertComparable(I); 339 return Idx <= I.Idx; 340 } 341 bool operator>=(const ParamIdx &I) const { 342 assertComparable(I); 343 return Idx >= I.Idx; 344 } 345 }; 346 347 static_assert(sizeof(ParamIdx) == sizeof(ParamIdx::SerialType), 348 "ParamIdx does not fit its serialization type"); 349 350 /// Contains information gathered from parsing the contents of TargetAttr. 351 struct ParsedTargetAttr { 352 std::vector<std::string> Features; 353 StringRef Architecture; 354 StringRef Tune; 355 StringRef BranchProtection; 356 bool DuplicateArchitecture = false; 357 bool DuplicateTune = false; 358 bool operator ==(const ParsedTargetAttr &Other) const { 359 return DuplicateArchitecture == Other.DuplicateArchitecture && 360 DuplicateTune == Other.DuplicateTune && 361 Architecture == Other.Architecture && 362 Tune == Other.Tune && 363 BranchProtection == Other.BranchProtection && 364 Features == Other.Features; 365 } 366 }; 367 368 #include "clang/AST/Attrs.inc" 369 370 inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, 371 const Attr *At) { 372 DB.AddTaggedVal(reinterpret_cast<uint64_t>(At), DiagnosticsEngine::ak_attr); 373 return DB; 374 } 375 } // end namespace clang 376 377 #endif 378