1 //===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements stmt-related attribute processing.
11 //===----------------------------------------------------------------------===//
13 #include "clang/AST/ASTContext.h"
14 #include "clang/AST/EvaluatedExprVisitor.h"
15 #include "clang/Basic/TargetInfo.h"
16 #include "clang/Sema/DelayedDiagnostic.h"
17 #include "clang/Sema/ParsedAttr.h"
18 #include "clang/Sema/ScopeInfo.h"
21 using namespace clang
;
24 static Attr
*handleFallThroughAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
26 FallThroughAttr
Attr(S
.Context
, A
);
27 if (isa
<SwitchCase
>(St
)) {
28 S
.Diag(A
.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target
)
29 << A
<< St
->getBeginLoc();
30 SourceLocation L
= S
.getLocForEndOfToken(Range
.getEnd());
31 S
.Diag(L
, diag::note_fallthrough_insert_semi_fixit
)
32 << FixItHint::CreateInsertion(L
, ";");
35 auto *FnScope
= S
.getCurFunction();
36 if (FnScope
->SwitchStack
.empty()) {
37 S
.Diag(A
.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch
);
41 // If this is spelled as the standard C++17 attribute, but not in C++17, warn
42 // about using it as an extension.
43 if (!S
.getLangOpts().CPlusPlus17
&& A
.isCXX11Attribute() &&
45 S
.Diag(A
.getLoc(), diag::ext_cxx17_attr
) << A
;
47 FnScope
->setHasFallthroughStmt();
48 return ::new (S
.Context
) FallThroughAttr(S
.Context
, A
);
51 static Attr
*handleSuppressAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
53 if (A
.getAttributeSpellingListIndex() == SuppressAttr::CXX11_gsl_suppress
&&
55 // Suppression attribute with GSL spelling requires at least 1 argument.
56 S
.Diag(A
.getLoc(), diag::err_attribute_too_few_arguments
) << A
<< 1;
60 std::vector
<StringRef
> DiagnosticIdentifiers
;
61 for (unsigned I
= 0, E
= A
.getNumArgs(); I
!= E
; ++I
) {
64 if (!S
.checkStringLiteralArgumentAttr(A
, I
, RuleName
, nullptr))
67 DiagnosticIdentifiers
.push_back(RuleName
);
70 return ::new (S
.Context
) SuppressAttr(
71 S
.Context
, A
, DiagnosticIdentifiers
.data(), DiagnosticIdentifiers
.size());
74 static Attr
*handleLoopHintAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
76 IdentifierLoc
*PragmaNameLoc
= A
.getArgAsIdent(0);
77 IdentifierLoc
*OptionLoc
= A
.getArgAsIdent(1);
78 IdentifierLoc
*StateLoc
= A
.getArgAsIdent(2);
79 Expr
*ValueExpr
= A
.getArgAsExpr(3);
81 StringRef PragmaName
=
82 llvm::StringSwitch
<StringRef
>(PragmaNameLoc
->Ident
->getName())
83 .Cases("unroll", "nounroll", "unroll_and_jam", "nounroll_and_jam",
84 PragmaNameLoc
->Ident
->getName())
85 .Default("clang loop");
87 // This could be handled automatically by adding a Subjects definition in
88 // Attr.td, but that would make the diagnostic behavior worse in this case
89 // because the user spells this attribute as a pragma.
90 if (!isa
<DoStmt
, ForStmt
, CXXForRangeStmt
, WhileStmt
>(St
)) {
91 std::string Pragma
= "#pragma " + std::string(PragmaName
);
92 S
.Diag(St
->getBeginLoc(), diag::err_pragma_loop_precedes_nonloop
) << Pragma
;
96 LoopHintAttr::OptionType Option
;
97 LoopHintAttr::LoopHintState State
;
99 auto SetHints
= [&Option
, &State
](LoopHintAttr::OptionType O
,
100 LoopHintAttr::LoopHintState S
) {
105 if (PragmaName
== "nounroll") {
106 SetHints(LoopHintAttr::Unroll
, LoopHintAttr::Disable
);
107 } else if (PragmaName
== "unroll") {
110 if (!ValueExpr
->isValueDependent()) {
111 auto Value
= ValueExpr
->EvaluateKnownConstInt(S
.getASTContext());
112 if (Value
.isZero() || Value
.isOne())
113 SetHints(LoopHintAttr::Unroll
, LoopHintAttr::Disable
);
115 SetHints(LoopHintAttr::UnrollCount
, LoopHintAttr::Numeric
);
117 SetHints(LoopHintAttr::UnrollCount
, LoopHintAttr::Numeric
);
119 SetHints(LoopHintAttr::Unroll
, LoopHintAttr::Enable
);
120 } else if (PragmaName
== "nounroll_and_jam") {
121 SetHints(LoopHintAttr::UnrollAndJam
, LoopHintAttr::Disable
);
122 } else if (PragmaName
== "unroll_and_jam") {
123 // #pragma unroll_and_jam N
125 SetHints(LoopHintAttr::UnrollAndJamCount
, LoopHintAttr::Numeric
);
127 SetHints(LoopHintAttr::UnrollAndJam
, LoopHintAttr::Enable
);
129 // #pragma clang loop ...
130 assert(OptionLoc
&& OptionLoc
->Ident
&&
131 "Attribute must have valid option info.");
132 Option
= llvm::StringSwitch
<LoopHintAttr::OptionType
>(
133 OptionLoc
->Ident
->getName())
134 .Case("vectorize", LoopHintAttr::Vectorize
)
135 .Case("vectorize_width", LoopHintAttr::VectorizeWidth
)
136 .Case("interleave", LoopHintAttr::Interleave
)
137 .Case("vectorize_predicate", LoopHintAttr::VectorizePredicate
)
138 .Case("interleave_count", LoopHintAttr::InterleaveCount
)
139 .Case("unroll", LoopHintAttr::Unroll
)
140 .Case("unroll_count", LoopHintAttr::UnrollCount
)
141 .Case("pipeline", LoopHintAttr::PipelineDisabled
)
142 .Case("pipeline_initiation_interval",
143 LoopHintAttr::PipelineInitiationInterval
)
144 .Case("distribute", LoopHintAttr::Distribute
)
145 .Default(LoopHintAttr::Vectorize
);
146 if (Option
== LoopHintAttr::VectorizeWidth
) {
147 assert((ValueExpr
|| (StateLoc
&& StateLoc
->Ident
)) &&
148 "Attribute must have a valid value expression or argument.");
149 if (ValueExpr
&& S
.CheckLoopHintExpr(ValueExpr
, St
->getBeginLoc(),
150 /*AllowZero=*/false))
152 if (StateLoc
&& StateLoc
->Ident
&& StateLoc
->Ident
->isStr("scalable"))
153 State
= LoopHintAttr::ScalableWidth
;
155 State
= LoopHintAttr::FixedWidth
;
156 } else if (Option
== LoopHintAttr::InterleaveCount
||
157 Option
== LoopHintAttr::UnrollCount
||
158 Option
== LoopHintAttr::PipelineInitiationInterval
) {
159 assert(ValueExpr
&& "Attribute must have a valid value expression.");
160 if (S
.CheckLoopHintExpr(ValueExpr
, St
->getBeginLoc(),
161 /*AllowZero=*/false))
163 State
= LoopHintAttr::Numeric
;
164 } else if (Option
== LoopHintAttr::Vectorize
||
165 Option
== LoopHintAttr::Interleave
||
166 Option
== LoopHintAttr::VectorizePredicate
||
167 Option
== LoopHintAttr::Unroll
||
168 Option
== LoopHintAttr::Distribute
||
169 Option
== LoopHintAttr::PipelineDisabled
) {
170 assert(StateLoc
&& StateLoc
->Ident
&& "Loop hint must have an argument");
171 if (StateLoc
->Ident
->isStr("disable"))
172 State
= LoopHintAttr::Disable
;
173 else if (StateLoc
->Ident
->isStr("assume_safety"))
174 State
= LoopHintAttr::AssumeSafety
;
175 else if (StateLoc
->Ident
->isStr("full"))
176 State
= LoopHintAttr::Full
;
177 else if (StateLoc
->Ident
->isStr("enable"))
178 State
= LoopHintAttr::Enable
;
180 llvm_unreachable("bad loop hint argument");
182 llvm_unreachable("bad loop hint");
185 return LoopHintAttr::CreateImplicit(S
.Context
, Option
, State
, ValueExpr
, A
);
189 class CallExprFinder
: public ConstEvaluatedExprVisitor
<CallExprFinder
> {
190 bool FoundAsmStmt
= false;
191 std::vector
<const CallExpr
*> CallExprs
;
194 typedef ConstEvaluatedExprVisitor
<CallExprFinder
> Inherited
;
196 CallExprFinder(Sema
&S
, const Stmt
*St
) : Inherited(S
.Context
) { Visit(St
); }
198 bool foundCallExpr() { return !CallExprs
.empty(); }
199 const std::vector
<const CallExpr
*> &getCallExprs() { return CallExprs
; }
201 bool foundAsmStmt() { return FoundAsmStmt
; }
203 void VisitCallExpr(const CallExpr
*E
) { CallExprs
.push_back(E
); }
205 void VisitAsmStmt(const AsmStmt
*S
) { FoundAsmStmt
= true; }
207 void Visit(const Stmt
*St
) {
210 ConstEvaluatedExprVisitor
<CallExprFinder
>::Visit(St
);
215 static Attr
*handleNoMergeAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
217 CallExprFinder
CEF(S
, St
);
219 if (!CEF
.foundCallExpr() && !CEF
.foundAsmStmt()) {
220 S
.Diag(St
->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt
)
225 return ::new (S
.Context
) NoMergeAttr(S
.Context
, A
);
228 static Attr
*handleNoConvergentAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
230 CallExprFinder
CEF(S
, St
);
232 if (!CEF
.foundCallExpr() && !CEF
.foundAsmStmt()) {
233 S
.Diag(St
->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt
)
238 return ::new (S
.Context
) NoConvergentAttr(S
.Context
, A
);
241 template <typename OtherAttr
, int DiagIdx
>
242 static bool CheckStmtInlineAttr(Sema
&SemaRef
, const Stmt
*OrigSt
,
244 const AttributeCommonInfo
&A
) {
245 CallExprFinder
OrigCEF(SemaRef
, OrigSt
);
246 CallExprFinder
CEF(SemaRef
, CurSt
);
248 // If the call expressions lists are equal in size, we can skip
249 // previously emitted diagnostics. However, if the statement has a pack
250 // expansion, we have no way of telling which CallExpr is the instantiated
251 // version of the other. In this case, we will end up re-diagnosing in the
253 // ie: [[clang::always_inline]] non_dependent(), (other_call<Pack>()...)
254 // will diagnose nondependent again.
255 bool CanSuppressDiag
=
256 OrigSt
&& CEF
.getCallExprs().size() == OrigCEF
.getCallExprs().size();
258 if (!CEF
.foundCallExpr()) {
259 return SemaRef
.Diag(CurSt
->getBeginLoc(),
260 diag::warn_attribute_ignored_no_calls_in_stmt
)
264 for (const auto &Tup
:
265 llvm::zip_longest(OrigCEF
.getCallExprs(), CEF
.getCallExprs())) {
266 // If the original call expression already had a callee, we already
267 // diagnosed this, so skip it here. We can't skip if there isn't a 1:1
268 // relationship between the two lists of call expressions.
269 if (!CanSuppressDiag
|| !(*std::get
<0>(Tup
))->getCalleeDecl()) {
270 const Decl
*Callee
= (*std::get
<1>(Tup
))->getCalleeDecl();
272 (Callee
->hasAttr
<OtherAttr
>() || Callee
->hasAttr
<FlattenAttr
>())) {
273 SemaRef
.Diag(CurSt
->getBeginLoc(),
274 diag::warn_function_stmt_attribute_precedence
)
275 << A
<< (Callee
->hasAttr
<OtherAttr
>() ? DiagIdx
: 1);
276 SemaRef
.Diag(Callee
->getBeginLoc(), diag::note_conflicting_attribute
);
284 bool Sema::CheckNoInlineAttr(const Stmt
*OrigSt
, const Stmt
*CurSt
,
285 const AttributeCommonInfo
&A
) {
286 return CheckStmtInlineAttr
<AlwaysInlineAttr
, 0>(*this, OrigSt
, CurSt
, A
);
289 bool Sema::CheckAlwaysInlineAttr(const Stmt
*OrigSt
, const Stmt
*CurSt
,
290 const AttributeCommonInfo
&A
) {
291 return CheckStmtInlineAttr
<NoInlineAttr
, 2>(*this, OrigSt
, CurSt
, A
);
294 static Attr
*handleNoInlineAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
296 NoInlineAttr
NIA(S
.Context
, A
);
297 if (!NIA
.isStmtNoInline()) {
298 S
.Diag(St
->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt
)
299 << "[[clang::noinline]]";
303 if (S
.CheckNoInlineAttr(/*OrigSt=*/nullptr, St
, A
))
306 return ::new (S
.Context
) NoInlineAttr(S
.Context
, A
);
309 static Attr
*handleAlwaysInlineAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
311 AlwaysInlineAttr
AIA(S
.Context
, A
);
312 if (!AIA
.isClangAlwaysInline()) {
313 S
.Diag(St
->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt
)
314 << "[[clang::always_inline]]";
318 if (S
.CheckAlwaysInlineAttr(/*OrigSt=*/nullptr, St
, A
))
321 return ::new (S
.Context
) AlwaysInlineAttr(S
.Context
, A
);
324 static Attr
*handleCXXAssumeAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
326 ExprResult Res
= S
.ActOnCXXAssumeAttr(St
, A
, Range
);
330 return ::new (S
.Context
) CXXAssumeAttr(S
.Context
, A
, Res
.get());
333 static Attr
*handleMustTailAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
335 // Validation is in Sema::ActOnAttributedStmt().
336 return ::new (S
.Context
) MustTailAttr(S
.Context
, A
);
339 static Attr
*handleLikely(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
342 if (!S
.getLangOpts().CPlusPlus20
&& A
.isCXX11Attribute() && !A
.getScopeName())
343 S
.Diag(A
.getLoc(), diag::ext_cxx20_attr
) << A
<< Range
;
345 return ::new (S
.Context
) LikelyAttr(S
.Context
, A
);
348 static Attr
*handleUnlikely(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
351 if (!S
.getLangOpts().CPlusPlus20
&& A
.isCXX11Attribute() && !A
.getScopeName())
352 S
.Diag(A
.getLoc(), diag::ext_cxx20_attr
) << A
<< Range
;
354 return ::new (S
.Context
) UnlikelyAttr(S
.Context
, A
);
357 CodeAlignAttr
*Sema::BuildCodeAlignAttr(const AttributeCommonInfo
&CI
,
359 if (!E
->isValueDependent()) {
361 ExprResult Res
= VerifyIntegerConstantExpression(E
, &ArgVal
);
366 // This attribute requires an integer argument which is a constant power of
367 // two between 1 and 4096 inclusive.
368 if (ArgVal
< CodeAlignAttr::MinimumAlignment
||
369 ArgVal
> CodeAlignAttr::MaximumAlignment
|| !ArgVal
.isPowerOf2()) {
370 if (std::optional
<int64_t> Value
= ArgVal
.trySExtValue())
371 Diag(CI
.getLoc(), diag::err_attribute_power_of_two_in_range
)
372 << CI
<< CodeAlignAttr::MinimumAlignment
373 << CodeAlignAttr::MaximumAlignment
<< Value
.value();
375 Diag(CI
.getLoc(), diag::err_attribute_power_of_two_in_range
)
376 << CI
<< CodeAlignAttr::MinimumAlignment
377 << CodeAlignAttr::MaximumAlignment
<< E
;
381 return new (Context
) CodeAlignAttr(Context
, CI
, E
);
384 static Attr
*handleCodeAlignAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
) {
386 Expr
*E
= A
.getArgAsExpr(0);
387 return S
.BuildCodeAlignAttr(A
, E
);
390 // Diagnose non-identical duplicates as a 'conflicting' loop attributes
391 // and suppress duplicate errors in cases where the two match.
392 template <typename LoopAttrT
>
393 static void CheckForDuplicateLoopAttrs(Sema
&S
, ArrayRef
<const Attr
*> Attrs
) {
394 auto FindFunc
= [](const Attr
*A
) { return isa
<const LoopAttrT
>(A
); };
395 const auto *FirstItr
= std::find_if(Attrs
.begin(), Attrs
.end(), FindFunc
);
397 if (FirstItr
== Attrs
.end()) // no attributes found
400 const auto *LastFoundItr
= FirstItr
;
401 std::optional
<llvm::APSInt
> FirstValue
;
404 dyn_cast
<ConstantExpr
>(cast
<LoopAttrT
>(*FirstItr
)->getAlignment());
405 // Return early if first alignment expression is dependent (since we don't
406 // know what the effective size will be), and skip the loop entirely.
410 while (Attrs
.end() != (LastFoundItr
= std::find_if(LastFoundItr
+ 1,
411 Attrs
.end(), FindFunc
))) {
413 dyn_cast
<ConstantExpr
>(cast
<LoopAttrT
>(*LastFoundItr
)->getAlignment());
414 // If the value is dependent, we can not test anything.
417 // Test the attribute values.
418 llvm::APSInt SecondValue
= CASA
->getResultAsAPSInt();
420 FirstValue
= CAFA
->getResultAsAPSInt();
422 if (FirstValue
!= SecondValue
) {
423 S
.Diag((*LastFoundItr
)->getLocation(), diag::err_loop_attr_conflict
)
425 S
.Diag((*FirstItr
)->getLocation(), diag::note_previous_attribute
);
431 static Attr
*handleMSConstexprAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
433 if (!S
.getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2022_3
)) {
434 S
.Diag(A
.getLoc(), diag::warn_unknown_attribute_ignored
)
435 << A
<< A
.getRange();
438 return ::new (S
.Context
) MSConstexprAttr(S
.Context
, A
);
441 #define WANT_STMT_MERGE_LOGIC
442 #include "clang/Sema/AttrParsedAttrImpl.inc"
443 #undef WANT_STMT_MERGE_LOGIC
446 CheckForIncompatibleAttributes(Sema
&S
,
447 const SmallVectorImpl
<const Attr
*> &Attrs
) {
448 // The vast majority of attributed statements will only have one attribute
449 // on them, so skip all of the checking in the common case.
450 if (Attrs
.size() < 2)
453 // First, check for the easy cases that are table-generated for us.
454 if (!DiagnoseMutualExclusions(S
, Attrs
))
458 // For the following categories, they come in two variants: a state form and
459 // a numeric form. The state form may be one of default, enable, and
460 // disable. The numeric form provides an integer hint (for example, unroll
461 // count) to the transformer.
466 // For unroll, default indicates full unrolling rather than enabling the
469 // The loop distribution transformation only has a state form that is
470 // exposed by #pragma clang loop distribute (enable | disable).
472 // The vector predication only has a state form that is exposed by
473 // #pragma clang loop vectorize_predicate (enable | disable).
475 // This serves as a indicator to how many category are listed in this enum.
478 // The following array accumulates the hints encountered while iterating
479 // through the attributes to check for compatibility.
481 const LoopHintAttr
*StateAttr
;
482 const LoopHintAttr
*NumericAttr
;
483 } HintAttrs
[CategoryType::NumberOfCategories
] = {};
485 for (const auto *I
: Attrs
) {
486 const LoopHintAttr
*LH
= dyn_cast
<LoopHintAttr
>(I
);
488 // Skip non loop hint attributes
492 CategoryType Category
= CategoryType::NumberOfCategories
;
493 LoopHintAttr::OptionType Option
= LH
->getOption();
495 case LoopHintAttr::Vectorize
:
496 case LoopHintAttr::VectorizeWidth
:
497 Category
= Vectorize
;
499 case LoopHintAttr::Interleave
:
500 case LoopHintAttr::InterleaveCount
:
501 Category
= Interleave
;
503 case LoopHintAttr::Unroll
:
504 case LoopHintAttr::UnrollCount
:
507 case LoopHintAttr::UnrollAndJam
:
508 case LoopHintAttr::UnrollAndJamCount
:
509 Category
= UnrollAndJam
;
511 case LoopHintAttr::Distribute
:
512 // Perform the check for duplicated 'distribute' hints.
513 Category
= Distribute
;
515 case LoopHintAttr::PipelineDisabled
:
516 case LoopHintAttr::PipelineInitiationInterval
:
519 case LoopHintAttr::VectorizePredicate
:
520 Category
= VectorizePredicate
;
524 assert(Category
!= NumberOfCategories
&& "Unhandled loop hint option");
525 auto &CategoryState
= HintAttrs
[Category
];
526 const LoopHintAttr
*PrevAttr
;
527 if (Option
== LoopHintAttr::Vectorize
||
528 Option
== LoopHintAttr::Interleave
|| Option
== LoopHintAttr::Unroll
||
529 Option
== LoopHintAttr::UnrollAndJam
||
530 Option
== LoopHintAttr::VectorizePredicate
||
531 Option
== LoopHintAttr::PipelineDisabled
||
532 Option
== LoopHintAttr::Distribute
) {
533 // Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
534 PrevAttr
= CategoryState
.StateAttr
;
535 CategoryState
.StateAttr
= LH
;
537 // Numeric hint. For example, vectorize_width(8).
538 PrevAttr
= CategoryState
.NumericAttr
;
539 CategoryState
.NumericAttr
= LH
;
542 PrintingPolicy
Policy(S
.Context
.getLangOpts());
543 SourceLocation OptionLoc
= LH
->getRange().getBegin();
545 // Cannot specify same type of attribute twice.
546 S
.Diag(OptionLoc
, diag::err_pragma_loop_compatibility
)
547 << /*Duplicate=*/true << PrevAttr
->getDiagnosticName(Policy
)
548 << LH
->getDiagnosticName(Policy
);
550 if (CategoryState
.StateAttr
&& CategoryState
.NumericAttr
&&
551 (Category
== Unroll
|| Category
== UnrollAndJam
||
552 CategoryState
.StateAttr
->getState() == LoopHintAttr::Disable
)) {
553 // Disable hints are not compatible with numeric hints of the same
554 // category. As a special case, numeric unroll hints are also not
555 // compatible with enable or full form of the unroll pragma because these
556 // directives indicate full unrolling.
557 S
.Diag(OptionLoc
, diag::err_pragma_loop_compatibility
)
558 << /*Duplicate=*/false
559 << CategoryState
.StateAttr
->getDiagnosticName(Policy
)
560 << CategoryState
.NumericAttr
->getDiagnosticName(Policy
);
565 static Attr
*handleOpenCLUnrollHint(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
567 // Although the feature was introduced only in OpenCL C v2.0 s6.11.5, it's
568 // useful for OpenCL 1.x too and doesn't require HW support.
569 // opencl_unroll_hint can have 0 arguments (compiler
570 // determines unrolling factor) or 1 argument (the unroll factor provided
572 unsigned UnrollFactor
= 0;
573 if (A
.getNumArgs() == 1) {
574 Expr
*E
= A
.getArgAsExpr(0);
575 std::optional
<llvm::APSInt
> ArgVal
;
577 if (!(ArgVal
= E
->getIntegerConstantExpr(S
.Context
))) {
578 S
.Diag(A
.getLoc(), diag::err_attribute_argument_type
)
579 << A
<< AANT_ArgumentIntegerConstant
<< E
->getSourceRange();
583 int Val
= ArgVal
->getSExtValue();
585 S
.Diag(A
.getRange().getBegin(),
586 diag::err_attribute_requires_positive_integer
)
587 << A
<< /* positive */ 0;
590 UnrollFactor
= static_cast<unsigned>(Val
);
593 return ::new (S
.Context
) OpenCLUnrollHintAttr(S
.Context
, A
, UnrollFactor
);
596 static Attr
*handleHLSLLoopHintAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
599 if (A
.getSemanticSpelling() == HLSLLoopHintAttr::Spelling::Microsoft_loop
&&
600 !A
.checkAtMostNumArgs(S
, 0))
603 unsigned UnrollFactor
= 0;
604 if (A
.getNumArgs() == 1) {
605 Expr
*E
= A
.getArgAsExpr(0);
607 if (S
.CheckLoopHintExpr(E
, St
->getBeginLoc(),
608 /*AllowZero=*/false))
611 std::optional
<llvm::APSInt
> ArgVal
= E
->getIntegerConstantExpr(S
.Context
);
612 // CheckLoopHintExpr handles non int const cases
613 assert(ArgVal
!= std::nullopt
&& "ArgVal should be an integer constant.");
614 int Val
= ArgVal
->getSExtValue();
615 // CheckLoopHintExpr handles negative and zero cases
616 assert(Val
> 0 && "Val should be a positive integer greater than zero.");
617 UnrollFactor
= static_cast<unsigned>(Val
);
619 return ::new (S
.Context
) HLSLLoopHintAttr(S
.Context
, A
, UnrollFactor
);
622 static Attr
*ProcessStmtAttribute(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
624 if (A
.isInvalid() || A
.getKind() == ParsedAttr::IgnoredAttribute
)
627 // Unknown attributes are automatically warned on. Target-specific attributes
628 // which do not apply to the current target architecture are treated as
629 // though they were unknown attributes.
630 const TargetInfo
*Aux
= S
.Context
.getAuxTargetInfo();
631 if (A
.getKind() == ParsedAttr::UnknownAttribute
||
632 !(A
.existsInTarget(S
.Context
.getTargetInfo()) ||
633 (S
.Context
.getLangOpts().SYCLIsDevice
&& Aux
&&
634 A
.existsInTarget(*Aux
)))) {
635 S
.Diag(A
.getLoc(), A
.isRegularKeywordAttribute()
636 ? (unsigned)diag::err_keyword_not_supported_on_target
637 : A
.isDeclspecAttribute()
638 ? (unsigned)diag::warn_unhandled_ms_attribute_ignored
639 : (unsigned)diag::warn_unknown_attribute_ignored
)
640 << A
<< A
.getRange();
644 if (S
.checkCommonAttributeFeatures(St
, A
))
647 switch (A
.getKind()) {
648 case ParsedAttr::AT_AlwaysInline
:
649 return handleAlwaysInlineAttr(S
, St
, A
, Range
);
650 case ParsedAttr::AT_CXXAssume
:
651 return handleCXXAssumeAttr(S
, St
, A
, Range
);
652 case ParsedAttr::AT_FallThrough
:
653 return handleFallThroughAttr(S
, St
, A
, Range
);
654 case ParsedAttr::AT_LoopHint
:
655 return handleLoopHintAttr(S
, St
, A
, Range
);
656 case ParsedAttr::AT_HLSLLoopHint
:
657 return handleHLSLLoopHintAttr(S
, St
, A
, Range
);
658 case ParsedAttr::AT_OpenCLUnrollHint
:
659 return handleOpenCLUnrollHint(S
, St
, A
, Range
);
660 case ParsedAttr::AT_Suppress
:
661 return handleSuppressAttr(S
, St
, A
, Range
);
662 case ParsedAttr::AT_NoMerge
:
663 return handleNoMergeAttr(S
, St
, A
, Range
);
664 case ParsedAttr::AT_NoInline
:
665 return handleNoInlineAttr(S
, St
, A
, Range
);
666 case ParsedAttr::AT_MustTail
:
667 return handleMustTailAttr(S
, St
, A
, Range
);
668 case ParsedAttr::AT_Likely
:
669 return handleLikely(S
, St
, A
, Range
);
670 case ParsedAttr::AT_Unlikely
:
671 return handleUnlikely(S
, St
, A
, Range
);
672 case ParsedAttr::AT_CodeAlign
:
673 return handleCodeAlignAttr(S
, St
, A
);
674 case ParsedAttr::AT_MSConstexpr
:
675 return handleMSConstexprAttr(S
, St
, A
, Range
);
676 case ParsedAttr::AT_NoConvergent
:
677 return handleNoConvergentAttr(S
, St
, A
, Range
);
678 case ParsedAttr::AT_Annotate
:
679 return S
.CreateAnnotationAttr(A
);
681 if (Attr
*AT
= nullptr; A
.getInfo().handleStmtAttribute(S
, St
, A
, AT
) !=
682 ParsedAttrInfo::NotHandled
) {
685 // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
686 // declaration attribute is not written on a statement, but this code is
687 // needed for attributes in Attr.td that do not list any subjects.
688 S
.Diag(A
.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt
)
689 << A
<< A
.isRegularKeywordAttribute() << St
->getBeginLoc();
694 void Sema::ProcessStmtAttributes(Stmt
*S
, const ParsedAttributes
&InAttrs
,
695 SmallVectorImpl
<const Attr
*> &OutAttrs
) {
696 for (const ParsedAttr
&AL
: InAttrs
) {
697 if (const Attr
*A
= ProcessStmtAttribute(*this, S
, AL
, InAttrs
.Range
))
698 OutAttrs
.push_back(A
);
701 CheckForIncompatibleAttributes(*this, OutAttrs
);
702 CheckForDuplicateLoopAttrs
<CodeAlignAttr
>(*this, OutAttrs
);
705 bool Sema::CheckRebuiltStmtAttributes(ArrayRef
<const Attr
*> Attrs
) {
706 CheckForDuplicateLoopAttrs
<CodeAlignAttr
>(*this, Attrs
);
710 ExprResult
Sema::ActOnCXXAssumeAttr(Stmt
*St
, const ParsedAttr
&A
,
712 if (A
.getNumArgs() != 1 || !A
.getArgAsExpr(0)) {
713 Diag(A
.getLoc(), diag::err_attribute_wrong_number_arguments
)
714 << A
.getAttrName() << 1 << Range
;
718 auto *Assumption
= A
.getArgAsExpr(0);
720 if (DiagnoseUnexpandedParameterPack(Assumption
)) {
724 if (Assumption
->getDependence() == ExprDependence::None
) {
725 ExprResult Res
= BuildCXXAssumeExpr(Assumption
, A
.getAttrName(), Range
);
728 Assumption
= Res
.get();
731 if (!getLangOpts().CPlusPlus23
&&
732 A
.getSyntax() == AttributeCommonInfo::AS_CXX11
)
733 Diag(A
.getLoc(), diag::ext_cxx23_attr
) << A
<< Range
;
738 ExprResult
Sema::BuildCXXAssumeExpr(Expr
*Assumption
,
739 const IdentifierInfo
*AttrName
,
741 ExprResult Res
= CorrectDelayedTyposInExpr(Assumption
);
745 Res
= CheckPlaceholderExpr(Res
.get());
749 Res
= PerformContextuallyConvertToBool(Res
.get());
753 Assumption
= Res
.get();
754 if (Assumption
->HasSideEffects(Context
))
755 Diag(Assumption
->getBeginLoc(), diag::warn_assume_side_effects
)
756 << AttrName
<< Range
;