clang 23.0.0git
AttrImpl.cpp
Go to the documentation of this file.
1//===--- AttrImpl.cpp - 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 contains out-of-line methods for Attr classes.
10//
11//===----------------------------------------------------------------------===//
12
15#include "clang/AST/Attr.h"
16#include "clang/AST/Expr.h"
17#include "clang/AST/Type.h"
18#include <optional>
19#include <type_traits>
20using namespace clang;
21
22void LoopHintAttr::printPrettyPragma(raw_ostream &OS,
23 const PrintingPolicy &Policy) const {
24 unsigned SpellingIndex = getAttributeSpellingListIndex();
25 // For "#pragma unroll" and "#pragma nounroll" the string "unroll" or
26 // "nounroll" is already emitted as the pragma name.
27 if (SpellingIndex == Pragma_nounroll ||
28 SpellingIndex == Pragma_nounroll_and_jam)
29 return;
30 else if (SpellingIndex == Pragma_unroll ||
31 SpellingIndex == Pragma_unroll_and_jam) {
32 OS << ' ' << getValueString(Policy);
33 return;
34 }
35
36 assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
37 OS << ' ' << getOptionName(option) << getValueString(Policy);
38}
39
40// Return a string containing the loop hint argument including the
41// enclosing parentheses.
42std::string LoopHintAttr::getValueString(const PrintingPolicy &Policy) const {
43 std::string ValueName;
44 llvm::raw_string_ostream OS(ValueName);
45 OS << "(";
46 if (state == Numeric)
47 value->printPretty(OS, nullptr, Policy);
48 else if (state == FixedWidth || state == ScalableWidth) {
49 if (value) {
50 value->printPretty(OS, nullptr, Policy);
51 if (state == ScalableWidth)
52 OS << ", scalable";
53 } else if (state == ScalableWidth)
54 OS << "scalable";
55 else
56 OS << "fixed";
57 } else if (state == Enable)
58 OS << "enable";
59 else if (state == Full)
60 OS << "full";
61 else if (state == AssumeSafety)
62 OS << "assume_safety";
63 else
64 OS << "disable";
65 OS << ")";
66 return ValueName;
67}
68
69// Return a string suitable for identifying this attribute in diagnostics.
70std::string
71LoopHintAttr::getDiagnosticName(const PrintingPolicy &Policy) const {
72 unsigned SpellingIndex = getAttributeSpellingListIndex();
73 if (SpellingIndex == Pragma_nounroll)
74 return "#pragma nounroll";
75 else if (SpellingIndex == Pragma_unroll)
76 return "#pragma unroll" +
77 (option == UnrollCount ? getValueString(Policy) : "");
78 else if (SpellingIndex == Pragma_nounroll_and_jam)
79 return "#pragma nounroll_and_jam";
80 else if (SpellingIndex == Pragma_unroll_and_jam)
81 return "#pragma unroll_and_jam" +
82 (option == UnrollAndJamCount ? getValueString(Policy) : "");
83
84 assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
85 return getOptionName(option) + getValueString(Policy);
86}
87
88void OMPDeclareSimdDeclAttr::printPrettyPragma(
89 raw_ostream &OS, const PrintingPolicy &Policy) const {
90 if (getBranchState() != BS_Undefined)
91 OS << ' ' << ConvertBranchStateTyToStr(getBranchState());
92 if (auto *E = getSimdlen()) {
93 OS << " simdlen(";
94 E->printPretty(OS, nullptr, Policy);
95 OS << ")";
96 }
97 if (uniforms_size() > 0) {
98 OS << " uniform";
99 StringRef Sep = "(";
100 for (auto *E : uniforms()) {
101 OS << Sep;
102 E->printPretty(OS, nullptr, Policy);
103 Sep = ", ";
104 }
105 OS << ")";
106 }
107 alignments_iterator NI = alignments_begin();
108 for (auto *E : aligneds()) {
109 OS << " aligned(";
110 E->printPretty(OS, nullptr, Policy);
111 if (*NI) {
112 OS << ": ";
113 (*NI)->printPretty(OS, nullptr, Policy);
114 }
115 OS << ")";
116 ++NI;
117 }
118 steps_iterator I = steps_begin();
119 modifiers_iterator MI = modifiers_begin();
120 for (auto *E : linears()) {
121 OS << " linear(";
122 if (*MI != OMPC_LINEAR_unknown)
123 OS << getOpenMPSimpleClauseTypeName(llvm::omp::Clause::OMPC_linear, *MI)
124 << "(";
125 E->printPretty(OS, nullptr, Policy);
126 if (*MI != OMPC_LINEAR_unknown)
127 OS << ")";
128 if (*I) {
129 OS << ": ";
130 (*I)->printPretty(OS, nullptr, Policy);
131 }
132 OS << ")";
133 ++I;
134 ++MI;
135 }
136}
137
138void OMPDeclareTargetDeclAttr::printPrettyPragma(
139 raw_ostream &OS, const PrintingPolicy &Policy) const {
140 // Use fake syntax because it is for testing and debugging purpose only.
141 if (getDevType() != DT_Any)
142 OS << " device_type(" << ConvertDevTypeTyToStr(getDevType()) << ")";
143 if (getMapType() != MT_To && getMapType() != MT_Enter)
144 OS << ' ' << ConvertMapTypeTyToStr(getMapType());
145 if (Expr *E = getIndirectExpr()) {
146 OS << " indirect(";
147 E->printPretty(OS, nullptr, Policy);
148 OS << ")";
149 } else if (getIndirect()) {
150 OS << " indirect";
151 }
152}
153
154std::optional<OMPDeclareTargetDeclAttr *>
155OMPDeclareTargetDeclAttr::getActiveAttr(const ValueDecl *VD) {
156 if (llvm::all_of(VD->redecls(), [](const Decl *D) { return !D->hasAttrs(); }))
157 return std::nullopt;
158 unsigned Level = 0;
159 OMPDeclareTargetDeclAttr *FoundAttr = nullptr;
160 for (const Decl *D : VD->redecls()) {
161 for (auto *Attr : D->specific_attrs<OMPDeclareTargetDeclAttr>()) {
162 if (Level <= Attr->getLevel()) {
163 Level = Attr->getLevel();
164 FoundAttr = Attr;
165 }
166 }
167 }
168 if (FoundAttr)
169 return FoundAttr;
170 return std::nullopt;
171}
172
173std::optional<OMPDeclareTargetDeclAttr::MapTypeTy>
174OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(const ValueDecl *VD) {
175 std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
176 if (ActiveAttr)
177 return (*ActiveAttr)->getMapType();
178 return std::nullopt;
179}
180
181std::optional<OMPDeclareTargetDeclAttr::DevTypeTy>
182OMPDeclareTargetDeclAttr::getDeviceType(const ValueDecl *VD) {
183 std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
184 if (ActiveAttr)
185 return (*ActiveAttr)->getDevType();
186 return std::nullopt;
187}
188
189std::optional<SourceLocation>
190OMPDeclareTargetDeclAttr::getLocation(const ValueDecl *VD) {
191 std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
192 if (ActiveAttr)
193 return (*ActiveAttr)->getRange().getBegin();
194 return std::nullopt;
195}
196
197namespace clang {
198llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo &TI);
199llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo *TI);
200}
201
202void OMPDeclareVariantAttr::printPrettyPragma(
203 raw_ostream &OS, const PrintingPolicy &Policy) const {
204 if (const Expr *E = getVariantFuncRef()) {
205 OS << "(";
206 E->printPretty(OS, nullptr, Policy);
207 OS << ")";
208 }
209 OS << " match(" << traitInfos << ")";
210
211 auto PrintExprs = [&OS, &Policy](Expr **Begin, Expr **End) {
212 for (Expr **I = Begin; I != End; ++I) {
213 assert(*I && "Expected non-null Stmt");
214 if (I != Begin)
215 OS << ",";
216 (*I)->printPretty(OS, nullptr, Policy);
217 }
218 };
219 if (adjustArgsNothing_size()) {
220 OS << " adjust_args(nothing:";
221 PrintExprs(adjustArgsNothing_begin(), adjustArgsNothing_end());
222 OS << ")";
223 }
224 if (adjustArgsNeedDevicePtr_size()) {
225 OS << " adjust_args(need_device_ptr:";
226 PrintExprs(adjustArgsNeedDevicePtr_begin(), adjustArgsNeedDevicePtr_end());
227 OS << ")";
228 }
229 if (adjustArgsNeedDeviceAddr_size()) {
230 OS << " adjust_args(need_device_addr:";
231 PrintExprs(adjustArgsNeedDeviceAddr_begin(),
232 adjustArgsNeedDeviceAddr_end());
233 OS << ")";
234 }
235
236 auto PrintInteropInfo = [&OS](OMPInteropInfo *Begin, OMPInteropInfo *End) {
237 for (OMPInteropInfo *I = Begin; I != End; ++I) {
238 if (I != Begin)
239 OS << ", ";
240 OS << "interop(";
241 OS << getInteropTypeString(I);
242 OS << ")";
243 }
244 };
245 if (appendArgs_size()) {
246 OS << " append_args(";
247 PrintInteropInfo(appendArgs_begin(), appendArgs_end());
248 OS << ")";
249 }
250}
251
252unsigned AlignedAttr::getAlignment(ASTContext &Ctx) const {
253 assert(!isAlignmentDependent());
254 if (getCachedAlignmentValue())
255 return *getCachedAlignmentValue();
256
257 // Handle alignmentType case.
258 if (!isAlignmentExpr()) {
259 QualType T = getAlignmentType()->getType();
260
261 // C++ [expr.alignof]p3:
262 // When alignof is applied to a reference type, the result is the
263 // alignment of the referenced type.
264 T = T.getNonReferenceType();
265
266 if (T.getQualifiers().hasUnaligned())
267 return Ctx.getCharWidth();
268
269 return Ctx.getTypeAlignInChars(T.getTypePtr()).getQuantity() *
270 Ctx.getCharWidth();
271 }
272
273 // Handle alignmentExpr case.
274 if (alignmentExpr)
275 return alignmentExpr->EvaluateKnownConstInt(Ctx).getZExtValue() *
276 Ctx.getCharWidth();
277
279}
280
281StringLiteral *FormatMatchesAttr::getFormatString() const {
282 return cast<StringLiteral>(getExpectedFormat());
283}
284
285namespace {
286// Arguments whose types fail this test never compare equal unless there's a
287// specialization of equalAttrArgs for the type. Specilization for the following
288// arguments haven't been implemented yet:
289// - DeclArgument
290// - OMPTraitInfoArgument
291// - VariadicOMPInteropInfoArgument
292#define USE_DEFAULT_EQUALITY \
293 (std::is_same_v<T, StringRef> || std::is_same_v<T, VersionTuple> || \
294 std::is_same_v<T, IdentifierInfo *> || std::is_same_v<T, ParamIdx> || \
295 std::is_same_v<T, Attr *> || std::is_same_v<T, char *> || \
296 std::is_enum_v<T> || std::is_integral_v<T>)
297
298template <class T>
299typename std::enable_if_t<!USE_DEFAULT_EQUALITY, bool>
300equalAttrArgs(T A, T B, StructuralEquivalenceContext &Context) {
301 return false;
302}
303
304template <class T>
305typename std::enable_if_t<USE_DEFAULT_EQUALITY, bool>
306equalAttrArgs(T A1, T A2, StructuralEquivalenceContext &Context) {
307 return A1 == A2;
308}
309
310template <class T>
311bool equalAttrArgs(T *A1_B, T *A1_E, T *A2_B, T *A2_E,
313 if (A1_E - A1_B != A2_E - A2_B)
314 return false;
315
316 for (; A1_B != A1_E; ++A1_B, ++A2_B)
317 if (!equalAttrArgs(*A1_B, *A2_B, Context))
318 return false;
319
320 return true;
321}
322
323template <>
324bool equalAttrArgs<Attr *>(Attr *A1, Attr *A2,
326 return A1->isEquivalent(*A2, Context);
327}
328
329template <>
330bool equalAttrArgs<Expr *>(Expr *A1, Expr *A2,
332 return ASTStructuralEquivalence::isEquivalent(Context, A1, A2);
333}
334
335template <>
336bool equalAttrArgs<QualType>(QualType T1, QualType T2,
338 return ASTStructuralEquivalence::isEquivalent(Context, T1, T2);
339}
340
341template <>
342bool equalAttrArgs<const IdentifierInfo *>(
343 const IdentifierInfo *Name1, const IdentifierInfo *Name2,
345 return ASTStructuralEquivalence::isEquivalent(Name1, Name2);
346}
347
348bool areAlignedAttrsEqual(const AlignedAttr &A1, const AlignedAttr &A2,
350 if (A1.getSpelling() != A2.getSpelling())
351 return false;
352
353 if (A1.isAlignmentExpr() != A2.isAlignmentExpr())
354 return false;
355
356 if (A1.isAlignmentExpr())
357 return equalAttrArgs(A1.getAlignmentExpr(), A2.getAlignmentExpr(), Context);
358
359 return equalAttrArgs(A1.getAlignmentType()->getType(),
360 A2.getAlignmentType()->getType(), Context);
361}
362} // namespace
363
364#include "clang/AST/AttrImpl.inc"
Defines the clang::ASTContext interface.
C Language Family Type Representation.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
CharUnits getTypeAlignInChars(QualType T) const
Return the ABI-specified alignment of a (complete) type T, in characters.
unsigned getTargetDefaultAlignForAttributeAligned() const
Return the default alignment for attribute((aligned)) on this target, to be used if no alignment valu...
uint64_t getCharWidth() const
Return the size of the character type, in bits.
Attr - This represents one attribute.
Definition Attr.h:46
bool isEquivalent(const Attr &Other, StructuralEquivalenceContext &Context) const
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
Definition DeclBase.h:559
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
Definition DeclBase.h:1049
This represents one expression.
Definition Expr.h:112
One of these records is kept for each identifier that is lexed.
A (possibly-)qualified type.
Definition TypeBase.h:937
StringLiteral - This represents a string literal expression, e.g.
Definition Expr.h:1799
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
bool isEquivalent(StructuralEquivalenceContext &Context, QualType T1, QualType T2)
Determine structural equivalence of two types.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
const char * getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, unsigned Type)
const FunctionProtoType * T
@ OMPC_LINEAR_unknown
Definition OpenMPKinds.h:67
const StreamingDiagnostic & operator<<(const StreamingDiagnostic &DB, const ConceptReference *C)
Insertion operator for diagnostics.
U cast(CodeGen::Address addr)
Definition Address.h:327
Describes how types, statements, expressions, and declarations should be printed.