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