clang 24.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, &Policy](OMPInteropInfo *Begin,
237 OMPInteropInfo *End) {
238 for (OMPInteropInfo *I = Begin; I != End; ++I) {
239 if (I != Begin)
240 OS << ", ";
241 OS << "interop(";
242 if (!I->Prefs.empty()) {
243 OS << "prefer_type(";
244 if (I->HasPreferAttrs) {
245 StringRef Sep = "";
246 for (const auto &P : I->Prefs) {
247 OS << Sep << "{";
248 if (P.Fr) {
249 OS << "fr(";
250 P.Fr->printPretty(OS, nullptr, Policy);
251 OS << ")";
252 }
253 bool NeedSep = P.Fr != nullptr;
254 for (Expr *A : P.Attrs) {
255 if (NeedSep)
256 OS << ",";
257 OS << "attr(";
258 A->printPretty(OS, nullptr, Policy);
259 OS << ")";
260 NeedSep = true;
261 }
262 OS << "}";
263 Sep = ",";
264 }
265 } else {
266 StringRef Sep = "";
267 for (const auto &P : I->Prefs) {
268 OS << Sep;
269 if (P.Fr)
270 P.Fr->printPretty(OS, nullptr, Policy);
271 Sep = ",";
272 }
273 }
274 OS << "),";
275 }
276 OS << getInteropTypeString(I);
277 OS << ")";
278 }
279 };
280 if (appendArgs_size()) {
281 OS << " append_args(";
282 PrintInteropInfo(appendArgs_begin(), appendArgs_end());
283 OS << ")";
284 }
285}
286
287unsigned AlignedAttr::getAlignment(ASTContext &Ctx) const {
288 assert(!isAlignmentDependent());
289 if (getCachedAlignmentValue())
290 return *getCachedAlignmentValue();
291
292 // Handle alignmentType case.
293 if (!isAlignmentExpr()) {
294 QualType T = getAlignmentType()->getType();
295
296 // C++ [expr.alignof]p3:
297 // When alignof is applied to a reference type, the result is the
298 // alignment of the referenced type.
299 T = T.getNonReferenceType();
300
301 if (T.getQualifiers().hasUnaligned())
302 return Ctx.getCharWidth();
303
304 return Ctx.getTypeAlignInChars(T.getTypePtr()).getQuantity() *
305 Ctx.getCharWidth();
306 }
307
308 // Handle alignmentExpr case.
309 if (alignmentExpr)
310 return alignmentExpr->EvaluateKnownConstInt(Ctx).getZExtValue() *
311 Ctx.getCharWidth();
312
314}
315
316StringLiteral *FormatMatchesAttr::getFormatString() const {
317 return cast<StringLiteral>(getExpectedFormat());
318}
319
320namespace {
321// Arguments whose types fail this test never compare equal unless there's a
322// specialization of equalAttrArgs for the type. Specilization for the following
323// arguments haven't been implemented yet:
324// - DeclArgument
325// - OMPTraitInfoArgument
326// - VariadicOMPInteropInfoArgument
327#define USE_DEFAULT_EQUALITY \
328 (std::is_same_v<T, StringRef> || std::is_same_v<T, VersionTuple> || \
329 std::is_same_v<T, IdentifierInfo *> || std::is_same_v<T, char *> || \
330 std::is_enum_v<T> || std::is_integral_v<T>)
331
332template <class T>
333typename std::enable_if_t<!USE_DEFAULT_EQUALITY, bool>
334equalAttrArgs(T A, T B, StructuralEquivalenceContext &Context) {
335 return false;
336}
337
338template <class T>
339typename std::enable_if_t<USE_DEFAULT_EQUALITY, bool>
340equalAttrArgs(T A1, T A2, StructuralEquivalenceContext &Context) {
341 return A1 == A2;
342}
343
344template <>
345bool equalAttrArgs<ParamIdx>(ParamIdx P1, ParamIdx P2,
347 // ParamIdx can be invalid when representing an optional parameter that was
348 // not specified (e.g. the second argument of alloc_size(N)).
349 // ParamIdx::operator== asserts both sides are valid, so guard against the
350 // invalid case before delegating to it.
351 if (P1.isValid() != P2.isValid())
352 return false;
353 if (!P1.isValid())
354 return true;
355 return P1 == P2;
356}
357
358template <class T>
359bool equalAttrArgs(T *A1_B, T *A1_E, T *A2_B, T *A2_E,
361 if (A1_E - A1_B != A2_E - A2_B)
362 return false;
363
364 for (; A1_B != A1_E; ++A1_B, ++A2_B)
365 if (!equalAttrArgs(*A1_B, *A2_B, Context))
366 return false;
367
368 return true;
369}
370
371template <>
372bool equalAttrArgs<Attr *>(Attr *A1, Attr *A2,
374 if (!A1 || !A2)
375 return A1 == A2;
376 return A1->isEquivalent(*A2, Context);
377}
378
379template <>
380bool equalAttrArgs<Expr *>(Expr *A1, Expr *A2,
382 return ASTStructuralEquivalence::isEquivalent(Context, A1, A2);
383}
384
385template <>
386bool equalAttrArgs<QualType>(QualType T1, QualType T2,
388 return ASTStructuralEquivalence::isEquivalent(Context, T1, T2);
389}
390
391template <>
392bool equalAttrArgs<const IdentifierInfo *>(
393 const IdentifierInfo *Name1, const IdentifierInfo *Name2,
395 return ASTStructuralEquivalence::isEquivalent(Name1, Name2);
396}
397
398bool areAlignedAttrsEqual(const AlignedAttr &A1, const AlignedAttr &A2,
400 if (A1.getSpelling() != A2.getSpelling())
401 return false;
402
403 if (A1.isAlignmentExpr() != A2.isAlignmentExpr())
404 return false;
405
406 if (A1.isAlignmentExpr())
407 return equalAttrArgs(A1.getAlignmentExpr(), A2.getAlignmentExpr(), Context);
408
409 return equalAttrArgs(A1.getAlignmentType()->getType(),
410 A2.getAlignmentType()->getType(), Context);
411}
412} // namespace
413
414namespace {
415// Machinery to unique attributes based on the arguments.
416// The construction mirrors the equivalent testing code above.
417// The content of the arguments are added to the FoldingSetNodeID instance,
418// which allows the AttributedTypes to unique the attributes based on
419// the value of the arguments.
420
421#define USE_DEFAULT_PROFILE \
422 (std::is_same_v<T, StringRef> || std::is_same_v<T, VersionTuple> || \
423 std::is_same_v<T, IdentifierInfo *> || \
424 std::is_same_v<T, const IdentifierInfo *> || std::is_enum_v<T> || \
425 std::is_integral_v<T>)
426
427template <class T>
428typename std::enable_if_t<!USE_DEFAULT_PROFILE>
429profileAttrArg(llvm::FoldingSetNodeID &, const ASTContext &, T) {
430 llvm_unreachable("profile not implemented for this type");
431}
432
433template <class T>
434typename std::enable_if_t<USE_DEFAULT_PROFILE>
435profileAttrArg(llvm::FoldingSetNodeID &ID, const ASTContext &, T V) {
436 if constexpr (std::is_same_v<T, StringRef>)
437 ID.AddString(V);
438 else if constexpr (std::is_same_v<T, VersionTuple>) {
439 ID.AddInteger(V.getMajor());
440 ID.AddInteger(V.getMinor().value_or(0));
441 ID.AddInteger(V.getSubminor().value_or(0));
442 ID.AddInteger(V.getBuild().value_or(0));
443 } else if constexpr (std::is_same_v<T, IdentifierInfo *> ||
444 std::is_same_v<T, const IdentifierInfo *>)
445 ID.AddPointer(V);
446 else
447 ID.AddInteger(static_cast<long long>(V));
448}
449
450template <>
451inline void profileAttrArg<ParamIdx>(llvm::FoldingSetNodeID &ID,
452 const ASTContext &, ParamIdx P) {
453 ID.AddBoolean(P.isValid());
454 if (P.isValid())
455 ID.AddInteger(P.getASTIndex());
456}
457
458template <class T>
459inline void profileAttrArg(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx,
460 T *Begin, T *End) {
461 ID.AddInteger(End - Begin);
462 for (; Begin != End; ++Begin)
463 profileAttrArg(ID, Ctx, *Begin);
464}
465
466template <>
467inline void profileAttrArg<Attr *>(llvm::FoldingSetNodeID &ID,
468 const ASTContext &Ctx, Attr *A) {
469 if (!A) {
470 ID.AddPointer(nullptr);
471 return;
472 }
473 ID.AddInteger(A->getKind());
474 A->Profile(ID, Ctx);
475}
476
477template <>
478inline void profileAttrArg<Expr *>(llvm::FoldingSetNodeID &ID,
479 const ASTContext &Ctx, Expr *E) {
480 E->Profile(ID, Ctx, /*Canonical=*/true);
481}
482
483template <>
484inline void profileAttrArg<QualType>(llvm::FoldingSetNodeID &ID,
485 const ASTContext &, QualType T) {
486 ID.AddPointer(T.getCanonicalType().getAsOpaquePtr());
487}
488
489void profileAlignedAttr(const AlignedAttr &A, llvm::FoldingSetNodeID &ID,
490 const ASTContext &Ctx) {
491 ID.AddInteger(A.getSpellingListIndex());
492 ID.AddBoolean(A.isAlignmentExpr());
493 if (A.isAlignmentExpr())
494 profileAttrArg(ID, Ctx, A.getAlignmentExpr());
495 else
496 profileAttrArg(ID, Ctx, A.getAlignmentType()->getType());
497}
498} // namespace
499
500#include "clang/AST/AttrImpl.inc"
Defines the clang::ASTContext interface.
#define V(N, I)
static StringRef getOptionName(StringRef Option, const char Delimiter='=')
Definition Clang.cpp:2265
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:223
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
attr::Kind getKind() const
Definition Attr.h:92
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) 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:567
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
Definition DeclBase.h:1066
This represents one expression.
Definition Expr.h:112
One of these records is kept for each identifier that is lexed.
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
Definition Attr.h:279
bool isValid() const
Is this parameter index valid?
Definition Attr.h:343
unsigned getASTIndex() const
Get the parameter index as it would normally be encoded at the AST level of representation: zero-orig...
Definition Attr.h:362
A (possibly-)qualified type.
Definition TypeBase.h:938
void printPretty(raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation=0, StringRef NewlineSymbol="\n", const ASTContext *Context=nullptr) const
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, bool Canonical, bool ProfileLambdaExpr=false) const
Produce a unique representation of the given statement.
StringLiteral - This represents a string literal expression, e.g.
Definition Expr.h:1805
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,...
Top level wrappers for InstallAPI frontend operations.
const char * getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, unsigned Type)
const FunctionProtoType * T
@ OMPC_LINEAR_unknown
Definition OpenMPKinds.h:67
@ Full
Match, but we didn't check for full match.
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.