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