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