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