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/SourceManager.h"
16 #include "clang/Basic/TargetInfo.h"
17 #include "clang/Sema/DelayedDiagnostic.h"
18 #include "clang/Sema/Lookup.h"
19 #include "clang/Sema/ScopeInfo.h"
20 #include "clang/Sema/SemaInternal.h"
21 #include "llvm/ADT/StringExtras.h"
24 using namespace clang
;
27 static Attr
*handleFallThroughAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
29 FallThroughAttr
Attr(S
.Context
, A
);
30 if (isa
<SwitchCase
>(St
)) {
31 S
.Diag(A
.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target
)
32 << A
<< St
->getBeginLoc();
33 SourceLocation L
= S
.getLocForEndOfToken(Range
.getEnd());
34 S
.Diag(L
, diag::note_fallthrough_insert_semi_fixit
)
35 << FixItHint::CreateInsertion(L
, ";");
38 auto *FnScope
= S
.getCurFunction();
39 if (FnScope
->SwitchStack
.empty()) {
40 S
.Diag(A
.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch
);
44 // If this is spelled as the standard C++17 attribute, but not in C++17, warn
45 // about using it as an extension.
46 if (!S
.getLangOpts().CPlusPlus17
&& A
.isCXX11Attribute() &&
48 S
.Diag(A
.getLoc(), diag::ext_cxx17_attr
) << A
;
50 FnScope
->setHasFallthroughStmt();
51 return ::new (S
.Context
) FallThroughAttr(S
.Context
, A
);
54 static Attr
*handleSuppressAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
56 if (A
.getAttributeSpellingListIndex() == SuppressAttr::CXX11_gsl_suppress
&&
58 // Suppression attribute with GSL spelling requires at least 1 argument.
59 S
.Diag(A
.getLoc(), diag::err_attribute_too_few_arguments
) << A
<< 1;
63 std::vector
<StringRef
> DiagnosticIdentifiers
;
64 for (unsigned I
= 0, E
= A
.getNumArgs(); I
!= E
; ++I
) {
67 if (!S
.checkStringLiteralArgumentAttr(A
, I
, RuleName
, nullptr))
70 DiagnosticIdentifiers
.push_back(RuleName
);
73 return ::new (S
.Context
) SuppressAttr(
74 S
.Context
, A
, DiagnosticIdentifiers
.data(), DiagnosticIdentifiers
.size());
77 static Attr
*handleLoopHintAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
79 IdentifierLoc
*PragmaNameLoc
= A
.getArgAsIdent(0);
80 IdentifierLoc
*OptionLoc
= A
.getArgAsIdent(1);
81 IdentifierLoc
*StateLoc
= A
.getArgAsIdent(2);
82 Expr
*ValueExpr
= A
.getArgAsExpr(3);
84 StringRef PragmaName
=
85 llvm::StringSwitch
<StringRef
>(PragmaNameLoc
->Ident
->getName())
86 .Cases("unroll", "nounroll", "unroll_and_jam", "nounroll_and_jam",
87 PragmaNameLoc
->Ident
->getName())
88 .Default("clang loop");
90 // This could be handled automatically by adding a Subjects definition in
91 // Attr.td, but that would make the diagnostic behavior worse in this case
92 // because the user spells this attribute as a pragma.
93 if (!isa
<DoStmt
, ForStmt
, CXXForRangeStmt
, WhileStmt
>(St
)) {
94 std::string Pragma
= "#pragma " + std::string(PragmaName
);
95 S
.Diag(St
->getBeginLoc(), diag::err_pragma_loop_precedes_nonloop
) << Pragma
;
99 LoopHintAttr::OptionType Option
;
100 LoopHintAttr::LoopHintState State
;
102 auto SetHints
= [&Option
, &State
](LoopHintAttr::OptionType O
,
103 LoopHintAttr::LoopHintState S
) {
108 if (PragmaName
== "nounroll") {
109 SetHints(LoopHintAttr::Unroll
, LoopHintAttr::Disable
);
110 } else if (PragmaName
== "unroll") {
113 SetHints(LoopHintAttr::UnrollCount
, LoopHintAttr::Numeric
);
115 SetHints(LoopHintAttr::Unroll
, LoopHintAttr::Enable
);
116 } else if (PragmaName
== "nounroll_and_jam") {
117 SetHints(LoopHintAttr::UnrollAndJam
, LoopHintAttr::Disable
);
118 } else if (PragmaName
== "unroll_and_jam") {
119 // #pragma unroll_and_jam N
121 SetHints(LoopHintAttr::UnrollAndJamCount
, LoopHintAttr::Numeric
);
123 SetHints(LoopHintAttr::UnrollAndJam
, LoopHintAttr::Enable
);
125 // #pragma clang loop ...
126 assert(OptionLoc
&& OptionLoc
->Ident
&&
127 "Attribute must have valid option info.");
128 Option
= llvm::StringSwitch
<LoopHintAttr::OptionType
>(
129 OptionLoc
->Ident
->getName())
130 .Case("vectorize", LoopHintAttr::Vectorize
)
131 .Case("vectorize_width", LoopHintAttr::VectorizeWidth
)
132 .Case("interleave", LoopHintAttr::Interleave
)
133 .Case("vectorize_predicate", LoopHintAttr::VectorizePredicate
)
134 .Case("interleave_count", LoopHintAttr::InterleaveCount
)
135 .Case("unroll", LoopHintAttr::Unroll
)
136 .Case("unroll_count", LoopHintAttr::UnrollCount
)
137 .Case("pipeline", LoopHintAttr::PipelineDisabled
)
138 .Case("pipeline_initiation_interval",
139 LoopHintAttr::PipelineInitiationInterval
)
140 .Case("distribute", LoopHintAttr::Distribute
)
141 .Default(LoopHintAttr::Vectorize
);
142 if (Option
== LoopHintAttr::VectorizeWidth
) {
143 assert((ValueExpr
|| (StateLoc
&& StateLoc
->Ident
)) &&
144 "Attribute must have a valid value expression or argument.");
145 if (ValueExpr
&& S
.CheckLoopHintExpr(ValueExpr
, St
->getBeginLoc()))
147 if (StateLoc
&& StateLoc
->Ident
&& StateLoc
->Ident
->isStr("scalable"))
148 State
= LoopHintAttr::ScalableWidth
;
150 State
= LoopHintAttr::FixedWidth
;
151 } else if (Option
== LoopHintAttr::InterleaveCount
||
152 Option
== LoopHintAttr::UnrollCount
||
153 Option
== LoopHintAttr::PipelineInitiationInterval
) {
154 assert(ValueExpr
&& "Attribute must have a valid value expression.");
155 if (S
.CheckLoopHintExpr(ValueExpr
, St
->getBeginLoc()))
157 State
= LoopHintAttr::Numeric
;
158 } else if (Option
== LoopHintAttr::Vectorize
||
159 Option
== LoopHintAttr::Interleave
||
160 Option
== LoopHintAttr::VectorizePredicate
||
161 Option
== LoopHintAttr::Unroll
||
162 Option
== LoopHintAttr::Distribute
||
163 Option
== LoopHintAttr::PipelineDisabled
) {
164 assert(StateLoc
&& StateLoc
->Ident
&& "Loop hint must have an argument");
165 if (StateLoc
->Ident
->isStr("disable"))
166 State
= LoopHintAttr::Disable
;
167 else if (StateLoc
->Ident
->isStr("assume_safety"))
168 State
= LoopHintAttr::AssumeSafety
;
169 else if (StateLoc
->Ident
->isStr("full"))
170 State
= LoopHintAttr::Full
;
171 else if (StateLoc
->Ident
->isStr("enable"))
172 State
= LoopHintAttr::Enable
;
174 llvm_unreachable("bad loop hint argument");
176 llvm_unreachable("bad loop hint");
179 return LoopHintAttr::CreateImplicit(S
.Context
, Option
, State
, ValueExpr
, A
);
183 class CallExprFinder
: public ConstEvaluatedExprVisitor
<CallExprFinder
> {
184 bool FoundAsmStmt
= false;
185 std::vector
<const CallExpr
*> CallExprs
;
188 typedef ConstEvaluatedExprVisitor
<CallExprFinder
> Inherited
;
190 CallExprFinder(Sema
&S
, const Stmt
*St
) : Inherited(S
.Context
) { Visit(St
); }
192 bool foundCallExpr() { return !CallExprs
.empty(); }
193 const std::vector
<const CallExpr
*> &getCallExprs() { return CallExprs
; }
195 bool foundAsmStmt() { return FoundAsmStmt
; }
197 void VisitCallExpr(const CallExpr
*E
) { CallExprs
.push_back(E
); }
199 void VisitAsmStmt(const AsmStmt
*S
) { FoundAsmStmt
= true; }
201 void Visit(const Stmt
*St
) {
204 ConstEvaluatedExprVisitor
<CallExprFinder
>::Visit(St
);
209 static Attr
*handleNoMergeAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
211 NoMergeAttr
NMA(S
.Context
, A
);
212 CallExprFinder
CEF(S
, St
);
214 if (!CEF
.foundCallExpr() && !CEF
.foundAsmStmt()) {
215 S
.Diag(St
->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt
)
220 return ::new (S
.Context
) NoMergeAttr(S
.Context
, A
);
223 template <typename OtherAttr
, int DiagIdx
>
224 static bool CheckStmtInlineAttr(Sema
&SemaRef
, const Stmt
*OrigSt
,
226 const AttributeCommonInfo
&A
) {
227 CallExprFinder
OrigCEF(SemaRef
, OrigSt
);
228 CallExprFinder
CEF(SemaRef
, CurSt
);
230 // If the call expressions lists are equal in size, we can skip
231 // previously emitted diagnostics. However, if the statement has a pack
232 // expansion, we have no way of telling which CallExpr is the instantiated
233 // version of the other. In this case, we will end up re-diagnosing in the
235 // ie: [[clang::always_inline]] non_dependent(), (other_call<Pack>()...)
236 // will diagnose nondependent again.
237 bool CanSuppressDiag
=
238 OrigSt
&& CEF
.getCallExprs().size() == OrigCEF
.getCallExprs().size();
240 if (!CEF
.foundCallExpr()) {
241 return SemaRef
.Diag(CurSt
->getBeginLoc(),
242 diag::warn_attribute_ignored_no_calls_in_stmt
)
246 for (const auto &Tup
:
247 llvm::zip_longest(OrigCEF
.getCallExprs(), CEF
.getCallExprs())) {
248 // If the original call expression already had a callee, we already
249 // diagnosed this, so skip it here. We can't skip if there isn't a 1:1
250 // relationship between the two lists of call expressions.
251 if (!CanSuppressDiag
|| !(*std::get
<0>(Tup
))->getCalleeDecl()) {
252 const Decl
*Callee
= (*std::get
<1>(Tup
))->getCalleeDecl();
254 (Callee
->hasAttr
<OtherAttr
>() || Callee
->hasAttr
<FlattenAttr
>())) {
255 SemaRef
.Diag(CurSt
->getBeginLoc(),
256 diag::warn_function_stmt_attribute_precedence
)
257 << A
<< (Callee
->hasAttr
<OtherAttr
>() ? DiagIdx
: 1);
258 SemaRef
.Diag(Callee
->getBeginLoc(), diag::note_conflicting_attribute
);
266 bool Sema::CheckNoInlineAttr(const Stmt
*OrigSt
, const Stmt
*CurSt
,
267 const AttributeCommonInfo
&A
) {
268 return CheckStmtInlineAttr
<AlwaysInlineAttr
, 0>(*this, OrigSt
, CurSt
, A
);
271 bool Sema::CheckAlwaysInlineAttr(const Stmt
*OrigSt
, const Stmt
*CurSt
,
272 const AttributeCommonInfo
&A
) {
273 return CheckStmtInlineAttr
<NoInlineAttr
, 2>(*this, OrigSt
, CurSt
, A
);
276 static Attr
*handleNoInlineAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
278 NoInlineAttr
NIA(S
.Context
, A
);
279 if (!NIA
.isClangNoInline()) {
280 S
.Diag(St
->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt
)
281 << "[[clang::noinline]]";
285 if (S
.CheckNoInlineAttr(/*OrigSt=*/nullptr, St
, A
))
288 return ::new (S
.Context
) NoInlineAttr(S
.Context
, A
);
291 static Attr
*handleAlwaysInlineAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
293 AlwaysInlineAttr
AIA(S
.Context
, A
);
294 if (!AIA
.isClangAlwaysInline()) {
295 S
.Diag(St
->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt
)
296 << "[[clang::always_inline]]";
300 if (S
.CheckAlwaysInlineAttr(/*OrigSt=*/nullptr, St
, A
))
303 return ::new (S
.Context
) AlwaysInlineAttr(S
.Context
, A
);
306 static Attr
*handleMustTailAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
308 // Validation is in Sema::ActOnAttributedStmt().
309 return ::new (S
.Context
) MustTailAttr(S
.Context
, A
);
312 static Attr
*handleLikely(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
315 if (!S
.getLangOpts().CPlusPlus20
&& A
.isCXX11Attribute() && !A
.getScopeName())
316 S
.Diag(A
.getLoc(), diag::ext_cxx20_attr
) << A
<< Range
;
318 return ::new (S
.Context
) LikelyAttr(S
.Context
, A
);
321 static Attr
*handleUnlikely(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
324 if (!S
.getLangOpts().CPlusPlus20
&& A
.isCXX11Attribute() && !A
.getScopeName())
325 S
.Diag(A
.getLoc(), diag::ext_cxx20_attr
) << A
<< Range
;
327 return ::new (S
.Context
) UnlikelyAttr(S
.Context
, A
);
330 CodeAlignAttr
*Sema::BuildCodeAlignAttr(const AttributeCommonInfo
&CI
,
332 if (!E
->isValueDependent()) {
334 ExprResult Res
= VerifyIntegerConstantExpression(E
, &ArgVal
);
339 // This attribute requires an integer argument which is a constant power of
340 // two between 1 and 4096 inclusive.
341 if (ArgVal
< CodeAlignAttr::MinimumAlignment
||
342 ArgVal
> CodeAlignAttr::MaximumAlignment
|| !ArgVal
.isPowerOf2()) {
343 if (std::optional
<int64_t> Value
= ArgVal
.trySExtValue())
344 Diag(CI
.getLoc(), diag::err_attribute_power_of_two_in_range
)
345 << CI
<< CodeAlignAttr::MinimumAlignment
346 << CodeAlignAttr::MaximumAlignment
<< Value
.value();
348 Diag(CI
.getLoc(), diag::err_attribute_power_of_two_in_range
)
349 << CI
<< CodeAlignAttr::MinimumAlignment
350 << CodeAlignAttr::MaximumAlignment
<< E
;
354 return new (Context
) CodeAlignAttr(Context
, CI
, E
);
357 static Attr
*handleCodeAlignAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
) {
359 Expr
*E
= A
.getArgAsExpr(0);
360 return S
.BuildCodeAlignAttr(A
, E
);
363 // Diagnose non-identical duplicates as a 'conflicting' loop attributes
364 // and suppress duplicate errors in cases where the two match.
365 template <typename LoopAttrT
>
366 static void CheckForDuplicateLoopAttrs(Sema
&S
, ArrayRef
<const Attr
*> Attrs
) {
367 auto FindFunc
= [](const Attr
*A
) { return isa
<const LoopAttrT
>(A
); };
368 const auto *FirstItr
= std::find_if(Attrs
.begin(), Attrs
.end(), FindFunc
);
370 if (FirstItr
== Attrs
.end()) // no attributes found
373 const auto *LastFoundItr
= FirstItr
;
374 std::optional
<llvm::APSInt
> FirstValue
;
377 dyn_cast
<ConstantExpr
>(cast
<LoopAttrT
>(*FirstItr
)->getAlignment());
378 // Return early if first alignment expression is dependent (since we don't
379 // know what the effective size will be), and skip the loop entirely.
383 while (Attrs
.end() != (LastFoundItr
= std::find_if(LastFoundItr
+ 1,
384 Attrs
.end(), FindFunc
))) {
386 dyn_cast
<ConstantExpr
>(cast
<LoopAttrT
>(*LastFoundItr
)->getAlignment());
387 // If the value is dependent, we can not test anything.
390 // Test the attribute values.
391 llvm::APSInt SecondValue
= CASA
->getResultAsAPSInt();
393 FirstValue
= CAFA
->getResultAsAPSInt();
395 if (FirstValue
!= SecondValue
) {
396 S
.Diag((*LastFoundItr
)->getLocation(), diag::err_loop_attr_conflict
)
398 S
.Diag((*FirstItr
)->getLocation(), diag::note_previous_attribute
);
404 static Attr
*handleMSConstexprAttr(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
406 if (!S
.getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2022_3
)) {
407 S
.Diag(A
.getLoc(), diag::warn_unknown_attribute_ignored
)
408 << A
<< A
.getRange();
411 return ::new (S
.Context
) MSConstexprAttr(S
.Context
, A
);
414 #define WANT_STMT_MERGE_LOGIC
415 #include "clang/Sema/AttrParsedAttrImpl.inc"
416 #undef WANT_STMT_MERGE_LOGIC
419 CheckForIncompatibleAttributes(Sema
&S
,
420 const SmallVectorImpl
<const Attr
*> &Attrs
) {
421 // The vast majority of attributed statements will only have one attribute
422 // on them, so skip all of the checking in the common case.
423 if (Attrs
.size() < 2)
426 // First, check for the easy cases that are table-generated for us.
427 if (!DiagnoseMutualExclusions(S
, Attrs
))
431 // For the following categories, they come in two variants: a state form and
432 // a numeric form. The state form may be one of default, enable, and
433 // disable. The numeric form provides an integer hint (for example, unroll
434 // count) to the transformer.
439 // For unroll, default indicates full unrolling rather than enabling the
442 // The loop distribution transformation only has a state form that is
443 // exposed by #pragma clang loop distribute (enable | disable).
445 // The vector predication only has a state form that is exposed by
446 // #pragma clang loop vectorize_predicate (enable | disable).
448 // This serves as a indicator to how many category are listed in this enum.
451 // The following array accumulates the hints encountered while iterating
452 // through the attributes to check for compatibility.
454 const LoopHintAttr
*StateAttr
;
455 const LoopHintAttr
*NumericAttr
;
456 } HintAttrs
[CategoryType::NumberOfCategories
] = {};
458 for (const auto *I
: Attrs
) {
459 const LoopHintAttr
*LH
= dyn_cast
<LoopHintAttr
>(I
);
461 // Skip non loop hint attributes
465 CategoryType Category
= CategoryType::NumberOfCategories
;
466 LoopHintAttr::OptionType Option
= LH
->getOption();
468 case LoopHintAttr::Vectorize
:
469 case LoopHintAttr::VectorizeWidth
:
470 Category
= Vectorize
;
472 case LoopHintAttr::Interleave
:
473 case LoopHintAttr::InterleaveCount
:
474 Category
= Interleave
;
476 case LoopHintAttr::Unroll
:
477 case LoopHintAttr::UnrollCount
:
480 case LoopHintAttr::UnrollAndJam
:
481 case LoopHintAttr::UnrollAndJamCount
:
482 Category
= UnrollAndJam
;
484 case LoopHintAttr::Distribute
:
485 // Perform the check for duplicated 'distribute' hints.
486 Category
= Distribute
;
488 case LoopHintAttr::PipelineDisabled
:
489 case LoopHintAttr::PipelineInitiationInterval
:
492 case LoopHintAttr::VectorizePredicate
:
493 Category
= VectorizePredicate
;
497 assert(Category
!= NumberOfCategories
&& "Unhandled loop hint option");
498 auto &CategoryState
= HintAttrs
[Category
];
499 const LoopHintAttr
*PrevAttr
;
500 if (Option
== LoopHintAttr::Vectorize
||
501 Option
== LoopHintAttr::Interleave
|| Option
== LoopHintAttr::Unroll
||
502 Option
== LoopHintAttr::UnrollAndJam
||
503 Option
== LoopHintAttr::VectorizePredicate
||
504 Option
== LoopHintAttr::PipelineDisabled
||
505 Option
== LoopHintAttr::Distribute
) {
506 // Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
507 PrevAttr
= CategoryState
.StateAttr
;
508 CategoryState
.StateAttr
= LH
;
510 // Numeric hint. For example, vectorize_width(8).
511 PrevAttr
= CategoryState
.NumericAttr
;
512 CategoryState
.NumericAttr
= LH
;
515 PrintingPolicy
Policy(S
.Context
.getLangOpts());
516 SourceLocation OptionLoc
= LH
->getRange().getBegin();
518 // Cannot specify same type of attribute twice.
519 S
.Diag(OptionLoc
, diag::err_pragma_loop_compatibility
)
520 << /*Duplicate=*/true << PrevAttr
->getDiagnosticName(Policy
)
521 << LH
->getDiagnosticName(Policy
);
523 if (CategoryState
.StateAttr
&& CategoryState
.NumericAttr
&&
524 (Category
== Unroll
|| Category
== UnrollAndJam
||
525 CategoryState
.StateAttr
->getState() == LoopHintAttr::Disable
)) {
526 // Disable hints are not compatible with numeric hints of the same
527 // category. As a special case, numeric unroll hints are also not
528 // compatible with enable or full form of the unroll pragma because these
529 // directives indicate full unrolling.
530 S
.Diag(OptionLoc
, diag::err_pragma_loop_compatibility
)
531 << /*Duplicate=*/false
532 << CategoryState
.StateAttr
->getDiagnosticName(Policy
)
533 << CategoryState
.NumericAttr
->getDiagnosticName(Policy
);
538 static Attr
*handleOpenCLUnrollHint(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
540 // Although the feature was introduced only in OpenCL C v2.0 s6.11.5, it's
541 // useful for OpenCL 1.x too and doesn't require HW support.
542 // opencl_unroll_hint can have 0 arguments (compiler
543 // determines unrolling factor) or 1 argument (the unroll factor provided
545 unsigned UnrollFactor
= 0;
546 if (A
.getNumArgs() == 1) {
547 Expr
*E
= A
.getArgAsExpr(0);
548 std::optional
<llvm::APSInt
> ArgVal
;
550 if (!(ArgVal
= E
->getIntegerConstantExpr(S
.Context
))) {
551 S
.Diag(A
.getLoc(), diag::err_attribute_argument_type
)
552 << A
<< AANT_ArgumentIntegerConstant
<< E
->getSourceRange();
556 int Val
= ArgVal
->getSExtValue();
558 S
.Diag(A
.getRange().getBegin(),
559 diag::err_attribute_requires_positive_integer
)
560 << A
<< /* positive */ 0;
563 UnrollFactor
= static_cast<unsigned>(Val
);
566 return ::new (S
.Context
) OpenCLUnrollHintAttr(S
.Context
, A
, UnrollFactor
);
569 static Attr
*ProcessStmtAttribute(Sema
&S
, Stmt
*St
, const ParsedAttr
&A
,
571 if (A
.isInvalid() || A
.getKind() == ParsedAttr::IgnoredAttribute
)
574 // Unknown attributes are automatically warned on. Target-specific attributes
575 // which do not apply to the current target architecture are treated as
576 // though they were unknown attributes.
577 const TargetInfo
*Aux
= S
.Context
.getAuxTargetInfo();
578 if (A
.getKind() == ParsedAttr::UnknownAttribute
||
579 !(A
.existsInTarget(S
.Context
.getTargetInfo()) ||
580 (S
.Context
.getLangOpts().SYCLIsDevice
&& Aux
&&
581 A
.existsInTarget(*Aux
)))) {
582 S
.Diag(A
.getLoc(), A
.isRegularKeywordAttribute()
583 ? (unsigned)diag::err_keyword_not_supported_on_target
584 : A
.isDeclspecAttribute()
585 ? (unsigned)diag::warn_unhandled_ms_attribute_ignored
586 : (unsigned)diag::warn_unknown_attribute_ignored
)
587 << A
<< A
.getRange();
591 if (S
.checkCommonAttributeFeatures(St
, A
))
594 switch (A
.getKind()) {
595 case ParsedAttr::AT_AlwaysInline
:
596 return handleAlwaysInlineAttr(S
, St
, A
, Range
);
597 case ParsedAttr::AT_FallThrough
:
598 return handleFallThroughAttr(S
, St
, A
, Range
);
599 case ParsedAttr::AT_LoopHint
:
600 return handleLoopHintAttr(S
, St
, A
, Range
);
601 case ParsedAttr::AT_OpenCLUnrollHint
:
602 return handleOpenCLUnrollHint(S
, St
, A
, Range
);
603 case ParsedAttr::AT_Suppress
:
604 return handleSuppressAttr(S
, St
, A
, Range
);
605 case ParsedAttr::AT_NoMerge
:
606 return handleNoMergeAttr(S
, St
, A
, Range
);
607 case ParsedAttr::AT_NoInline
:
608 return handleNoInlineAttr(S
, St
, A
, Range
);
609 case ParsedAttr::AT_MustTail
:
610 return handleMustTailAttr(S
, St
, A
, Range
);
611 case ParsedAttr::AT_Likely
:
612 return handleLikely(S
, St
, A
, Range
);
613 case ParsedAttr::AT_Unlikely
:
614 return handleUnlikely(S
, St
, A
, Range
);
615 case ParsedAttr::AT_CodeAlign
:
616 return handleCodeAlignAttr(S
, St
, A
);
617 case ParsedAttr::AT_MSConstexpr
:
618 return handleMSConstexprAttr(S
, St
, A
, Range
);
620 // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
621 // declaration attribute is not written on a statement, but this code is
622 // needed for attributes in Attr.td that do not list any subjects.
623 S
.Diag(A
.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt
)
624 << A
<< A
.isRegularKeywordAttribute() << St
->getBeginLoc();
629 void Sema::ProcessStmtAttributes(Stmt
*S
, const ParsedAttributes
&InAttrs
,
630 SmallVectorImpl
<const Attr
*> &OutAttrs
) {
631 for (const ParsedAttr
&AL
: InAttrs
) {
632 if (const Attr
*A
= ProcessStmtAttribute(*this, S
, AL
, InAttrs
.Range
))
633 OutAttrs
.push_back(A
);
636 CheckForIncompatibleAttributes(*this, OutAttrs
);
637 CheckForDuplicateLoopAttrs
<CodeAlignAttr
>(*this, OutAttrs
);
640 bool Sema::CheckRebuiltStmtAttributes(ArrayRef
<const Attr
*> Attrs
) {
641 CheckForDuplicateLoopAttrs
<CodeAlignAttr
>(*this, Attrs
);