| //===--- Attr.h - Classes for representing attributes ----------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the Attr interface and subclasses. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_AST_ATTR_H |
| #define LLVM_CLANG_AST_ATTR_H |
| |
| #include "clang/AST/ASTContextAllocate.h" // For Attrs.inc |
| #include "clang/AST/AttrIterator.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/AST/Type.h" |
| #include "clang/Basic/AttrKinds.h" |
| #include "clang/Basic/AttributeCommonInfo.h" |
| #include "clang/Basic/LLVM.h" |
| #include "clang/Basic/OpenMPKinds.h" |
| #include "clang/Basic/Sanitizers.h" |
| #include "clang/Basic/SourceLocation.h" |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/VersionTuple.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <algorithm> |
| #include <cassert> |
| |
| namespace clang { |
| class ASTContext; |
| class AttributeCommonInfo; |
| class IdentifierInfo; |
| class ObjCInterfaceDecl; |
| class Expr; |
| class QualType; |
| class FunctionDecl; |
| class TypeSourceInfo; |
| |
| /// Attr - This represents one attribute. |
| class Attr : public AttributeCommonInfo { |
| private: |
| unsigned AttrKind : 16; |
| |
| protected: |
| /// An index into the spelling list of an |
| /// attribute defined in Attr.td file. |
| unsigned Inherited : 1; |
| unsigned IsPackExpansion : 1; |
| unsigned Implicit : 1; |
| // FIXME: These are properties of the attribute kind, not state for this |
| // instance of the attribute. |
| unsigned IsLateParsed : 1; |
| unsigned InheritEvenIfAlreadyPresent : 1; |
| |
| void *operator new(size_t bytes) noexcept { |
| llvm_unreachable("Attrs cannot be allocated with regular 'new'."); |
| } |
| void operator delete(void *data) noexcept { |
| llvm_unreachable("Attrs cannot be released with regular 'delete'."); |
| } |
| |
| public: |
| // Forward so that the regular new and delete do not hide global ones. |
| void *operator new(size_t Bytes, ASTContext &C, |
| size_t Alignment = 8) noexcept { |
| return ::operator new(Bytes, C, Alignment); |
| } |
| void operator delete(void *Ptr, ASTContext &C, size_t Alignment) noexcept { |
| return ::operator delete(Ptr, C, Alignment); |
| } |
| |
| protected: |
| Attr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, |
| attr::Kind AK, bool IsLateParsed) |
| : AttributeCommonInfo(CommonInfo), AttrKind(AK), Inherited(false), |
| IsPackExpansion(false), Implicit(false), IsLateParsed(IsLateParsed), |
| InheritEvenIfAlreadyPresent(false) {} |
| |
| public: |
| attr::Kind getKind() const { return static_cast<attr::Kind>(AttrKind); } |
| |
| unsigned getSpellingListIndex() const { |
| return getAttributeSpellingListIndex(); |
| } |
| const char *getSpelling() const; |
| |
| SourceLocation getLocation() const { return getRange().getBegin(); } |
| |
| bool isInherited() const { return Inherited; } |
| |
| /// Returns true if the attribute has been implicitly created instead |
| /// of explicitly written by the user. |
| bool isImplicit() const { return Implicit; } |
| void setImplicit(bool I) { Implicit = I; } |
| |
| void setPackExpansion(bool PE) { IsPackExpansion = PE; } |
| bool isPackExpansion() const { return IsPackExpansion; } |
| |
| // Clone this attribute. |
| Attr *clone(ASTContext &C) const; |
| |
| bool isLateParsed() const { return IsLateParsed; } |
| |
| // Pretty print this attribute. |
| void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const; |
| }; |
| |
| class TypeAttr : public Attr { |
| protected: |
| TypeAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, |
| attr::Kind AK, bool IsLateParsed) |
| : Attr(Context, CommonInfo, AK, IsLateParsed) {} |
| |
| public: |
| static bool classof(const Attr *A) { |
| return A->getKind() >= attr::FirstTypeAttr && |
| A->getKind() <= attr::LastTypeAttr; |
| } |
| }; |
| |
| class StmtAttr : public Attr { |
| protected: |
| StmtAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, |
| attr::Kind AK, bool IsLateParsed) |
| : Attr(Context, CommonInfo, AK, IsLateParsed) {} |
| |
| public: |
| static bool classof(const Attr *A) { |
| return A->getKind() >= attr::FirstStmtAttr && |
| A->getKind() <= attr::LastStmtAttr; |
| } |
| }; |
| |
| class InheritableAttr : public Attr { |
| protected: |
| InheritableAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, |
| attr::Kind AK, bool IsLateParsed, |
| bool InheritEvenIfAlreadyPresent) |
| : Attr(Context, CommonInfo, AK, IsLateParsed) { |
| this->InheritEvenIfAlreadyPresent = InheritEvenIfAlreadyPresent; |
| } |
| |
| public: |
| void setInherited(bool I) { Inherited = I; } |
| |
| /// Should this attribute be inherited from a prior declaration even if it's |
| /// explicitly provided in the current declaration? |
| bool shouldInheritEvenIfAlreadyPresent() const { |
| return InheritEvenIfAlreadyPresent; |
| } |
| |
| // Implement isa/cast/dyncast/etc. |
| static bool classof(const Attr *A) { |
| return A->getKind() >= attr::FirstInheritableAttr && |
| A->getKind() <= attr::LastInheritableAttr; |
| } |
| }; |
| |
| class InheritableParamAttr : public InheritableAttr { |
| protected: |
| InheritableParamAttr(ASTContext &Context, |
| const AttributeCommonInfo &CommonInfo, attr::Kind AK, |
| bool IsLateParsed, bool InheritEvenIfAlreadyPresent) |
| : InheritableAttr(Context, CommonInfo, AK, IsLateParsed, |
| InheritEvenIfAlreadyPresent) {} |
| |
| public: |
| // Implement isa/cast/dyncast/etc. |
| static bool classof(const Attr *A) { |
| return A->getKind() >= attr::FirstInheritableParamAttr && |
| A->getKind() <= attr::LastInheritableParamAttr; |
| } |
| }; |
| |
| /// A parameter attribute which changes the argument-passing ABI rule |
| /// for the parameter. |
| class ParameterABIAttr : public InheritableParamAttr { |
| protected: |
| ParameterABIAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, |
| attr::Kind AK, bool IsLateParsed, |
| bool InheritEvenIfAlreadyPresent) |
| : InheritableParamAttr(Context, CommonInfo, AK, IsLateParsed, |
| InheritEvenIfAlreadyPresent) {} |
| |
| public: |
| ParameterABI getABI() const { |
| switch (getKind()) { |
| case attr::SwiftContext: |
| return ParameterABI::SwiftContext; |
| case attr::SwiftErrorResult: |
| return ParameterABI::SwiftErrorResult; |
| case attr::SwiftIndirectResult: |
| return ParameterABI::SwiftIndirectResult; |
| default: |
| llvm_unreachable("bad parameter ABI attribute kind"); |
| } |
| } |
| |
| static bool classof(const Attr *A) { |
| return A->getKind() >= attr::FirstParameterABIAttr && |
| A->getKind() <= attr::LastParameterABIAttr; |
| } |
| }; |
| |
| /// A single parameter index whose accessors require each use to make explicit |
| /// the parameter index encoding needed. |
| class ParamIdx { |
| // Idx is exposed only via accessors that specify specific encodings. |
| unsigned Idx : 30; |
| unsigned HasThis : 1; |
| unsigned IsValid : 1; |
| |
| void assertComparable(const ParamIdx &I) const { |
| assert(isValid() && I.isValid() && |
| "ParamIdx must be valid to be compared"); |
| // It's possible to compare indices from separate functions, but so far |
| // it's not proven useful. Moreover, it might be confusing because a |
| // comparison on the results of getASTIndex might be inconsistent with a |
| // comparison on the ParamIdx objects themselves. |
| assert(HasThis == I.HasThis && |
| "ParamIdx must be for the same function to be compared"); |
| } |
| |
| public: |
| /// Construct an invalid parameter index (\c isValid returns false and |
| /// accessors fail an assert). |
| ParamIdx() : Idx(0), HasThis(false), IsValid(false) {} |
| |
| /// \param Idx is the parameter index as it is normally specified in |
| /// attributes in the source: one-origin including any C++ implicit this |
| /// parameter. |
| /// |
| /// \param D is the declaration containing the parameters. It is used to |
| /// determine if there is a C++ implicit this parameter. |
| ParamIdx(unsigned Idx, const Decl *D) |
| : Idx(Idx), HasThis(false), IsValid(true) { |
| assert(Idx >= 1 && "Idx must be one-origin"); |
| if (const auto *FD = dyn_cast<FunctionDecl>(D)) |
| HasThis = FD->isCXXInstanceMember(); |
| } |
| |
| /// A type into which \c ParamIdx can be serialized. |
| /// |
| /// A static assertion that it's of the correct size follows the \c ParamIdx |
| /// class definition. |
| typedef uint32_t SerialType; |
| |
| /// Produce a representation that can later be passed to \c deserialize to |
| /// construct an equivalent \c ParamIdx. |
| SerialType serialize() const { |
| return *reinterpret_cast<const SerialType *>(this); |
| } |
| |
| /// Construct from a result from \c serialize. |
| static ParamIdx deserialize(SerialType S) { |
| ParamIdx P(*reinterpret_cast<ParamIdx *>(&S)); |
| assert((!P.IsValid || P.Idx >= 1) && "valid Idx must be one-origin"); |
| return P; |
| } |
| |
| /// Is this parameter index valid? |
| bool isValid() const { return IsValid; } |
| |
| /// Get the parameter index as it would normally be encoded for attributes at |
| /// the source level of representation: one-origin including any C++ implicit |
| /// this parameter. |
| /// |
| /// This encoding thus makes sense for diagnostics, pretty printing, and |
| /// constructing new attributes from a source-like specification. |
| unsigned getSourceIndex() const { |
| assert(isValid() && "ParamIdx must be valid"); |
| return Idx; |
| } |
| |
| /// Get the parameter index as it would normally be encoded at the AST level |
| /// of representation: zero-origin not including any C++ implicit this |
| /// parameter. |
| /// |
| /// This is the encoding primarily used in Sema. However, in diagnostics, |
| /// Sema uses \c getSourceIndex instead. |
| unsigned getASTIndex() const { |
| assert(isValid() && "ParamIdx must be valid"); |
| assert(Idx >= 1 + HasThis && |
| "stored index must be base-1 and not specify C++ implicit this"); |
| return Idx - 1 - HasThis; |
| } |
| |
| /// Get the parameter index as it would normally be encoded at the LLVM level |
| /// of representation: zero-origin including any C++ implicit this parameter. |
| /// |
| /// This is the encoding primarily used in CodeGen. |
| unsigned getLLVMIndex() const { |
| assert(isValid() && "ParamIdx must be valid"); |
| assert(Idx >= 1 && "stored index must be base-1"); |
| return Idx - 1; |
| } |
| |
| bool operator==(const ParamIdx &I) const { |
| assertComparable(I); |
| return Idx == I.Idx; |
| } |
| bool operator!=(const ParamIdx &I) const { |
| assertComparable(I); |
| return Idx != I.Idx; |
| } |
| bool operator<(const ParamIdx &I) const { |
| assertComparable(I); |
| return Idx < I.Idx; |
| } |
| bool operator>(const ParamIdx &I) const { |
| assertComparable(I); |
| return Idx > I.Idx; |
| } |
| bool operator<=(const ParamIdx &I) const { |
| assertComparable(I); |
| return Idx <= I.Idx; |
| } |
| bool operator>=(const ParamIdx &I) const { |
| assertComparable(I); |
| return Idx >= I.Idx; |
| } |
| }; |
| |
| static_assert(sizeof(ParamIdx) == sizeof(ParamIdx::SerialType), |
| "ParamIdx does not fit its serialization type"); |
| |
| #include "clang/AST/Attrs.inc" |
| |
| inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, |
| const Attr *At) { |
| DB.AddTaggedVal(reinterpret_cast<intptr_t>(At), |
| DiagnosticsEngine::ak_attr); |
| return DB; |
| } |
| |
| inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, |
| const Attr *At) { |
| PD.AddTaggedVal(reinterpret_cast<intptr_t>(At), |
| DiagnosticsEngine::ak_attr); |
| return PD; |
| } |
| } // end namespace clang |
| |
| #endif |