1//===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements stmt-related attribute processing. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/Sema/SemaInternal.h" 15#include "clang/AST/ASTContext.h" 16#include "clang/Basic/SourceManager.h" 17#include "clang/Sema/DelayedDiagnostic.h" 18#include "clang/Sema/Lookup.h" 19#include "clang/Sema/LoopHint.h" 20#include "clang/Sema/ScopeInfo.h" 21#include "llvm/ADT/StringExtras.h" 22 23using namespace clang; 24using namespace sema; 25 26static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, 27 SourceRange Range) { 28 if (!isa<NullStmt>(St)) { 29 S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target) 30 << St->getLocStart(); 31 if (isa<SwitchCase>(St)) { 32 SourceLocation L = S.getLocForEndOfToken(Range.getEnd()); 33 S.Diag(L, diag::note_fallthrough_insert_semi_fixit) 34 << FixItHint::CreateInsertion(L, ";"); 35 } 36 return nullptr; 37 } 38 if (S.getCurFunction()->SwitchStack.empty()) { 39 S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch); 40 return nullptr; 41 } 42 return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context, 43 A.getAttributeSpellingListIndex()); 44} 45 46static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, 47 SourceRange) { 48 IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0); 49 IdentifierLoc *OptionLoc = A.getArgAsIdent(1); 50 IdentifierLoc *StateLoc = A.getArgAsIdent(2); 51 Expr *ValueExpr = A.getArgAsExpr(3); 52 53 bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll"; 54 bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll"; 55 if (St->getStmtClass() != Stmt::DoStmtClass && 56 St->getStmtClass() != Stmt::ForStmtClass && 57 St->getStmtClass() != Stmt::CXXForRangeStmtClass && 58 St->getStmtClass() != Stmt::WhileStmtClass) { 59 const char *Pragma = 60 llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName()) 61 .Case("unroll", "#pragma unroll") 62 .Case("nounroll", "#pragma nounroll") 63 .Default("#pragma clang loop"); 64 S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma; 65 return nullptr; 66 } 67 68 LoopHintAttr::OptionType Option; 69 LoopHintAttr::Spelling Spelling; 70 if (PragmaUnroll) { 71 Option = ValueExpr ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll; 72 Spelling = LoopHintAttr::Pragma_unroll; 73 } else if (PragmaNoUnroll) { 74 Option = LoopHintAttr::Unroll; 75 Spelling = LoopHintAttr::Pragma_nounroll; 76 } else { 77 assert(OptionLoc && OptionLoc->Ident && 78 "Attribute must have valid option info."); 79 IdentifierInfo *OptionInfo = OptionLoc->Ident; 80 Option = llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName()) 81 .Case("vectorize", LoopHintAttr::Vectorize) 82 .Case("vectorize_width", LoopHintAttr::VectorizeWidth) 83 .Case("interleave", LoopHintAttr::Interleave) 84 .Case("interleave_count", LoopHintAttr::InterleaveCount) 85 .Case("unroll", LoopHintAttr::Unroll) 86 .Case("unroll_count", LoopHintAttr::UnrollCount) 87 .Default(LoopHintAttr::Vectorize); 88 Spelling = LoopHintAttr::Pragma_clang_loop; 89 } 90 91 LoopHintAttr::LoopHintState State = LoopHintAttr::Default; 92 if (PragmaNoUnroll) { 93 State = LoopHintAttr::Disable; 94 } else if (Option == LoopHintAttr::VectorizeWidth || 95 Option == LoopHintAttr::InterleaveCount || 96 Option == LoopHintAttr::UnrollCount) { 97 assert(ValueExpr && "Attribute must have a valid value expression."); 98 if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart())) 99 return nullptr; 100 } else if (Option == LoopHintAttr::Vectorize || 101 Option == LoopHintAttr::Interleave || 102 Option == LoopHintAttr::Unroll) { 103 // Default state is assumed if StateLoc is not specified, such as with 104 // '#pragma unroll'. 105 if (StateLoc && StateLoc->Ident) { 106 if (StateLoc->Ident->isStr("disable")) 107 State = LoopHintAttr::Disable; 108 else 109 State = LoopHintAttr::Enable; 110 } 111 } 112 113 return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State, 114 ValueExpr, A.getRange()); 115} 116 117static void 118CheckForIncompatibleAttributes(Sema &S, 119 const SmallVectorImpl<const Attr *> &Attrs) { 120 // There are 3 categories of loop hints attributes: vectorize, interleave, 121 // and unroll. Each comes in two variants: a state form and a numeric form. 122 // The state form selectively defaults/enables/disables the transformation 123 // for the loop (for unroll, default indicates full unrolling rather than 124 // enabling the transformation). The numeric form form provides an integer 125 // hint (for example, unroll count) to the transformer. The following array 126 // accumulates the hints encountered while iterating through the attributes 127 // to check for compatibility. 128 struct { 129 const LoopHintAttr *StateAttr; 130 const LoopHintAttr *NumericAttr; 131 } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}; 132 133 for (const auto *I : Attrs) { 134 const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I); 135 136 // Skip non loop hint attributes 137 if (!LH) 138 continue; 139 140 int Option = LH->getOption(); 141 int Category; 142 enum { Vectorize, Interleave, Unroll }; 143 switch (Option) { 144 case LoopHintAttr::Vectorize: 145 case LoopHintAttr::VectorizeWidth: 146 Category = Vectorize; 147 break; 148 case LoopHintAttr::Interleave: 149 case LoopHintAttr::InterleaveCount: 150 Category = Interleave; 151 break; 152 case LoopHintAttr::Unroll: 153 case LoopHintAttr::UnrollCount: 154 Category = Unroll; 155 break; 156 }; 157 158 auto &CategoryState = HintAttrs[Category]; 159 const LoopHintAttr *PrevAttr; 160 if (Option == LoopHintAttr::Vectorize || 161 Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) { 162 // Enable|disable hint. For example, vectorize(enable). 163 PrevAttr = CategoryState.StateAttr; 164 CategoryState.StateAttr = LH; 165 } else { 166 // Numeric hint. For example, vectorize_width(8). 167 PrevAttr = CategoryState.NumericAttr; 168 CategoryState.NumericAttr = LH; 169 } 170 171 PrintingPolicy Policy(S.Context.getLangOpts()); 172 SourceLocation OptionLoc = LH->getRange().getBegin(); 173 if (PrevAttr) 174 // Cannot specify same type of attribute twice. 175 S.Diag(OptionLoc, diag::err_pragma_loop_compatibility) 176 << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy) 177 << LH->getDiagnosticName(Policy); 178 179 if (CategoryState.StateAttr && CategoryState.NumericAttr && 180 (Category == Unroll || 181 CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) { 182 // Disable hints are not compatible with numeric hints of the same 183 // category. As a special case, numeric unroll hints are also not 184 // compatible with "enable" form of the unroll pragma, unroll(full). 185 S.Diag(OptionLoc, diag::err_pragma_loop_compatibility) 186 << /*Duplicate=*/false 187 << CategoryState.StateAttr->getDiagnosticName(Policy) 188 << CategoryState.NumericAttr->getDiagnosticName(Policy); 189 } 190 } 191} 192 193static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, 194 SourceRange Range) { 195 switch (A.getKind()) { 196 case AttributeList::UnknownAttribute: 197 S.Diag(A.getLoc(), A.isDeclspecAttribute() ? 198 diag::warn_unhandled_ms_attribute_ignored : 199 diag::warn_unknown_attribute_ignored) << A.getName(); 200 return nullptr; 201 case AttributeList::AT_FallThrough: 202 return handleFallThroughAttr(S, St, A, Range); 203 case AttributeList::AT_LoopHint: 204 return handleLoopHintAttr(S, St, A, Range); 205 default: 206 // if we're here, then we parsed a known attribute, but didn't recognize 207 // it as a statement attribute => it is declaration attribute 208 S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt) 209 << A.getName() << St->getLocStart(); 210 return nullptr; 211 } 212} 213 214StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList, 215 SourceRange Range) { 216 SmallVector<const Attr*, 8> Attrs; 217 for (const AttributeList* l = AttrList; l; l = l->getNext()) { 218 if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range)) 219 Attrs.push_back(a); 220 } 221 222 CheckForIncompatibleAttributes(*this, Attrs); 223 224 if (Attrs.empty()) 225 return S; 226 227 return ActOnAttributedStmt(Range.getBegin(), Attrs, S); 228} 229