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