1234973Sdim//===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===// 2234973Sdim// 3234973Sdim// The LLVM Compiler Infrastructure 4234973Sdim// 5234973Sdim// This file is distributed under the University of Illinois Open Source 6234973Sdim// License. See LICENSE.TXT for details. 7234973Sdim// 8234973Sdim//===----------------------------------------------------------------------===// 9234973Sdim// 10234973Sdim// This file implements stmt-related attribute processing. 11234973Sdim// 12234973Sdim//===----------------------------------------------------------------------===// 13234973Sdim 14234973Sdim#include "clang/Sema/SemaInternal.h" 15234973Sdim#include "clang/AST/ASTContext.h" 16234973Sdim#include "clang/Basic/SourceManager.h" 17234973Sdim#include "clang/Sema/DelayedDiagnostic.h" 18234973Sdim#include "clang/Sema/Lookup.h" 19276479Sdim#include "clang/Sema/LoopHint.h" 20239462Sdim#include "clang/Sema/ScopeInfo.h" 21234973Sdim#include "llvm/ADT/StringExtras.h" 22239462Sdim 23234973Sdimusing namespace clang; 24234973Sdimusing namespace sema; 25234973Sdim 26239462Sdimstatic Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, 27239462Sdim SourceRange Range) { 28239462Sdim if (!isa<NullStmt>(St)) { 29239462Sdim S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target) 30239462Sdim << St->getLocStart(); 31239462Sdim if (isa<SwitchCase>(St)) { 32276479Sdim SourceLocation L = S.getLocForEndOfToken(Range.getEnd()); 33239462Sdim S.Diag(L, diag::note_fallthrough_insert_semi_fixit) 34239462Sdim << FixItHint::CreateInsertion(L, ";"); 35239462Sdim } 36276479Sdim return nullptr; 37239462Sdim } 38239462Sdim if (S.getCurFunction()->SwitchStack.empty()) { 39239462Sdim S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch); 40276479Sdim return nullptr; 41239462Sdim } 42276479Sdim return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context, 43276479Sdim A.getAttributeSpellingListIndex()); 44239462Sdim} 45234973Sdim 46276479Sdimstatic Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, 47276479Sdim SourceRange) { 48276479Sdim IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0); 49276479Sdim IdentifierLoc *OptionLoc = A.getArgAsIdent(1); 50280031Sdim IdentifierLoc *StateLoc = A.getArgAsIdent(2); 51276479Sdim Expr *ValueExpr = A.getArgAsExpr(3); 52239462Sdim 53280031Sdim bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll"; 54280031Sdim bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll"; 55276479Sdim if (St->getStmtClass() != Stmt::DoStmtClass && 56276479Sdim St->getStmtClass() != Stmt::ForStmtClass && 57276479Sdim St->getStmtClass() != Stmt::CXXForRangeStmtClass && 58276479Sdim St->getStmtClass() != Stmt::WhileStmtClass) { 59280031Sdim const char *Pragma = 60280031Sdim llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName()) 61280031Sdim .Case("unroll", "#pragma unroll") 62280031Sdim .Case("nounroll", "#pragma nounroll") 63280031Sdim .Default("#pragma clang loop"); 64276479Sdim S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma; 65276479Sdim return nullptr; 66276479Sdim } 67276479Sdim 68296417Sdim LoopHintAttr::Spelling Spelling; 69276479Sdim LoopHintAttr::OptionType Option; 70296417Sdim LoopHintAttr::LoopHintState State; 71296417Sdim if (PragmaNoUnroll) { 72296417Sdim // #pragma nounroll 73296417Sdim Spelling = LoopHintAttr::Pragma_nounroll; 74296417Sdim Option = LoopHintAttr::Unroll; 75296417Sdim State = LoopHintAttr::Disable; 76296417Sdim } else if (PragmaUnroll) { 77276479Sdim Spelling = LoopHintAttr::Pragma_unroll; 78296417Sdim if (ValueExpr) { 79296417Sdim // #pragma unroll N 80296417Sdim Option = LoopHintAttr::UnrollCount; 81296417Sdim State = LoopHintAttr::Numeric; 82296417Sdim } else { 83296417Sdim // #pragma unroll 84296417Sdim Option = LoopHintAttr::Unroll; 85296417Sdim State = LoopHintAttr::Enable; 86296417Sdim } 87276479Sdim } else { 88296417Sdim // #pragma clang loop ... 89296417Sdim Spelling = LoopHintAttr::Pragma_clang_loop; 90280031Sdim assert(OptionLoc && OptionLoc->Ident && 91280031Sdim "Attribute must have valid option info."); 92296417Sdim Option = llvm::StringSwitch<LoopHintAttr::OptionType>( 93296417Sdim OptionLoc->Ident->getName()) 94276479Sdim .Case("vectorize", LoopHintAttr::Vectorize) 95276479Sdim .Case("vectorize_width", LoopHintAttr::VectorizeWidth) 96276479Sdim .Case("interleave", LoopHintAttr::Interleave) 97276479Sdim .Case("interleave_count", LoopHintAttr::InterleaveCount) 98276479Sdim .Case("unroll", LoopHintAttr::Unroll) 99276479Sdim .Case("unroll_count", LoopHintAttr::UnrollCount) 100276479Sdim .Default(LoopHintAttr::Vectorize); 101296417Sdim if (Option == LoopHintAttr::VectorizeWidth || 102296417Sdim Option == LoopHintAttr::InterleaveCount || 103296417Sdim Option == LoopHintAttr::UnrollCount) { 104296417Sdim assert(ValueExpr && "Attribute must have a valid value expression."); 105296417Sdim if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart())) 106296417Sdim return nullptr; 107296417Sdim State = LoopHintAttr::Numeric; 108296417Sdim } else if (Option == LoopHintAttr::Vectorize || 109296417Sdim Option == LoopHintAttr::Interleave || 110296417Sdim Option == LoopHintAttr::Unroll) { 111296417Sdim assert(StateLoc && StateLoc->Ident && "Loop hint must have an argument"); 112280031Sdim if (StateLoc->Ident->isStr("disable")) 113280031Sdim State = LoopHintAttr::Disable; 114288943Sdim else if (StateLoc->Ident->isStr("assume_safety")) 115288943Sdim State = LoopHintAttr::AssumeSafety; 116296417Sdim else if (StateLoc->Ident->isStr("full")) 117296417Sdim State = LoopHintAttr::Full; 118296417Sdim else if (StateLoc->Ident->isStr("enable")) 119296417Sdim State = LoopHintAttr::Enable; 120280031Sdim else 121296417Sdim llvm_unreachable("bad loop hint argument"); 122296417Sdim } else 123296417Sdim llvm_unreachable("bad loop hint"); 124280031Sdim } 125276479Sdim 126280031Sdim return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State, 127280031Sdim ValueExpr, A.getRange()); 128276479Sdim} 129276479Sdim 130280031Sdimstatic void 131280031SdimCheckForIncompatibleAttributes(Sema &S, 132280031Sdim const SmallVectorImpl<const Attr *> &Attrs) { 133280031Sdim // There are 3 categories of loop hints attributes: vectorize, interleave, 134280031Sdim // and unroll. Each comes in two variants: a state form and a numeric form. 135280031Sdim // The state form selectively defaults/enables/disables the transformation 136280031Sdim // for the loop (for unroll, default indicates full unrolling rather than 137280031Sdim // enabling the transformation). The numeric form form provides an integer 138280031Sdim // hint (for example, unroll count) to the transformer. The following array 139280031Sdim // accumulates the hints encountered while iterating through the attributes 140280031Sdim // to check for compatibility. 141276479Sdim struct { 142280031Sdim const LoopHintAttr *StateAttr; 143276479Sdim const LoopHintAttr *NumericAttr; 144276479Sdim } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}; 145276479Sdim 146276479Sdim for (const auto *I : Attrs) { 147276479Sdim const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I); 148276479Sdim 149276479Sdim // Skip non loop hint attributes 150276479Sdim if (!LH) 151276479Sdim continue; 152276479Sdim 153296417Sdim LoopHintAttr::OptionType Option = LH->getOption(); 154296417Sdim enum { Vectorize, Interleave, Unroll } Category; 155276479Sdim switch (Option) { 156276479Sdim case LoopHintAttr::Vectorize: 157276479Sdim case LoopHintAttr::VectorizeWidth: 158280031Sdim Category = Vectorize; 159276479Sdim break; 160276479Sdim case LoopHintAttr::Interleave: 161276479Sdim case LoopHintAttr::InterleaveCount: 162280031Sdim Category = Interleave; 163276479Sdim break; 164276479Sdim case LoopHintAttr::Unroll: 165276479Sdim case LoopHintAttr::UnrollCount: 166280031Sdim Category = Unroll; 167276479Sdim break; 168276479Sdim }; 169276479Sdim 170276479Sdim auto &CategoryState = HintAttrs[Category]; 171276479Sdim const LoopHintAttr *PrevAttr; 172276479Sdim if (Option == LoopHintAttr::Vectorize || 173276479Sdim Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) { 174288943Sdim // Enable|Disable|AssumeSafety hint. For example, vectorize(enable). 175280031Sdim PrevAttr = CategoryState.StateAttr; 176280031Sdim CategoryState.StateAttr = LH; 177276479Sdim } else { 178276479Sdim // Numeric hint. For example, vectorize_width(8). 179276479Sdim PrevAttr = CategoryState.NumericAttr; 180276479Sdim CategoryState.NumericAttr = LH; 181276479Sdim } 182276479Sdim 183280031Sdim PrintingPolicy Policy(S.Context.getLangOpts()); 184280031Sdim SourceLocation OptionLoc = LH->getRange().getBegin(); 185276479Sdim if (PrevAttr) 186276479Sdim // Cannot specify same type of attribute twice. 187276479Sdim S.Diag(OptionLoc, diag::err_pragma_loop_compatibility) 188280031Sdim << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy) 189280031Sdim << LH->getDiagnosticName(Policy); 190276479Sdim 191280031Sdim if (CategoryState.StateAttr && CategoryState.NumericAttr && 192280031Sdim (Category == Unroll || 193280031Sdim CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) { 194280031Sdim // Disable hints are not compatible with numeric hints of the same 195280031Sdim // category. As a special case, numeric unroll hints are also not 196296417Sdim // compatible with enable or full form of the unroll pragma because these 197296417Sdim // directives indicate full unrolling. 198276479Sdim S.Diag(OptionLoc, diag::err_pragma_loop_compatibility) 199276479Sdim << /*Duplicate=*/false 200280031Sdim << CategoryState.StateAttr->getDiagnosticName(Policy) 201280031Sdim << CategoryState.NumericAttr->getDiagnosticName(Policy); 202276479Sdim } 203276479Sdim } 204276479Sdim} 205276479Sdim 206239462Sdimstatic Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, 207239462Sdim SourceRange Range) { 208234973Sdim switch (A.getKind()) { 209243830Sdim case AttributeList::UnknownAttribute: 210243830Sdim S.Diag(A.getLoc(), A.isDeclspecAttribute() ? 211243830Sdim diag::warn_unhandled_ms_attribute_ignored : 212243830Sdim diag::warn_unknown_attribute_ignored) << A.getName(); 213276479Sdim return nullptr; 214239462Sdim case AttributeList::AT_FallThrough: 215239462Sdim return handleFallThroughAttr(S, St, A, Range); 216276479Sdim case AttributeList::AT_LoopHint: 217276479Sdim return handleLoopHintAttr(S, St, A, Range); 218234973Sdim default: 219243830Sdim // if we're here, then we parsed a known attribute, but didn't recognize 220243830Sdim // it as a statement attribute => it is declaration attribute 221249423Sdim S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt) 222249423Sdim << A.getName() << St->getLocStart(); 223276479Sdim return nullptr; 224234973Sdim } 225234973Sdim} 226234973Sdim 227234973SdimStmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList, 228234973Sdim SourceRange Range) { 229239462Sdim SmallVector<const Attr*, 8> Attrs; 230234973Sdim for (const AttributeList* l = AttrList; l; l = l->getNext()) { 231239462Sdim if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range)) 232234973Sdim Attrs.push_back(a); 233234973Sdim } 234234973Sdim 235276479Sdim CheckForIncompatibleAttributes(*this, Attrs); 236276479Sdim 237234973Sdim if (Attrs.empty()) 238234973Sdim return S; 239234973Sdim 240234973Sdim return ActOnAttributedStmt(Range.getBegin(), Attrs, S); 241234973Sdim} 242