xref: /llvm-project/clang/lib/Sema/SemaStmtAttr.cpp (revision 380bb51b70b6d9f3da07a87f56fc3fe44bc78691)
1 //===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===//
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 implements stmt-related attribute processing.
10 //
11 //===----------------------------------------------------------------------===//
12 
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"
19 #include <optional>
20 
21 using namespace clang;
22 using namespace sema;
23 
24 static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A,
25                                    SourceRange Range) {
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, ";");
33     return nullptr;
34   }
35   auto *FnScope = S.getCurFunction();
36   if (FnScope->SwitchStack.empty()) {
37     S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch);
38     return nullptr;
39   }
40 
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() &&
44       !A.getScopeName())
45     S.Diag(A.getLoc(), diag::ext_cxx17_attr) << A;
46 
47   FnScope->setHasFallthroughStmt();
48   return ::new (S.Context) FallThroughAttr(S.Context, A);
49 }
50 
51 static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A,
52                                 SourceRange Range) {
53   if (A.getAttributeSpellingListIndex() == SuppressAttr::CXX11_gsl_suppress &&
54       A.getNumArgs() < 1) {
55     // Suppression attribute with GSL spelling requires at least 1 argument.
56     S.Diag(A.getLoc(), diag::err_attribute_too_few_arguments) << A << 1;
57     return nullptr;
58   }
59 
60   std::vector<StringRef> DiagnosticIdentifiers;
61   for (unsigned I = 0, E = A.getNumArgs(); I != E; ++I) {
62     StringRef RuleName;
63 
64     if (!S.checkStringLiteralArgumentAttr(A, I, RuleName, nullptr))
65       return nullptr;
66 
67     DiagnosticIdentifiers.push_back(RuleName);
68   }
69 
70   return ::new (S.Context) SuppressAttr(
71       S.Context, A, DiagnosticIdentifiers.data(), DiagnosticIdentifiers.size());
72 }
73 
74 static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
75                                 SourceRange) {
76   IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
77   IdentifierLoc *OptionLoc = A.getArgAsIdent(1);
78   IdentifierLoc *StateLoc = A.getArgAsIdent(2);
79   Expr *ValueExpr = A.getArgAsExpr(3);
80 
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");
86 
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;
93     return nullptr;
94   }
95 
96   LoopHintAttr::OptionType Option;
97   LoopHintAttr::LoopHintState State;
98 
99   auto SetHints = [&Option, &State](LoopHintAttr::OptionType O,
100                                     LoopHintAttr::LoopHintState S) {
101     Option = O;
102     State = S;
103   };
104 
105   if (PragmaName == "nounroll") {
106     SetHints(LoopHintAttr::Unroll, LoopHintAttr::Disable);
107   } else if (PragmaName == "unroll") {
108     // #pragma unroll N
109     if (ValueExpr) {
110       if (!ValueExpr->isValueDependent()) {
111         auto Value = ValueExpr->EvaluateKnownConstInt(S.getASTContext());
112         if (Value.isZero() || Value.isOne())
113           SetHints(LoopHintAttr::Unroll, LoopHintAttr::Disable);
114         else
115           SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Numeric);
116       } else
117         SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Numeric);
118     } else
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
124     if (ValueExpr)
125       SetHints(LoopHintAttr::UnrollAndJamCount, LoopHintAttr::Numeric);
126     else
127       SetHints(LoopHintAttr::UnrollAndJam, LoopHintAttr::Enable);
128   } else {
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))
151         return nullptr;
152       if (StateLoc && StateLoc->Ident && StateLoc->Ident->isStr("scalable"))
153         State = LoopHintAttr::ScalableWidth;
154       else
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))
162         return nullptr;
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;
179       else
180         llvm_unreachable("bad loop hint argument");
181     } else
182       llvm_unreachable("bad loop hint");
183   }
184 
185   return LoopHintAttr::CreateImplicit(S.Context, Option, State, ValueExpr, A);
186 }
187 
188 namespace {
189 class CallExprFinder : public ConstEvaluatedExprVisitor<CallExprFinder> {
190   bool FoundAsmStmt = false;
191   std::vector<const CallExpr *> CallExprs;
192 
193 public:
194   typedef ConstEvaluatedExprVisitor<CallExprFinder> Inherited;
195 
196   CallExprFinder(Sema &S, const Stmt *St) : Inherited(S.Context) { Visit(St); }
197 
198   bool foundCallExpr() { return !CallExprs.empty(); }
199   const std::vector<const CallExpr *> &getCallExprs() { return CallExprs; }
200 
201   bool foundAsmStmt() { return FoundAsmStmt; }
202 
203   void VisitCallExpr(const CallExpr *E) { CallExprs.push_back(E); }
204 
205   void VisitAsmStmt(const AsmStmt *S) { FoundAsmStmt = true; }
206 
207   void Visit(const Stmt *St) {
208     if (!St)
209       return;
210     ConstEvaluatedExprVisitor<CallExprFinder>::Visit(St);
211   }
212 };
213 } // namespace
214 
215 static Attr *handleNoMergeAttr(Sema &S, Stmt *St, const ParsedAttr &A,
216                                SourceRange Range) {
217   CallExprFinder CEF(S, St);
218 
219   if (!CEF.foundCallExpr() && !CEF.foundAsmStmt()) {
220     S.Diag(St->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt)
221         << A;
222     return nullptr;
223   }
224 
225   return ::new (S.Context) NoMergeAttr(S.Context, A);
226 }
227 
228 static Attr *handleNoConvergentAttr(Sema &S, Stmt *St, const ParsedAttr &A,
229                                     SourceRange Range) {
230   CallExprFinder CEF(S, St);
231 
232   if (!CEF.foundCallExpr() && !CEF.foundAsmStmt()) {
233     S.Diag(St->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt)
234         << A;
235     return nullptr;
236   }
237 
238   return ::new (S.Context) NoConvergentAttr(S.Context, A);
239 }
240 
241 template <typename OtherAttr, int DiagIdx>
242 static bool CheckStmtInlineAttr(Sema &SemaRef, const Stmt *OrigSt,
243                                 const Stmt *CurSt,
244                                 const AttributeCommonInfo &A) {
245   CallExprFinder OrigCEF(SemaRef, OrigSt);
246   CallExprFinder CEF(SemaRef, CurSt);
247 
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
252   // instantiation.
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();
257 
258   if (!CEF.foundCallExpr()) {
259     return SemaRef.Diag(CurSt->getBeginLoc(),
260                         diag::warn_attribute_ignored_no_calls_in_stmt)
261            << A;
262   }
263 
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();
271       if (Callee &&
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);
277       }
278     }
279   }
280 
281   return false;
282 }
283 
284 bool Sema::CheckNoInlineAttr(const Stmt *OrigSt, const Stmt *CurSt,
285                              const AttributeCommonInfo &A) {
286   return CheckStmtInlineAttr<AlwaysInlineAttr, 0>(*this, OrigSt, CurSt, A);
287 }
288 
289 bool Sema::CheckAlwaysInlineAttr(const Stmt *OrigSt, const Stmt *CurSt,
290                                  const AttributeCommonInfo &A) {
291   return CheckStmtInlineAttr<NoInlineAttr, 2>(*this, OrigSt, CurSt, A);
292 }
293 
294 static Attr *handleNoInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A,
295                                 SourceRange Range) {
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]]";
300     return nullptr;
301   }
302 
303   if (S.CheckNoInlineAttr(/*OrigSt=*/nullptr, St, A))
304     return nullptr;
305 
306   return ::new (S.Context) NoInlineAttr(S.Context, A);
307 }
308 
309 static Attr *handleAlwaysInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A,
310                                     SourceRange Range) {
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]]";
315     return nullptr;
316   }
317 
318   if (S.CheckAlwaysInlineAttr(/*OrigSt=*/nullptr, St, A))
319     return nullptr;
320 
321   return ::new (S.Context) AlwaysInlineAttr(S.Context, A);
322 }
323 
324 static Attr *handleCXXAssumeAttr(Sema &S, Stmt *St, const ParsedAttr &A,
325                                  SourceRange Range) {
326   ExprResult Res = S.ActOnCXXAssumeAttr(St, A, Range);
327   if (!Res.isUsable())
328     return nullptr;
329 
330   return ::new (S.Context) CXXAssumeAttr(S.Context, A, Res.get());
331 }
332 
333 static Attr *handleMustTailAttr(Sema &S, Stmt *St, const ParsedAttr &A,
334                                 SourceRange Range) {
335   // Validation is in Sema::ActOnAttributedStmt().
336   return ::new (S.Context) MustTailAttr(S.Context, A);
337 }
338 
339 static Attr *handleLikely(Sema &S, Stmt *St, const ParsedAttr &A,
340                           SourceRange Range) {
341 
342   if (!S.getLangOpts().CPlusPlus20 && A.isCXX11Attribute() && !A.getScopeName())
343     S.Diag(A.getLoc(), diag::ext_cxx20_attr) << A << Range;
344 
345   return ::new (S.Context) LikelyAttr(S.Context, A);
346 }
347 
348 static Attr *handleUnlikely(Sema &S, Stmt *St, const ParsedAttr &A,
349                             SourceRange Range) {
350 
351   if (!S.getLangOpts().CPlusPlus20 && A.isCXX11Attribute() && !A.getScopeName())
352     S.Diag(A.getLoc(), diag::ext_cxx20_attr) << A << Range;
353 
354   return ::new (S.Context) UnlikelyAttr(S.Context, A);
355 }
356 
357 CodeAlignAttr *Sema::BuildCodeAlignAttr(const AttributeCommonInfo &CI,
358                                         Expr *E) {
359   if (!E->isValueDependent()) {
360     llvm::APSInt ArgVal;
361     ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal);
362     if (Res.isInvalid())
363       return nullptr;
364     E = Res.get();
365 
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();
374       else
375         Diag(CI.getLoc(), diag::err_attribute_power_of_two_in_range)
376             << CI << CodeAlignAttr::MinimumAlignment
377             << CodeAlignAttr::MaximumAlignment << E;
378       return nullptr;
379     }
380   }
381   return new (Context) CodeAlignAttr(Context, CI, E);
382 }
383 
384 static Attr *handleCodeAlignAttr(Sema &S, Stmt *St, const ParsedAttr &A) {
385 
386   Expr *E = A.getArgAsExpr(0);
387   return S.BuildCodeAlignAttr(A, E);
388 }
389 
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);
396 
397   if (FirstItr == Attrs.end()) // no attributes found
398     return;
399 
400   const auto *LastFoundItr = FirstItr;
401   std::optional<llvm::APSInt> FirstValue;
402 
403   const auto *CAFA =
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.
407   if (!CAFA)
408     return;
409 
410   while (Attrs.end() != (LastFoundItr = std::find_if(LastFoundItr + 1,
411                                                      Attrs.end(), FindFunc))) {
412     const auto *CASA =
413         dyn_cast<ConstantExpr>(cast<LoopAttrT>(*LastFoundItr)->getAlignment());
414     // If the value is dependent, we can not test anything.
415     if (!CASA)
416       return;
417     // Test the attribute values.
418     llvm::APSInt SecondValue = CASA->getResultAsAPSInt();
419     if (!FirstValue)
420       FirstValue = CAFA->getResultAsAPSInt();
421 
422     if (FirstValue != SecondValue) {
423       S.Diag((*LastFoundItr)->getLocation(), diag::err_loop_attr_conflict)
424           << *FirstItr;
425       S.Diag((*FirstItr)->getLocation(), diag::note_previous_attribute);
426     }
427   }
428   return;
429 }
430 
431 static Attr *handleMSConstexprAttr(Sema &S, Stmt *St, const ParsedAttr &A,
432                                    SourceRange Range) {
433   if (!S.getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2022_3)) {
434     S.Diag(A.getLoc(), diag::warn_unknown_attribute_ignored)
435         << A << A.getRange();
436     return nullptr;
437   }
438   return ::new (S.Context) MSConstexprAttr(S.Context, A);
439 }
440 
441 #define WANT_STMT_MERGE_LOGIC
442 #include "clang/Sema/AttrParsedAttrImpl.inc"
443 #undef WANT_STMT_MERGE_LOGIC
444 
445 static void
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)
451     return;
452 
453   // First, check for the easy cases that are table-generated for us.
454   if (!DiagnoseMutualExclusions(S, Attrs))
455     return;
456 
457   enum CategoryType {
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.
462     Vectorize,
463     Interleave,
464     UnrollAndJam,
465     Pipeline,
466     // For unroll, default indicates full unrolling rather than enabling the
467     // transformation.
468     Unroll,
469     // The loop distribution transformation only has a state form that is
470     // exposed by #pragma clang loop distribute (enable | disable).
471     Distribute,
472     // The vector predication only has a state form that is exposed by
473     // #pragma clang loop vectorize_predicate (enable | disable).
474     VectorizePredicate,
475     // This serves as a indicator to how many category are listed in this enum.
476     NumberOfCategories
477   };
478   // The following array accumulates the hints encountered while iterating
479   // through the attributes to check for compatibility.
480   struct {
481     const LoopHintAttr *StateAttr;
482     const LoopHintAttr *NumericAttr;
483   } HintAttrs[CategoryType::NumberOfCategories] = {};
484 
485   for (const auto *I : Attrs) {
486     const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
487 
488     // Skip non loop hint attributes
489     if (!LH)
490       continue;
491 
492     CategoryType Category = CategoryType::NumberOfCategories;
493     LoopHintAttr::OptionType Option = LH->getOption();
494     switch (Option) {
495     case LoopHintAttr::Vectorize:
496     case LoopHintAttr::VectorizeWidth:
497       Category = Vectorize;
498       break;
499     case LoopHintAttr::Interleave:
500     case LoopHintAttr::InterleaveCount:
501       Category = Interleave;
502       break;
503     case LoopHintAttr::Unroll:
504     case LoopHintAttr::UnrollCount:
505       Category = Unroll;
506       break;
507     case LoopHintAttr::UnrollAndJam:
508     case LoopHintAttr::UnrollAndJamCount:
509       Category = UnrollAndJam;
510       break;
511     case LoopHintAttr::Distribute:
512       // Perform the check for duplicated 'distribute' hints.
513       Category = Distribute;
514       break;
515     case LoopHintAttr::PipelineDisabled:
516     case LoopHintAttr::PipelineInitiationInterval:
517       Category = Pipeline;
518       break;
519     case LoopHintAttr::VectorizePredicate:
520       Category = VectorizePredicate;
521       break;
522     };
523 
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;
536     } else {
537       // Numeric hint.  For example, vectorize_width(8).
538       PrevAttr = CategoryState.NumericAttr;
539       CategoryState.NumericAttr = LH;
540     }
541 
542     PrintingPolicy Policy(S.Context.getLangOpts());
543     SourceLocation OptionLoc = LH->getRange().getBegin();
544     if (PrevAttr)
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);
549 
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);
561     }
562   }
563 }
564 
565 static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A,
566                                     SourceRange Range) {
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
571   // by the user).
572   unsigned UnrollFactor = 0;
573   if (A.getNumArgs() == 1) {
574     Expr *E = A.getArgAsExpr(0);
575     std::optional<llvm::APSInt> ArgVal;
576 
577     if (!(ArgVal = E->getIntegerConstantExpr(S.Context))) {
578       S.Diag(A.getLoc(), diag::err_attribute_argument_type)
579           << A << AANT_ArgumentIntegerConstant << E->getSourceRange();
580       return nullptr;
581     }
582 
583     int Val = ArgVal->getSExtValue();
584     if (Val <= 0) {
585       S.Diag(A.getRange().getBegin(),
586              diag::err_attribute_requires_positive_integer)
587           << A << /* positive */ 0;
588       return nullptr;
589     }
590     UnrollFactor = static_cast<unsigned>(Val);
591   }
592 
593   return ::new (S.Context) OpenCLUnrollHintAttr(S.Context, A, UnrollFactor);
594 }
595 
596 static Attr *handleHLSLLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
597                                     SourceRange Range) {
598 
599   if (A.getSemanticSpelling() == HLSLLoopHintAttr::Spelling::Microsoft_loop &&
600       !A.checkAtMostNumArgs(S, 0))
601     return nullptr;
602 
603   unsigned UnrollFactor = 0;
604   if (A.getNumArgs() == 1) {
605     Expr *E = A.getArgAsExpr(0);
606 
607     if (S.CheckLoopHintExpr(E, St->getBeginLoc(),
608                             /*AllowZero=*/false))
609       return nullptr;
610 
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);
618   }
619   return ::new (S.Context) HLSLLoopHintAttr(S.Context, A, UnrollFactor);
620 }
621 
622 static Attr *handleHLSLControlFlowHint(Sema &S, Stmt *St, const ParsedAttr &A,
623                                        SourceRange Range) {
624 
625   return ::new (S.Context) HLSLControlFlowHintAttr(S.Context, A);
626 }
627 
628 static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
629                                   SourceRange Range) {
630   if (A.isInvalid() || A.getKind() == ParsedAttr::IgnoredAttribute)
631     return nullptr;
632 
633   // Unknown attributes are automatically warned on. Target-specific attributes
634   // which do not apply to the current target architecture are treated as
635   // though they were unknown attributes.
636   const TargetInfo *Aux = S.Context.getAuxTargetInfo();
637   if (A.getKind() == ParsedAttr::UnknownAttribute ||
638       !(A.existsInTarget(S.Context.getTargetInfo()) ||
639         (S.Context.getLangOpts().SYCLIsDevice && Aux &&
640          A.existsInTarget(*Aux)))) {
641     S.Diag(A.getLoc(), A.isRegularKeywordAttribute()
642                            ? (unsigned)diag::err_keyword_not_supported_on_target
643                        : A.isDeclspecAttribute()
644                            ? (unsigned)diag::warn_unhandled_ms_attribute_ignored
645                            : (unsigned)diag::warn_unknown_attribute_ignored)
646         << A << A.getRange();
647     return nullptr;
648   }
649 
650   if (S.checkCommonAttributeFeatures(St, A))
651     return nullptr;
652 
653   switch (A.getKind()) {
654   case ParsedAttr::AT_AlwaysInline:
655     return handleAlwaysInlineAttr(S, St, A, Range);
656   case ParsedAttr::AT_CXXAssume:
657     return handleCXXAssumeAttr(S, St, A, Range);
658   case ParsedAttr::AT_FallThrough:
659     return handleFallThroughAttr(S, St, A, Range);
660   case ParsedAttr::AT_LoopHint:
661     return handleLoopHintAttr(S, St, A, Range);
662   case ParsedAttr::AT_HLSLLoopHint:
663     return handleHLSLLoopHintAttr(S, St, A, Range);
664   case ParsedAttr::AT_HLSLControlFlowHint:
665     return handleHLSLControlFlowHint(S, St, A, Range);
666   case ParsedAttr::AT_OpenCLUnrollHint:
667     return handleOpenCLUnrollHint(S, St, A, Range);
668   case ParsedAttr::AT_Suppress:
669     return handleSuppressAttr(S, St, A, Range);
670   case ParsedAttr::AT_NoMerge:
671     return handleNoMergeAttr(S, St, A, Range);
672   case ParsedAttr::AT_NoInline:
673     return handleNoInlineAttr(S, St, A, Range);
674   case ParsedAttr::AT_MustTail:
675     return handleMustTailAttr(S, St, A, Range);
676   case ParsedAttr::AT_Likely:
677     return handleLikely(S, St, A, Range);
678   case ParsedAttr::AT_Unlikely:
679     return handleUnlikely(S, St, A, Range);
680   case ParsedAttr::AT_CodeAlign:
681     return handleCodeAlignAttr(S, St, A);
682   case ParsedAttr::AT_MSConstexpr:
683     return handleMSConstexprAttr(S, St, A, Range);
684   case ParsedAttr::AT_NoConvergent:
685     return handleNoConvergentAttr(S, St, A, Range);
686   case ParsedAttr::AT_Annotate:
687     return S.CreateAnnotationAttr(A);
688   default:
689     if (Attr *AT = nullptr; A.getInfo().handleStmtAttribute(S, St, A, AT) !=
690                             ParsedAttrInfo::NotHandled) {
691       return AT;
692     }
693     // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
694     // declaration attribute is not written on a statement, but this code is
695     // needed for attributes in Attr.td that do not list any subjects.
696     S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
697         << A << A.isRegularKeywordAttribute() << St->getBeginLoc();
698     return nullptr;
699   }
700 }
701 
702 void Sema::ProcessStmtAttributes(Stmt *S, const ParsedAttributes &InAttrs,
703                                  SmallVectorImpl<const Attr *> &OutAttrs) {
704   for (const ParsedAttr &AL : InAttrs) {
705     if (const Attr *A = ProcessStmtAttribute(*this, S, AL, InAttrs.Range))
706       OutAttrs.push_back(A);
707   }
708 
709   CheckForIncompatibleAttributes(*this, OutAttrs);
710   CheckForDuplicateLoopAttrs<CodeAlignAttr>(*this, OutAttrs);
711 }
712 
713 bool Sema::CheckRebuiltStmtAttributes(ArrayRef<const Attr *> Attrs) {
714   CheckForDuplicateLoopAttrs<CodeAlignAttr>(*this, Attrs);
715   return false;
716 }
717 
718 ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A,
719                                     SourceRange Range) {
720   if (A.getNumArgs() != 1 || !A.getArgAsExpr(0)) {
721     Diag(A.getLoc(), diag::err_attribute_wrong_number_arguments)
722         << A.getAttrName() << 1 << Range;
723     return ExprError();
724   }
725 
726   auto *Assumption = A.getArgAsExpr(0);
727 
728   if (DiagnoseUnexpandedParameterPack(Assumption)) {
729     return ExprError();
730   }
731 
732   if (Assumption->getDependence() == ExprDependence::None) {
733     ExprResult Res = BuildCXXAssumeExpr(Assumption, A.getAttrName(), Range);
734     if (Res.isInvalid())
735       return ExprError();
736     Assumption = Res.get();
737   }
738 
739   if (!getLangOpts().CPlusPlus23 &&
740       A.getSyntax() == AttributeCommonInfo::AS_CXX11)
741     Diag(A.getLoc(), diag::ext_cxx23_attr) << A << Range;
742 
743   return Assumption;
744 }
745 
746 ExprResult Sema::BuildCXXAssumeExpr(Expr *Assumption,
747                                     const IdentifierInfo *AttrName,
748                                     SourceRange Range) {
749   ExprResult Res = CorrectDelayedTyposInExpr(Assumption);
750   if (Res.isInvalid())
751     return ExprError();
752 
753   Res = CheckPlaceholderExpr(Res.get());
754   if (Res.isInvalid())
755     return ExprError();
756 
757   Res = PerformContextuallyConvertToBool(Res.get());
758   if (Res.isInvalid())
759     return ExprError();
760 
761   Assumption = Res.get();
762   if (Assumption->HasSideEffects(Context))
763     Diag(Assumption->getBeginLoc(), diag::warn_assume_side_effects)
764         << AttrName << Range;
765 
766   return Assumption;
767 }
768