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