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