xref: /freebsd-src/contrib/llvm-project/clang/lib/Sema/SemaStmtAttr.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file implements stmt-related attribute processing.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
14e8d8bef9SDimitry Andric #include "clang/AST/EvaluatedExprVisitor.h"
150b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
16e8d8bef9SDimitry Andric #include "clang/Basic/TargetInfo.h"
170b57cec5SDimitry Andric #include "clang/Sema/DelayedDiagnostic.h"
180b57cec5SDimitry Andric #include "clang/Sema/Lookup.h"
19*0fca6ea1SDimitry Andric #include "clang/Sema/ParsedAttr.h"
200b57cec5SDimitry Andric #include "clang/Sema/ScopeInfo.h"
21e8d8bef9SDimitry Andric #include "clang/Sema/SemaInternal.h"
220b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
23bdd1243dSDimitry Andric #include <optional>
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace clang;
260b57cec5SDimitry Andric using namespace sema;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A,
290b57cec5SDimitry Andric                                    SourceRange Range) {
30a7dea167SDimitry Andric   FallThroughAttr Attr(S.Context, A);
310b57cec5SDimitry Andric   if (isa<SwitchCase>(St)) {
32fe6060f1SDimitry Andric     S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
33fe6060f1SDimitry Andric         << A << St->getBeginLoc();
340b57cec5SDimitry Andric     SourceLocation L = S.getLocForEndOfToken(Range.getEnd());
350b57cec5SDimitry Andric     S.Diag(L, diag::note_fallthrough_insert_semi_fixit)
360b57cec5SDimitry Andric         << FixItHint::CreateInsertion(L, ";");
370b57cec5SDimitry Andric     return nullptr;
380b57cec5SDimitry Andric   }
390b57cec5SDimitry Andric   auto *FnScope = S.getCurFunction();
400b57cec5SDimitry Andric   if (FnScope->SwitchStack.empty()) {
410b57cec5SDimitry Andric     S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch);
420b57cec5SDimitry Andric     return nullptr;
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   // If this is spelled as the standard C++17 attribute, but not in C++17, warn
460b57cec5SDimitry Andric   // about using it as an extension.
470b57cec5SDimitry Andric   if (!S.getLangOpts().CPlusPlus17 && A.isCXX11Attribute() &&
480b57cec5SDimitry Andric       !A.getScopeName())
49a7dea167SDimitry Andric     S.Diag(A.getLoc(), diag::ext_cxx17_attr) << A;
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   FnScope->setHasFallthroughStmt();
52a7dea167SDimitry Andric   return ::new (S.Context) FallThroughAttr(S.Context, A);
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A,
560b57cec5SDimitry Andric                                 SourceRange Range) {
575f757f3fSDimitry Andric   if (A.getAttributeSpellingListIndex() == SuppressAttr::CXX11_gsl_suppress &&
585f757f3fSDimitry Andric       A.getNumArgs() < 1) {
595f757f3fSDimitry Andric     // Suppression attribute with GSL spelling requires at least 1 argument.
605f757f3fSDimitry Andric     S.Diag(A.getLoc(), diag::err_attribute_too_few_arguments) << A << 1;
615f757f3fSDimitry Andric     return nullptr;
625f757f3fSDimitry Andric   }
635f757f3fSDimitry Andric 
640b57cec5SDimitry Andric   std::vector<StringRef> DiagnosticIdentifiers;
650b57cec5SDimitry Andric   for (unsigned I = 0, E = A.getNumArgs(); I != E; ++I) {
660b57cec5SDimitry Andric     StringRef RuleName;
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric     if (!S.checkStringLiteralArgumentAttr(A, I, RuleName, nullptr))
690b57cec5SDimitry Andric       return nullptr;
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric     DiagnosticIdentifiers.push_back(RuleName);
720b57cec5SDimitry Andric   }
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   return ::new (S.Context) SuppressAttr(
75a7dea167SDimitry Andric       S.Context, A, DiagnosticIdentifiers.data(), DiagnosticIdentifiers.size());
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
790b57cec5SDimitry Andric                                 SourceRange) {
800b57cec5SDimitry Andric   IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
810b57cec5SDimitry Andric   IdentifierLoc *OptionLoc = A.getArgAsIdent(1);
820b57cec5SDimitry Andric   IdentifierLoc *StateLoc = A.getArgAsIdent(2);
830b57cec5SDimitry Andric   Expr *ValueExpr = A.getArgAsExpr(3);
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   StringRef PragmaName =
860b57cec5SDimitry Andric       llvm::StringSwitch<StringRef>(PragmaNameLoc->Ident->getName())
870b57cec5SDimitry Andric           .Cases("unroll", "nounroll", "unroll_and_jam", "nounroll_and_jam",
880b57cec5SDimitry Andric                  PragmaNameLoc->Ident->getName())
890b57cec5SDimitry Andric           .Default("clang loop");
900b57cec5SDimitry Andric 
91fe6060f1SDimitry Andric   // This could be handled automatically by adding a Subjects definition in
92fe6060f1SDimitry Andric   // Attr.td, but that would make the diagnostic behavior worse in this case
93fe6060f1SDimitry Andric   // because the user spells this attribute as a pragma.
94fe6060f1SDimitry Andric   if (!isa<DoStmt, ForStmt, CXXForRangeStmt, WhileStmt>(St)) {
950b57cec5SDimitry Andric     std::string Pragma = "#pragma " + std::string(PragmaName);
960b57cec5SDimitry Andric     S.Diag(St->getBeginLoc(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
970b57cec5SDimitry Andric     return nullptr;
980b57cec5SDimitry Andric   }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   LoopHintAttr::OptionType Option;
1010b57cec5SDimitry Andric   LoopHintAttr::LoopHintState State;
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   auto SetHints = [&Option, &State](LoopHintAttr::OptionType O,
1040b57cec5SDimitry Andric                                     LoopHintAttr::LoopHintState S) {
1050b57cec5SDimitry Andric     Option = O;
1060b57cec5SDimitry Andric     State = S;
1070b57cec5SDimitry Andric   };
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   if (PragmaName == "nounroll") {
1100b57cec5SDimitry Andric     SetHints(LoopHintAttr::Unroll, LoopHintAttr::Disable);
1110b57cec5SDimitry Andric   } else if (PragmaName == "unroll") {
1120b57cec5SDimitry Andric     // #pragma unroll N
113*0fca6ea1SDimitry Andric     if (ValueExpr) {
114*0fca6ea1SDimitry Andric       if (!ValueExpr->isValueDependent()) {
115*0fca6ea1SDimitry Andric         auto Value = ValueExpr->EvaluateKnownConstInt(S.getASTContext());
116*0fca6ea1SDimitry Andric         if (Value.isZero() || Value.isOne())
117*0fca6ea1SDimitry Andric           SetHints(LoopHintAttr::Unroll, LoopHintAttr::Disable);
1180b57cec5SDimitry Andric         else
119*0fca6ea1SDimitry Andric           SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Numeric);
120*0fca6ea1SDimitry Andric       } else
121*0fca6ea1SDimitry Andric         SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Numeric);
122*0fca6ea1SDimitry Andric     } else
1230b57cec5SDimitry Andric       SetHints(LoopHintAttr::Unroll, LoopHintAttr::Enable);
1240b57cec5SDimitry Andric   } else if (PragmaName == "nounroll_and_jam") {
1250b57cec5SDimitry Andric     SetHints(LoopHintAttr::UnrollAndJam, LoopHintAttr::Disable);
1260b57cec5SDimitry Andric   } else if (PragmaName == "unroll_and_jam") {
1270b57cec5SDimitry Andric     // #pragma unroll_and_jam N
1280b57cec5SDimitry Andric     if (ValueExpr)
1290b57cec5SDimitry Andric       SetHints(LoopHintAttr::UnrollAndJamCount, LoopHintAttr::Numeric);
1300b57cec5SDimitry Andric     else
1310b57cec5SDimitry Andric       SetHints(LoopHintAttr::UnrollAndJam, LoopHintAttr::Enable);
1320b57cec5SDimitry Andric   } else {
1330b57cec5SDimitry Andric     // #pragma clang loop ...
1340b57cec5SDimitry Andric     assert(OptionLoc && OptionLoc->Ident &&
1350b57cec5SDimitry Andric            "Attribute must have valid option info.");
1360b57cec5SDimitry Andric     Option = llvm::StringSwitch<LoopHintAttr::OptionType>(
1370b57cec5SDimitry Andric                  OptionLoc->Ident->getName())
1380b57cec5SDimitry Andric                  .Case("vectorize", LoopHintAttr::Vectorize)
1390b57cec5SDimitry Andric                  .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
1400b57cec5SDimitry Andric                  .Case("interleave", LoopHintAttr::Interleave)
141a7dea167SDimitry Andric                  .Case("vectorize_predicate", LoopHintAttr::VectorizePredicate)
1420b57cec5SDimitry Andric                  .Case("interleave_count", LoopHintAttr::InterleaveCount)
1430b57cec5SDimitry Andric                  .Case("unroll", LoopHintAttr::Unroll)
1440b57cec5SDimitry Andric                  .Case("unroll_count", LoopHintAttr::UnrollCount)
1450b57cec5SDimitry Andric                  .Case("pipeline", LoopHintAttr::PipelineDisabled)
1460b57cec5SDimitry Andric                  .Case("pipeline_initiation_interval",
1470b57cec5SDimitry Andric                        LoopHintAttr::PipelineInitiationInterval)
1480b57cec5SDimitry Andric                  .Case("distribute", LoopHintAttr::Distribute)
1490b57cec5SDimitry Andric                  .Default(LoopHintAttr::Vectorize);
150e8d8bef9SDimitry Andric     if (Option == LoopHintAttr::VectorizeWidth) {
151e8d8bef9SDimitry Andric       assert((ValueExpr || (StateLoc && StateLoc->Ident)) &&
152e8d8bef9SDimitry Andric              "Attribute must have a valid value expression or argument.");
153*0fca6ea1SDimitry Andric       if (ValueExpr && S.CheckLoopHintExpr(ValueExpr, St->getBeginLoc(),
154*0fca6ea1SDimitry Andric                                            /*AllowZero=*/false))
155e8d8bef9SDimitry Andric         return nullptr;
156e8d8bef9SDimitry Andric       if (StateLoc && StateLoc->Ident && StateLoc->Ident->isStr("scalable"))
157e8d8bef9SDimitry Andric         State = LoopHintAttr::ScalableWidth;
158e8d8bef9SDimitry Andric       else
159e8d8bef9SDimitry Andric         State = LoopHintAttr::FixedWidth;
160e8d8bef9SDimitry Andric     } else if (Option == LoopHintAttr::InterleaveCount ||
1610b57cec5SDimitry Andric                Option == LoopHintAttr::UnrollCount ||
1620b57cec5SDimitry Andric                Option == LoopHintAttr::PipelineInitiationInterval) {
1630b57cec5SDimitry Andric       assert(ValueExpr && "Attribute must have a valid value expression.");
164*0fca6ea1SDimitry Andric       if (S.CheckLoopHintExpr(ValueExpr, St->getBeginLoc(),
165*0fca6ea1SDimitry Andric                               /*AllowZero=*/false))
1660b57cec5SDimitry Andric         return nullptr;
1670b57cec5SDimitry Andric       State = LoopHintAttr::Numeric;
1680b57cec5SDimitry Andric     } else if (Option == LoopHintAttr::Vectorize ||
1690b57cec5SDimitry Andric                Option == LoopHintAttr::Interleave ||
170a7dea167SDimitry Andric                Option == LoopHintAttr::VectorizePredicate ||
1710b57cec5SDimitry Andric                Option == LoopHintAttr::Unroll ||
1720b57cec5SDimitry Andric                Option == LoopHintAttr::Distribute ||
1730b57cec5SDimitry Andric                Option == LoopHintAttr::PipelineDisabled) {
1740b57cec5SDimitry Andric       assert(StateLoc && StateLoc->Ident && "Loop hint must have an argument");
1750b57cec5SDimitry Andric       if (StateLoc->Ident->isStr("disable"))
1760b57cec5SDimitry Andric         State = LoopHintAttr::Disable;
1770b57cec5SDimitry Andric       else if (StateLoc->Ident->isStr("assume_safety"))
1780b57cec5SDimitry Andric         State = LoopHintAttr::AssumeSafety;
1790b57cec5SDimitry Andric       else if (StateLoc->Ident->isStr("full"))
1800b57cec5SDimitry Andric         State = LoopHintAttr::Full;
1810b57cec5SDimitry Andric       else if (StateLoc->Ident->isStr("enable"))
1820b57cec5SDimitry Andric         State = LoopHintAttr::Enable;
1830b57cec5SDimitry Andric       else
1840b57cec5SDimitry Andric         llvm_unreachable("bad loop hint argument");
1850b57cec5SDimitry Andric     } else
1860b57cec5SDimitry Andric       llvm_unreachable("bad loop hint");
1870b57cec5SDimitry Andric   }
1880b57cec5SDimitry Andric 
189a7dea167SDimitry Andric   return LoopHintAttr::CreateImplicit(S.Context, Option, State, ValueExpr, A);
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
1925ffd83dbSDimitry Andric namespace {
1935ffd83dbSDimitry Andric class CallExprFinder : public ConstEvaluatedExprVisitor<CallExprFinder> {
19481ad6265SDimitry Andric   bool FoundAsmStmt = false;
19581ad6265SDimitry Andric   std::vector<const CallExpr *> CallExprs;
1965ffd83dbSDimitry Andric 
1975ffd83dbSDimitry Andric public:
1985ffd83dbSDimitry Andric   typedef ConstEvaluatedExprVisitor<CallExprFinder> Inherited;
1995ffd83dbSDimitry Andric 
2005ffd83dbSDimitry Andric   CallExprFinder(Sema &S, const Stmt *St) : Inherited(S.Context) { Visit(St); }
2015ffd83dbSDimitry Andric 
20281ad6265SDimitry Andric   bool foundCallExpr() { return !CallExprs.empty(); }
20381ad6265SDimitry Andric   const std::vector<const CallExpr *> &getCallExprs() { return CallExprs; }
2045ffd83dbSDimitry Andric 
20581ad6265SDimitry Andric   bool foundAsmStmt() { return FoundAsmStmt; }
20681ad6265SDimitry Andric 
20781ad6265SDimitry Andric   void VisitCallExpr(const CallExpr *E) { CallExprs.push_back(E); }
20881ad6265SDimitry Andric 
20981ad6265SDimitry Andric   void VisitAsmStmt(const AsmStmt *S) { FoundAsmStmt = true; }
2105ffd83dbSDimitry Andric 
2115ffd83dbSDimitry Andric   void Visit(const Stmt *St) {
2125ffd83dbSDimitry Andric     if (!St)
2135ffd83dbSDimitry Andric       return;
2145ffd83dbSDimitry Andric     ConstEvaluatedExprVisitor<CallExprFinder>::Visit(St);
2155ffd83dbSDimitry Andric   }
2165ffd83dbSDimitry Andric };
2175ffd83dbSDimitry Andric } // namespace
2185ffd83dbSDimitry Andric 
2195ffd83dbSDimitry Andric static Attr *handleNoMergeAttr(Sema &S, Stmt *St, const ParsedAttr &A,
2205ffd83dbSDimitry Andric                                SourceRange Range) {
2215ffd83dbSDimitry Andric   NoMergeAttr NMA(S.Context, A);
2225ffd83dbSDimitry Andric   CallExprFinder CEF(S, St);
2235ffd83dbSDimitry Andric 
22481ad6265SDimitry Andric   if (!CEF.foundCallExpr() && !CEF.foundAsmStmt()) {
22581ad6265SDimitry Andric     S.Diag(St->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt)
22681ad6265SDimitry Andric         << A;
2275ffd83dbSDimitry Andric     return nullptr;
2285ffd83dbSDimitry Andric   }
2295ffd83dbSDimitry Andric 
2305ffd83dbSDimitry Andric   return ::new (S.Context) NoMergeAttr(S.Context, A);
2315ffd83dbSDimitry Andric }
2325ffd83dbSDimitry Andric 
23306c3fb27SDimitry Andric template <typename OtherAttr, int DiagIdx>
23406c3fb27SDimitry Andric static bool CheckStmtInlineAttr(Sema &SemaRef, const Stmt *OrigSt,
23506c3fb27SDimitry Andric                                 const Stmt *CurSt,
23606c3fb27SDimitry Andric                                 const AttributeCommonInfo &A) {
23706c3fb27SDimitry Andric   CallExprFinder OrigCEF(SemaRef, OrigSt);
23806c3fb27SDimitry Andric   CallExprFinder CEF(SemaRef, CurSt);
23906c3fb27SDimitry Andric 
24006c3fb27SDimitry Andric   // If the call expressions lists are equal in size, we can skip
24106c3fb27SDimitry Andric   // previously emitted diagnostics. However, if the statement has a pack
24206c3fb27SDimitry Andric   // expansion, we have no way of telling which CallExpr is the instantiated
24306c3fb27SDimitry Andric   // version of the other. In this case, we will end up re-diagnosing in the
24406c3fb27SDimitry Andric   // instantiation.
24506c3fb27SDimitry Andric   // ie: [[clang::always_inline]] non_dependent(), (other_call<Pack>()...)
24606c3fb27SDimitry Andric   // will diagnose nondependent again.
24706c3fb27SDimitry Andric   bool CanSuppressDiag =
24806c3fb27SDimitry Andric       OrigSt && CEF.getCallExprs().size() == OrigCEF.getCallExprs().size();
24906c3fb27SDimitry Andric 
25006c3fb27SDimitry Andric   if (!CEF.foundCallExpr()) {
25106c3fb27SDimitry Andric     return SemaRef.Diag(CurSt->getBeginLoc(),
25206c3fb27SDimitry Andric                         diag::warn_attribute_ignored_no_calls_in_stmt)
25306c3fb27SDimitry Andric            << A;
25406c3fb27SDimitry Andric   }
25506c3fb27SDimitry Andric 
25606c3fb27SDimitry Andric   for (const auto &Tup :
25706c3fb27SDimitry Andric        llvm::zip_longest(OrigCEF.getCallExprs(), CEF.getCallExprs())) {
25806c3fb27SDimitry Andric     // If the original call expression already had a callee, we already
25906c3fb27SDimitry Andric     // diagnosed this, so skip it here. We can't skip if there isn't a 1:1
26006c3fb27SDimitry Andric     // relationship between the two lists of call expressions.
26106c3fb27SDimitry Andric     if (!CanSuppressDiag || !(*std::get<0>(Tup))->getCalleeDecl()) {
26206c3fb27SDimitry Andric       const Decl *Callee = (*std::get<1>(Tup))->getCalleeDecl();
26306c3fb27SDimitry Andric       if (Callee &&
26406c3fb27SDimitry Andric           (Callee->hasAttr<OtherAttr>() || Callee->hasAttr<FlattenAttr>())) {
26506c3fb27SDimitry Andric         SemaRef.Diag(CurSt->getBeginLoc(),
26606c3fb27SDimitry Andric                      diag::warn_function_stmt_attribute_precedence)
26706c3fb27SDimitry Andric             << A << (Callee->hasAttr<OtherAttr>() ? DiagIdx : 1);
26806c3fb27SDimitry Andric         SemaRef.Diag(Callee->getBeginLoc(), diag::note_conflicting_attribute);
26906c3fb27SDimitry Andric       }
27006c3fb27SDimitry Andric     }
27106c3fb27SDimitry Andric   }
27206c3fb27SDimitry Andric 
27306c3fb27SDimitry Andric   return false;
27406c3fb27SDimitry Andric }
27506c3fb27SDimitry Andric 
27606c3fb27SDimitry Andric bool Sema::CheckNoInlineAttr(const Stmt *OrigSt, const Stmt *CurSt,
27706c3fb27SDimitry Andric                              const AttributeCommonInfo &A) {
27806c3fb27SDimitry Andric   return CheckStmtInlineAttr<AlwaysInlineAttr, 0>(*this, OrigSt, CurSt, A);
27906c3fb27SDimitry Andric }
28006c3fb27SDimitry Andric 
28106c3fb27SDimitry Andric bool Sema::CheckAlwaysInlineAttr(const Stmt *OrigSt, const Stmt *CurSt,
28206c3fb27SDimitry Andric                                  const AttributeCommonInfo &A) {
28306c3fb27SDimitry Andric   return CheckStmtInlineAttr<NoInlineAttr, 2>(*this, OrigSt, CurSt, A);
28406c3fb27SDimitry Andric }
28506c3fb27SDimitry Andric 
28681ad6265SDimitry Andric static Attr *handleNoInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A,
28781ad6265SDimitry Andric                                 SourceRange Range) {
28881ad6265SDimitry Andric   NoInlineAttr NIA(S.Context, A);
289*0fca6ea1SDimitry Andric   if (!NIA.isStmtNoInline()) {
29081ad6265SDimitry Andric     S.Diag(St->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt)
29181ad6265SDimitry Andric         << "[[clang::noinline]]";
29281ad6265SDimitry Andric     return nullptr;
29381ad6265SDimitry Andric   }
29481ad6265SDimitry Andric 
29506c3fb27SDimitry Andric   if (S.CheckNoInlineAttr(/*OrigSt=*/nullptr, St, A))
29681ad6265SDimitry Andric     return nullptr;
29781ad6265SDimitry Andric 
29881ad6265SDimitry Andric   return ::new (S.Context) NoInlineAttr(S.Context, A);
29981ad6265SDimitry Andric }
30081ad6265SDimitry Andric 
30181ad6265SDimitry Andric static Attr *handleAlwaysInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A,
30281ad6265SDimitry Andric                                     SourceRange Range) {
30381ad6265SDimitry Andric   AlwaysInlineAttr AIA(S.Context, A);
30481ad6265SDimitry Andric   if (!AIA.isClangAlwaysInline()) {
30581ad6265SDimitry Andric     S.Diag(St->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt)
30681ad6265SDimitry Andric         << "[[clang::always_inline]]";
30781ad6265SDimitry Andric     return nullptr;
30881ad6265SDimitry Andric   }
30981ad6265SDimitry Andric 
31006c3fb27SDimitry Andric   if (S.CheckAlwaysInlineAttr(/*OrigSt=*/nullptr, St, A))
31181ad6265SDimitry Andric     return nullptr;
31281ad6265SDimitry Andric 
31381ad6265SDimitry Andric   return ::new (S.Context) AlwaysInlineAttr(S.Context, A);
31481ad6265SDimitry Andric }
31581ad6265SDimitry Andric 
316*0fca6ea1SDimitry Andric static Attr *handleCXXAssumeAttr(Sema &S, Stmt *St, const ParsedAttr &A,
317*0fca6ea1SDimitry Andric                                  SourceRange Range) {
318*0fca6ea1SDimitry Andric   ExprResult Res = S.ActOnCXXAssumeAttr(St, A, Range);
319*0fca6ea1SDimitry Andric   if (!Res.isUsable())
320*0fca6ea1SDimitry Andric     return nullptr;
321*0fca6ea1SDimitry Andric 
322*0fca6ea1SDimitry Andric   return ::new (S.Context) CXXAssumeAttr(S.Context, A, Res.get());
323*0fca6ea1SDimitry Andric }
324*0fca6ea1SDimitry Andric 
325fe6060f1SDimitry Andric static Attr *handleMustTailAttr(Sema &S, Stmt *St, const ParsedAttr &A,
326fe6060f1SDimitry Andric                                 SourceRange Range) {
327fe6060f1SDimitry Andric   // Validation is in Sema::ActOnAttributedStmt().
328fe6060f1SDimitry Andric   return ::new (S.Context) MustTailAttr(S.Context, A);
329fe6060f1SDimitry Andric }
330fe6060f1SDimitry Andric 
331e8d8bef9SDimitry Andric static Attr *handleLikely(Sema &S, Stmt *St, const ParsedAttr &A,
332e8d8bef9SDimitry Andric                           SourceRange Range) {
333e8d8bef9SDimitry Andric 
334e8d8bef9SDimitry Andric   if (!S.getLangOpts().CPlusPlus20 && A.isCXX11Attribute() && !A.getScopeName())
335e8d8bef9SDimitry Andric     S.Diag(A.getLoc(), diag::ext_cxx20_attr) << A << Range;
336e8d8bef9SDimitry Andric 
337e8d8bef9SDimitry Andric   return ::new (S.Context) LikelyAttr(S.Context, A);
338e8d8bef9SDimitry Andric }
339e8d8bef9SDimitry Andric 
340e8d8bef9SDimitry Andric static Attr *handleUnlikely(Sema &S, Stmt *St, const ParsedAttr &A,
341e8d8bef9SDimitry Andric                             SourceRange Range) {
342e8d8bef9SDimitry Andric 
343e8d8bef9SDimitry Andric   if (!S.getLangOpts().CPlusPlus20 && A.isCXX11Attribute() && !A.getScopeName())
344e8d8bef9SDimitry Andric     S.Diag(A.getLoc(), diag::ext_cxx20_attr) << A << Range;
345e8d8bef9SDimitry Andric 
346e8d8bef9SDimitry Andric   return ::new (S.Context) UnlikelyAttr(S.Context, A);
347e8d8bef9SDimitry Andric }
348e8d8bef9SDimitry Andric 
3495f757f3fSDimitry Andric CodeAlignAttr *Sema::BuildCodeAlignAttr(const AttributeCommonInfo &CI,
3505f757f3fSDimitry Andric                                         Expr *E) {
3515f757f3fSDimitry Andric   if (!E->isValueDependent()) {
3525f757f3fSDimitry Andric     llvm::APSInt ArgVal;
3535f757f3fSDimitry Andric     ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal);
3545f757f3fSDimitry Andric     if (Res.isInvalid())
3555f757f3fSDimitry Andric       return nullptr;
3565f757f3fSDimitry Andric     E = Res.get();
3575f757f3fSDimitry Andric 
3585f757f3fSDimitry Andric     // This attribute requires an integer argument which is a constant power of
3595f757f3fSDimitry Andric     // two between 1 and 4096 inclusive.
3605f757f3fSDimitry Andric     if (ArgVal < CodeAlignAttr::MinimumAlignment ||
3615f757f3fSDimitry Andric         ArgVal > CodeAlignAttr::MaximumAlignment || !ArgVal.isPowerOf2()) {
3625f757f3fSDimitry Andric       if (std::optional<int64_t> Value = ArgVal.trySExtValue())
3635f757f3fSDimitry Andric         Diag(CI.getLoc(), diag::err_attribute_power_of_two_in_range)
3645f757f3fSDimitry Andric             << CI << CodeAlignAttr::MinimumAlignment
3655f757f3fSDimitry Andric             << CodeAlignAttr::MaximumAlignment << Value.value();
3665f757f3fSDimitry Andric       else
3675f757f3fSDimitry Andric         Diag(CI.getLoc(), diag::err_attribute_power_of_two_in_range)
3685f757f3fSDimitry Andric             << CI << CodeAlignAttr::MinimumAlignment
3695f757f3fSDimitry Andric             << CodeAlignAttr::MaximumAlignment << E;
3705f757f3fSDimitry Andric       return nullptr;
3715f757f3fSDimitry Andric     }
3725f757f3fSDimitry Andric   }
3735f757f3fSDimitry Andric   return new (Context) CodeAlignAttr(Context, CI, E);
3745f757f3fSDimitry Andric }
3755f757f3fSDimitry Andric 
3765f757f3fSDimitry Andric static Attr *handleCodeAlignAttr(Sema &S, Stmt *St, const ParsedAttr &A) {
3775f757f3fSDimitry Andric 
3785f757f3fSDimitry Andric   Expr *E = A.getArgAsExpr(0);
3795f757f3fSDimitry Andric   return S.BuildCodeAlignAttr(A, E);
3805f757f3fSDimitry Andric }
3815f757f3fSDimitry Andric 
3825f757f3fSDimitry Andric // Diagnose non-identical duplicates as a 'conflicting' loop attributes
3835f757f3fSDimitry Andric // and suppress duplicate errors in cases where the two match.
3845f757f3fSDimitry Andric template <typename LoopAttrT>
3855f757f3fSDimitry Andric static void CheckForDuplicateLoopAttrs(Sema &S, ArrayRef<const Attr *> Attrs) {
3865f757f3fSDimitry Andric   auto FindFunc = [](const Attr *A) { return isa<const LoopAttrT>(A); };
3875f757f3fSDimitry Andric   const auto *FirstItr = std::find_if(Attrs.begin(), Attrs.end(), FindFunc);
3885f757f3fSDimitry Andric 
3895f757f3fSDimitry Andric   if (FirstItr == Attrs.end()) // no attributes found
3905f757f3fSDimitry Andric     return;
3915f757f3fSDimitry Andric 
3925f757f3fSDimitry Andric   const auto *LastFoundItr = FirstItr;
3935f757f3fSDimitry Andric   std::optional<llvm::APSInt> FirstValue;
3945f757f3fSDimitry Andric 
3955f757f3fSDimitry Andric   const auto *CAFA =
3965f757f3fSDimitry Andric       dyn_cast<ConstantExpr>(cast<LoopAttrT>(*FirstItr)->getAlignment());
3975f757f3fSDimitry Andric   // Return early if first alignment expression is dependent (since we don't
3985f757f3fSDimitry Andric   // know what the effective size will be), and skip the loop entirely.
3995f757f3fSDimitry Andric   if (!CAFA)
4005f757f3fSDimitry Andric     return;
4015f757f3fSDimitry Andric 
4025f757f3fSDimitry Andric   while (Attrs.end() != (LastFoundItr = std::find_if(LastFoundItr + 1,
4035f757f3fSDimitry Andric                                                      Attrs.end(), FindFunc))) {
4045f757f3fSDimitry Andric     const auto *CASA =
4055f757f3fSDimitry Andric         dyn_cast<ConstantExpr>(cast<LoopAttrT>(*LastFoundItr)->getAlignment());
4065f757f3fSDimitry Andric     // If the value is dependent, we can not test anything.
4075f757f3fSDimitry Andric     if (!CASA)
4085f757f3fSDimitry Andric       return;
4095f757f3fSDimitry Andric     // Test the attribute values.
4105f757f3fSDimitry Andric     llvm::APSInt SecondValue = CASA->getResultAsAPSInt();
4115f757f3fSDimitry Andric     if (!FirstValue)
4125f757f3fSDimitry Andric       FirstValue = CAFA->getResultAsAPSInt();
4135f757f3fSDimitry Andric 
4145f757f3fSDimitry Andric     if (FirstValue != SecondValue) {
4155f757f3fSDimitry Andric       S.Diag((*LastFoundItr)->getLocation(), diag::err_loop_attr_conflict)
4165f757f3fSDimitry Andric           << *FirstItr;
4175f757f3fSDimitry Andric       S.Diag((*FirstItr)->getLocation(), diag::note_previous_attribute);
4185f757f3fSDimitry Andric     }
4195f757f3fSDimitry Andric   }
420*0fca6ea1SDimitry Andric   return;
4215f757f3fSDimitry Andric }
4225f757f3fSDimitry Andric 
4235f757f3fSDimitry Andric static Attr *handleMSConstexprAttr(Sema &S, Stmt *St, const ParsedAttr &A,
4245f757f3fSDimitry Andric                                    SourceRange Range) {
4255f757f3fSDimitry Andric   if (!S.getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2022_3)) {
4265f757f3fSDimitry Andric     S.Diag(A.getLoc(), diag::warn_unknown_attribute_ignored)
4275f757f3fSDimitry Andric         << A << A.getRange();
4285f757f3fSDimitry Andric     return nullptr;
4295f757f3fSDimitry Andric   }
4305f757f3fSDimitry Andric   return ::new (S.Context) MSConstexprAttr(S.Context, A);
4315f757f3fSDimitry Andric }
4325f757f3fSDimitry Andric 
433fe6060f1SDimitry Andric #define WANT_STMT_MERGE_LOGIC
434fe6060f1SDimitry Andric #include "clang/Sema/AttrParsedAttrImpl.inc"
435fe6060f1SDimitry Andric #undef WANT_STMT_MERGE_LOGIC
436fe6060f1SDimitry Andric 
4370b57cec5SDimitry Andric static void
4380b57cec5SDimitry Andric CheckForIncompatibleAttributes(Sema &S,
4390b57cec5SDimitry Andric                                const SmallVectorImpl<const Attr *> &Attrs) {
440fe6060f1SDimitry Andric   // The vast majority of attributed statements will only have one attribute
441fe6060f1SDimitry Andric   // on them, so skip all of the checking in the common case.
442fe6060f1SDimitry Andric   if (Attrs.size() < 2)
443fe6060f1SDimitry Andric     return;
444fe6060f1SDimitry Andric 
445fe6060f1SDimitry Andric   // First, check for the easy cases that are table-generated for us.
446fe6060f1SDimitry Andric   if (!DiagnoseMutualExclusions(S, Attrs))
447fe6060f1SDimitry Andric     return;
448fe6060f1SDimitry Andric 
449bdd1243dSDimitry Andric   enum CategoryType {
450bdd1243dSDimitry Andric     // For the following categories, they come in two variants: a state form and
451bdd1243dSDimitry Andric     // a numeric form. The state form may be one of default, enable, and
452bdd1243dSDimitry Andric     // disable. The numeric form provides an integer hint (for example, unroll
453bdd1243dSDimitry Andric     // count) to the transformer.
454bdd1243dSDimitry Andric     Vectorize,
455bdd1243dSDimitry Andric     Interleave,
456bdd1243dSDimitry Andric     UnrollAndJam,
457bdd1243dSDimitry Andric     Pipeline,
458bdd1243dSDimitry Andric     // For unroll, default indicates full unrolling rather than enabling the
459bdd1243dSDimitry Andric     // transformation.
460bdd1243dSDimitry Andric     Unroll,
461bdd1243dSDimitry Andric     // The loop distribution transformation only has a state form that is
462bdd1243dSDimitry Andric     // exposed by #pragma clang loop distribute (enable | disable).
463bdd1243dSDimitry Andric     Distribute,
464bdd1243dSDimitry Andric     // The vector predication only has a state form that is exposed by
465bdd1243dSDimitry Andric     // #pragma clang loop vectorize_predicate (enable | disable).
466bdd1243dSDimitry Andric     VectorizePredicate,
467bdd1243dSDimitry Andric     // This serves as a indicator to how many category are listed in this enum.
468bdd1243dSDimitry Andric     NumberOfCategories
469bdd1243dSDimitry Andric   };
470bdd1243dSDimitry Andric   // The following array accumulates the hints encountered while iterating
471bdd1243dSDimitry Andric   // through the attributes to check for compatibility.
4720b57cec5SDimitry Andric   struct {
4730b57cec5SDimitry Andric     const LoopHintAttr *StateAttr;
4740b57cec5SDimitry Andric     const LoopHintAttr *NumericAttr;
475bdd1243dSDimitry Andric   } HintAttrs[CategoryType::NumberOfCategories] = {};
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric   for (const auto *I : Attrs) {
4780b57cec5SDimitry Andric     const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
4790b57cec5SDimitry Andric 
4800b57cec5SDimitry Andric     // Skip non loop hint attributes
4810b57cec5SDimitry Andric     if (!LH)
4820b57cec5SDimitry Andric       continue;
4830b57cec5SDimitry Andric 
484bdd1243dSDimitry Andric     CategoryType Category = CategoryType::NumberOfCategories;
4850b57cec5SDimitry Andric     LoopHintAttr::OptionType Option = LH->getOption();
4860b57cec5SDimitry Andric     switch (Option) {
4870b57cec5SDimitry Andric     case LoopHintAttr::Vectorize:
4880b57cec5SDimitry Andric     case LoopHintAttr::VectorizeWidth:
4890b57cec5SDimitry Andric       Category = Vectorize;
4900b57cec5SDimitry Andric       break;
4910b57cec5SDimitry Andric     case LoopHintAttr::Interleave:
4920b57cec5SDimitry Andric     case LoopHintAttr::InterleaveCount:
4930b57cec5SDimitry Andric       Category = Interleave;
4940b57cec5SDimitry Andric       break;
4950b57cec5SDimitry Andric     case LoopHintAttr::Unroll:
4960b57cec5SDimitry Andric     case LoopHintAttr::UnrollCount:
4970b57cec5SDimitry Andric       Category = Unroll;
4980b57cec5SDimitry Andric       break;
4990b57cec5SDimitry Andric     case LoopHintAttr::UnrollAndJam:
5000b57cec5SDimitry Andric     case LoopHintAttr::UnrollAndJamCount:
5010b57cec5SDimitry Andric       Category = UnrollAndJam;
5020b57cec5SDimitry Andric       break;
5030b57cec5SDimitry Andric     case LoopHintAttr::Distribute:
5040b57cec5SDimitry Andric       // Perform the check for duplicated 'distribute' hints.
5050b57cec5SDimitry Andric       Category = Distribute;
5060b57cec5SDimitry Andric       break;
5070b57cec5SDimitry Andric     case LoopHintAttr::PipelineDisabled:
5080b57cec5SDimitry Andric     case LoopHintAttr::PipelineInitiationInterval:
5090b57cec5SDimitry Andric       Category = Pipeline;
5100b57cec5SDimitry Andric       break;
511a7dea167SDimitry Andric     case LoopHintAttr::VectorizePredicate:
512a7dea167SDimitry Andric       Category = VectorizePredicate;
513a7dea167SDimitry Andric       break;
5140b57cec5SDimitry Andric     };
5150b57cec5SDimitry Andric 
516bdd1243dSDimitry Andric     assert(Category != NumberOfCategories && "Unhandled loop hint option");
5170b57cec5SDimitry Andric     auto &CategoryState = HintAttrs[Category];
5180b57cec5SDimitry Andric     const LoopHintAttr *PrevAttr;
5190b57cec5SDimitry Andric     if (Option == LoopHintAttr::Vectorize ||
5200b57cec5SDimitry Andric         Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll ||
5210b57cec5SDimitry Andric         Option == LoopHintAttr::UnrollAndJam ||
522a7dea167SDimitry Andric         Option == LoopHintAttr::VectorizePredicate ||
5230b57cec5SDimitry Andric         Option == LoopHintAttr::PipelineDisabled ||
5240b57cec5SDimitry Andric         Option == LoopHintAttr::Distribute) {
5250b57cec5SDimitry Andric       // Enable|Disable|AssumeSafety hint.  For example, vectorize(enable).
5260b57cec5SDimitry Andric       PrevAttr = CategoryState.StateAttr;
5270b57cec5SDimitry Andric       CategoryState.StateAttr = LH;
5280b57cec5SDimitry Andric     } else {
5290b57cec5SDimitry Andric       // Numeric hint.  For example, vectorize_width(8).
5300b57cec5SDimitry Andric       PrevAttr = CategoryState.NumericAttr;
5310b57cec5SDimitry Andric       CategoryState.NumericAttr = LH;
5320b57cec5SDimitry Andric     }
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric     PrintingPolicy Policy(S.Context.getLangOpts());
5350b57cec5SDimitry Andric     SourceLocation OptionLoc = LH->getRange().getBegin();
5360b57cec5SDimitry Andric     if (PrevAttr)
5370b57cec5SDimitry Andric       // Cannot specify same type of attribute twice.
5380b57cec5SDimitry Andric       S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
5390b57cec5SDimitry Andric           << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy)
5400b57cec5SDimitry Andric           << LH->getDiagnosticName(Policy);
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric     if (CategoryState.StateAttr && CategoryState.NumericAttr &&
5430b57cec5SDimitry Andric         (Category == Unroll || Category == UnrollAndJam ||
5440b57cec5SDimitry Andric          CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) {
5450b57cec5SDimitry Andric       // Disable hints are not compatible with numeric hints of the same
5460b57cec5SDimitry Andric       // category.  As a special case, numeric unroll hints are also not
5470b57cec5SDimitry Andric       // compatible with enable or full form of the unroll pragma because these
5480b57cec5SDimitry Andric       // directives indicate full unrolling.
5490b57cec5SDimitry Andric       S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
5500b57cec5SDimitry Andric           << /*Duplicate=*/false
5510b57cec5SDimitry Andric           << CategoryState.StateAttr->getDiagnosticName(Policy)
5520b57cec5SDimitry Andric           << CategoryState.NumericAttr->getDiagnosticName(Policy);
5530b57cec5SDimitry Andric     }
5540b57cec5SDimitry Andric   }
5550b57cec5SDimitry Andric }
5560b57cec5SDimitry Andric 
5570b57cec5SDimitry Andric static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A,
5580b57cec5SDimitry Andric                                     SourceRange Range) {
5590b57cec5SDimitry Andric   // Although the feature was introduced only in OpenCL C v2.0 s6.11.5, it's
5600b57cec5SDimitry Andric   // useful for OpenCL 1.x too and doesn't require HW support.
5610b57cec5SDimitry Andric   // opencl_unroll_hint can have 0 arguments (compiler
5620b57cec5SDimitry Andric   // determines unrolling factor) or 1 argument (the unroll factor provided
5630b57cec5SDimitry Andric   // by the user).
5640b57cec5SDimitry Andric   unsigned UnrollFactor = 0;
565fe6060f1SDimitry Andric   if (A.getNumArgs() == 1) {
5660b57cec5SDimitry Andric     Expr *E = A.getArgAsExpr(0);
567bdd1243dSDimitry Andric     std::optional<llvm::APSInt> ArgVal;
5680b57cec5SDimitry Andric 
569e8d8bef9SDimitry Andric     if (!(ArgVal = E->getIntegerConstantExpr(S.Context))) {
5700b57cec5SDimitry Andric       S.Diag(A.getLoc(), diag::err_attribute_argument_type)
5710b57cec5SDimitry Andric           << A << AANT_ArgumentIntegerConstant << E->getSourceRange();
5720b57cec5SDimitry Andric       return nullptr;
5730b57cec5SDimitry Andric     }
5740b57cec5SDimitry Andric 
575e8d8bef9SDimitry Andric     int Val = ArgVal->getSExtValue();
5760b57cec5SDimitry Andric     if (Val <= 0) {
5770b57cec5SDimitry Andric       S.Diag(A.getRange().getBegin(),
5780b57cec5SDimitry Andric              diag::err_attribute_requires_positive_integer)
5790b57cec5SDimitry Andric           << A << /* positive */ 0;
5800b57cec5SDimitry Andric       return nullptr;
5810b57cec5SDimitry Andric     }
582fe6060f1SDimitry Andric     UnrollFactor = static_cast<unsigned>(Val);
5830b57cec5SDimitry Andric   }
5840b57cec5SDimitry Andric 
585fe6060f1SDimitry Andric   return ::new (S.Context) OpenCLUnrollHintAttr(S.Context, A, UnrollFactor);
5860b57cec5SDimitry Andric }
5870b57cec5SDimitry Andric 
588*0fca6ea1SDimitry Andric static Attr *handleHLSLLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
589*0fca6ea1SDimitry Andric                                     SourceRange Range) {
590*0fca6ea1SDimitry Andric 
591*0fca6ea1SDimitry Andric   if (A.getSemanticSpelling() == HLSLLoopHintAttr::Spelling::Microsoft_loop &&
592*0fca6ea1SDimitry Andric       !A.checkAtMostNumArgs(S, 0))
593*0fca6ea1SDimitry Andric     return nullptr;
594*0fca6ea1SDimitry Andric 
595*0fca6ea1SDimitry Andric   unsigned UnrollFactor = 0;
596*0fca6ea1SDimitry Andric   if (A.getNumArgs() == 1) {
597*0fca6ea1SDimitry Andric 
598*0fca6ea1SDimitry Andric     if (A.isArgIdent(0)) {
599*0fca6ea1SDimitry Andric       S.Diag(A.getLoc(), diag::err_attribute_argument_type)
600*0fca6ea1SDimitry Andric           << A << AANT_ArgumentIntegerConstant << A.getRange();
601*0fca6ea1SDimitry Andric       return nullptr;
602*0fca6ea1SDimitry Andric     }
603*0fca6ea1SDimitry Andric 
604*0fca6ea1SDimitry Andric     Expr *E = A.getArgAsExpr(0);
605*0fca6ea1SDimitry Andric 
606*0fca6ea1SDimitry Andric     if (S.CheckLoopHintExpr(E, St->getBeginLoc(),
607*0fca6ea1SDimitry Andric                             /*AllowZero=*/false))
608*0fca6ea1SDimitry Andric       return nullptr;
609*0fca6ea1SDimitry Andric 
610*0fca6ea1SDimitry Andric     std::optional<llvm::APSInt> ArgVal = E->getIntegerConstantExpr(S.Context);
611*0fca6ea1SDimitry Andric     // CheckLoopHintExpr handles non int const cases
612*0fca6ea1SDimitry Andric     assert(ArgVal != std::nullopt && "ArgVal should be an integer constant.");
613*0fca6ea1SDimitry Andric     int Val = ArgVal->getSExtValue();
614*0fca6ea1SDimitry Andric     // CheckLoopHintExpr handles negative and zero cases
615*0fca6ea1SDimitry Andric     assert(Val > 0 && "Val should be a positive integer greater than zero.");
616*0fca6ea1SDimitry Andric     UnrollFactor = static_cast<unsigned>(Val);
617*0fca6ea1SDimitry Andric   }
618*0fca6ea1SDimitry Andric   return ::new (S.Context) HLSLLoopHintAttr(S.Context, A, UnrollFactor);
619*0fca6ea1SDimitry Andric }
620*0fca6ea1SDimitry Andric 
6210b57cec5SDimitry Andric static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
6220b57cec5SDimitry Andric                                   SourceRange Range) {
623fe6060f1SDimitry Andric   if (A.isInvalid() || A.getKind() == ParsedAttr::IgnoredAttribute)
624fe6060f1SDimitry Andric     return nullptr;
625fe6060f1SDimitry Andric 
626fe6060f1SDimitry Andric   // Unknown attributes are automatically warned on. Target-specific attributes
627fe6060f1SDimitry Andric   // which do not apply to the current target architecture are treated as
628fe6060f1SDimitry Andric   // though they were unknown attributes.
629fe6060f1SDimitry Andric   const TargetInfo *Aux = S.Context.getAuxTargetInfo();
630fe6060f1SDimitry Andric   if (A.getKind() == ParsedAttr::UnknownAttribute ||
631fe6060f1SDimitry Andric       !(A.existsInTarget(S.Context.getTargetInfo()) ||
632fe6060f1SDimitry Andric         (S.Context.getLangOpts().SYCLIsDevice && Aux &&
633fe6060f1SDimitry Andric          A.existsInTarget(*Aux)))) {
63406c3fb27SDimitry Andric     S.Diag(A.getLoc(), A.isRegularKeywordAttribute()
63506c3fb27SDimitry Andric                            ? (unsigned)diag::err_keyword_not_supported_on_target
63606c3fb27SDimitry Andric                        : A.isDeclspecAttribute()
6370b57cec5SDimitry Andric                            ? (unsigned)diag::warn_unhandled_ms_attribute_ignored
6380b57cec5SDimitry Andric                            : (unsigned)diag::warn_unknown_attribute_ignored)
639e8d8bef9SDimitry Andric         << A << A.getRange();
6400b57cec5SDimitry Andric     return nullptr;
641fe6060f1SDimitry Andric   }
642fe6060f1SDimitry Andric 
643fe6060f1SDimitry Andric   if (S.checkCommonAttributeFeatures(St, A))
644fe6060f1SDimitry Andric     return nullptr;
645fe6060f1SDimitry Andric 
646fe6060f1SDimitry Andric   switch (A.getKind()) {
64781ad6265SDimitry Andric   case ParsedAttr::AT_AlwaysInline:
64881ad6265SDimitry Andric     return handleAlwaysInlineAttr(S, St, A, Range);
649*0fca6ea1SDimitry Andric   case ParsedAttr::AT_CXXAssume:
650*0fca6ea1SDimitry Andric     return handleCXXAssumeAttr(S, St, A, Range);
6510b57cec5SDimitry Andric   case ParsedAttr::AT_FallThrough:
6520b57cec5SDimitry Andric     return handleFallThroughAttr(S, St, A, Range);
6530b57cec5SDimitry Andric   case ParsedAttr::AT_LoopHint:
6540b57cec5SDimitry Andric     return handleLoopHintAttr(S, St, A, Range);
655*0fca6ea1SDimitry Andric   case ParsedAttr::AT_HLSLLoopHint:
656*0fca6ea1SDimitry Andric     return handleHLSLLoopHintAttr(S, St, A, Range);
6570b57cec5SDimitry Andric   case ParsedAttr::AT_OpenCLUnrollHint:
6580b57cec5SDimitry Andric     return handleOpenCLUnrollHint(S, St, A, Range);
6590b57cec5SDimitry Andric   case ParsedAttr::AT_Suppress:
6600b57cec5SDimitry Andric     return handleSuppressAttr(S, St, A, Range);
6615ffd83dbSDimitry Andric   case ParsedAttr::AT_NoMerge:
6625ffd83dbSDimitry Andric     return handleNoMergeAttr(S, St, A, Range);
66381ad6265SDimitry Andric   case ParsedAttr::AT_NoInline:
66481ad6265SDimitry Andric     return handleNoInlineAttr(S, St, A, Range);
665fe6060f1SDimitry Andric   case ParsedAttr::AT_MustTail:
666fe6060f1SDimitry Andric     return handleMustTailAttr(S, St, A, Range);
667e8d8bef9SDimitry Andric   case ParsedAttr::AT_Likely:
668e8d8bef9SDimitry Andric     return handleLikely(S, St, A, Range);
669e8d8bef9SDimitry Andric   case ParsedAttr::AT_Unlikely:
670e8d8bef9SDimitry Andric     return handleUnlikely(S, St, A, Range);
6715f757f3fSDimitry Andric   case ParsedAttr::AT_CodeAlign:
6725f757f3fSDimitry Andric     return handleCodeAlignAttr(S, St, A);
6735f757f3fSDimitry Andric   case ParsedAttr::AT_MSConstexpr:
6745f757f3fSDimitry Andric     return handleMSConstexprAttr(S, St, A, Range);
6750b57cec5SDimitry Andric   default:
676fe6060f1SDimitry Andric     // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
677fe6060f1SDimitry Andric     // declaration attribute is not written on a statement, but this code is
678fe6060f1SDimitry Andric     // needed for attributes in Attr.td that do not list any subjects.
6790b57cec5SDimitry Andric     S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
68006c3fb27SDimitry Andric         << A << A.isRegularKeywordAttribute() << St->getBeginLoc();
6810b57cec5SDimitry Andric     return nullptr;
6820b57cec5SDimitry Andric   }
6830b57cec5SDimitry Andric }
6840b57cec5SDimitry Andric 
68581ad6265SDimitry Andric void Sema::ProcessStmtAttributes(Stmt *S, const ParsedAttributes &InAttrs,
686fe6060f1SDimitry Andric                                  SmallVectorImpl<const Attr *> &OutAttrs) {
687fe6060f1SDimitry Andric   for (const ParsedAttr &AL : InAttrs) {
688fe6060f1SDimitry Andric     if (const Attr *A = ProcessStmtAttribute(*this, S, AL, InAttrs.Range))
689fe6060f1SDimitry Andric       OutAttrs.push_back(A);
6900b57cec5SDimitry Andric   }
6910b57cec5SDimitry Andric 
692fe6060f1SDimitry Andric   CheckForIncompatibleAttributes(*this, OutAttrs);
6935f757f3fSDimitry Andric   CheckForDuplicateLoopAttrs<CodeAlignAttr>(*this, OutAttrs);
6945f757f3fSDimitry Andric }
6955f757f3fSDimitry Andric 
6965f757f3fSDimitry Andric bool Sema::CheckRebuiltStmtAttributes(ArrayRef<const Attr *> Attrs) {
6975f757f3fSDimitry Andric   CheckForDuplicateLoopAttrs<CodeAlignAttr>(*this, Attrs);
6985f757f3fSDimitry Andric   return false;
6990b57cec5SDimitry Andric }
700*0fca6ea1SDimitry Andric 
701*0fca6ea1SDimitry Andric ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A,
702*0fca6ea1SDimitry Andric                                     SourceRange Range) {
703*0fca6ea1SDimitry Andric   if (A.getNumArgs() != 1 || !A.getArgAsExpr(0)) {
704*0fca6ea1SDimitry Andric     Diag(A.getLoc(), diag::err_attribute_wrong_number_arguments)
705*0fca6ea1SDimitry Andric         << A.getAttrName() << 1 << Range;
706*0fca6ea1SDimitry Andric     return ExprError();
707*0fca6ea1SDimitry Andric   }
708*0fca6ea1SDimitry Andric 
709*0fca6ea1SDimitry Andric   auto *Assumption = A.getArgAsExpr(0);
710*0fca6ea1SDimitry Andric 
711*0fca6ea1SDimitry Andric   if (DiagnoseUnexpandedParameterPack(Assumption)) {
712*0fca6ea1SDimitry Andric     return ExprError();
713*0fca6ea1SDimitry Andric   }
714*0fca6ea1SDimitry Andric 
715*0fca6ea1SDimitry Andric   if (Assumption->getDependence() == ExprDependence::None) {
716*0fca6ea1SDimitry Andric     ExprResult Res = BuildCXXAssumeExpr(Assumption, A.getAttrName(), Range);
717*0fca6ea1SDimitry Andric     if (Res.isInvalid())
718*0fca6ea1SDimitry Andric       return ExprError();
719*0fca6ea1SDimitry Andric     Assumption = Res.get();
720*0fca6ea1SDimitry Andric   }
721*0fca6ea1SDimitry Andric 
722*0fca6ea1SDimitry Andric   if (!getLangOpts().CPlusPlus23 &&
723*0fca6ea1SDimitry Andric       A.getSyntax() == AttributeCommonInfo::AS_CXX11)
724*0fca6ea1SDimitry Andric     Diag(A.getLoc(), diag::ext_cxx23_attr) << A << Range;
725*0fca6ea1SDimitry Andric 
726*0fca6ea1SDimitry Andric   return Assumption;
727*0fca6ea1SDimitry Andric }
728*0fca6ea1SDimitry Andric 
729*0fca6ea1SDimitry Andric ExprResult Sema::BuildCXXAssumeExpr(Expr *Assumption,
730*0fca6ea1SDimitry Andric                                     const IdentifierInfo *AttrName,
731*0fca6ea1SDimitry Andric                                     SourceRange Range) {
732*0fca6ea1SDimitry Andric   ExprResult Res = CorrectDelayedTyposInExpr(Assumption);
733*0fca6ea1SDimitry Andric   if (Res.isInvalid())
734*0fca6ea1SDimitry Andric     return ExprError();
735*0fca6ea1SDimitry Andric 
736*0fca6ea1SDimitry Andric   Res = CheckPlaceholderExpr(Res.get());
737*0fca6ea1SDimitry Andric   if (Res.isInvalid())
738*0fca6ea1SDimitry Andric     return ExprError();
739*0fca6ea1SDimitry Andric 
740*0fca6ea1SDimitry Andric   Res = PerformContextuallyConvertToBool(Res.get());
741*0fca6ea1SDimitry Andric   if (Res.isInvalid())
742*0fca6ea1SDimitry Andric     return ExprError();
743*0fca6ea1SDimitry Andric 
744*0fca6ea1SDimitry Andric   Assumption = Res.get();
745*0fca6ea1SDimitry Andric   if (Assumption->HasSideEffects(Context))
746*0fca6ea1SDimitry Andric     Diag(Assumption->getBeginLoc(), diag::warn_assume_side_effects)
747*0fca6ea1SDimitry Andric         << AttrName << Range;
748*0fca6ea1SDimitry Andric 
749*0fca6ea1SDimitry Andric   return Assumption;
750*0fca6ea1SDimitry Andric }
751