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 23 using namespace clang; 24 using namespace sema; 25 26 static 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 46 static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, 47 SourceRange) { 48 if (St->getStmtClass() != Stmt::DoStmtClass && 49 St->getStmtClass() != Stmt::ForStmtClass && 50 St->getStmtClass() != Stmt::CXXForRangeStmtClass && 51 St->getStmtClass() != Stmt::WhileStmtClass) { 52 S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop); 53 return nullptr; 54 } 55 56 IdentifierLoc *OptionLoc = A.getArgAsIdent(0); 57 IdentifierInfo *OptionInfo = OptionLoc->Ident; 58 IdentifierLoc *ValueLoc = A.getArgAsIdent(1); 59 IdentifierInfo *ValueInfo = ValueLoc->Ident; 60 Expr *ValueExpr = A.getArgAsExpr(2); 61 62 assert(OptionInfo && "Attribute must have valid option info."); 63 64 LoopHintAttr::OptionType Option = 65 llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName()) 66 .Case("vectorize", LoopHintAttr::Vectorize) 67 .Case("vectorize_width", LoopHintAttr::VectorizeWidth) 68 .Case("interleave", LoopHintAttr::Interleave) 69 .Case("interleave_count", LoopHintAttr::InterleaveCount) 70 .Case("unroll", LoopHintAttr::Unroll) 71 .Case("unroll_count", LoopHintAttr::UnrollCount) 72 .Default(LoopHintAttr::Vectorize); 73 74 int ValueInt; 75 if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave || 76 Option == LoopHintAttr::Unroll) { 77 if (!ValueInfo) { 78 S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword); 79 return nullptr; 80 } 81 if (ValueInfo->isStr("disable")) 82 ValueInt = 0; 83 else if (ValueInfo->isStr("enable")) 84 ValueInt = 1; 85 else { 86 S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword); 87 return nullptr; 88 } 89 } else if (Option == LoopHintAttr::VectorizeWidth || 90 Option == LoopHintAttr::InterleaveCount || 91 Option == LoopHintAttr::UnrollCount) { 92 // FIXME: We should support template parameters for the loop hint value. 93 // See bug report #19610. 94 llvm::APSInt ValueAPS; 95 if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context) || 96 (ValueInt = ValueAPS.getSExtValue()) < 1) { 97 S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value); 98 return nullptr; 99 } 100 } else 101 llvm_unreachable("Unknown loop hint option"); 102 103 return LoopHintAttr::CreateImplicit(S.Context, Option, ValueInt, 104 A.getRange()); 105 } 106 107 static void 108 CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl<const Attr *> &Attrs) { 109 // There are 3 categories of loop hints: vectorize, interleave, and 110 // unroll. Each comes in two variants: an enable/disable form and a 111 // form which takes a numeric argument. For example: 112 // unroll(enable|disable) and unroll_count(N). The following array 113 // accumulate the hints encountered while iterating through the 114 // attributes to check for compatibility. 115 struct { 116 int EnableOptionId; 117 int NumericOptionId; 118 bool EnabledIsSet; 119 bool ValueIsSet; 120 bool Enabled; 121 int Value; 122 } Options[] = {{LoopHintAttr::Vectorize, LoopHintAttr::VectorizeWidth, false, 123 false, false, 0}, 124 {LoopHintAttr::Interleave, LoopHintAttr::InterleaveCount, 125 false, false, false, 0}, 126 {LoopHintAttr::Unroll, LoopHintAttr::UnrollCount, false, false, 127 false, 0}}; 128 129 for (const auto *I : Attrs) { 130 const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I); 131 132 // Skip non loop hint attributes 133 if (!LH) 134 continue; 135 136 int Option = LH->getOption(); 137 int ValueInt = LH->getValue(); 138 139 int Category; 140 switch (Option) { 141 case LoopHintAttr::Vectorize: 142 case LoopHintAttr::VectorizeWidth: 143 Category = 0; 144 break; 145 case LoopHintAttr::Interleave: 146 case LoopHintAttr::InterleaveCount: 147 Category = 1; 148 break; 149 case LoopHintAttr::Unroll: 150 case LoopHintAttr::UnrollCount: 151 Category = 2; 152 break; 153 }; 154 155 auto &CategoryState = Options[Category]; 156 SourceLocation ValueLoc = LH->getRange().getEnd(); 157 if (Option == LoopHintAttr::Vectorize || 158 Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) { 159 // Enable|disable hint. For example, vectorize(enable). 160 if (CategoryState.EnabledIsSet) { 161 // Cannot specify enable/disable state twice. 162 S.Diag(ValueLoc, diag::err_pragma_loop_compatibility) 163 << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option) 164 << LoopHintAttr::getValueName(CategoryState.Enabled) 165 << LoopHintAttr::getOptionName(Option) 166 << LoopHintAttr::getValueName(ValueInt); 167 } 168 CategoryState.EnabledIsSet = true; 169 CategoryState.Enabled = ValueInt; 170 } else { 171 // Numeric hint. For example, unroll_count(8). 172 if (CategoryState.ValueIsSet) { 173 // Cannot specify numeric hint twice. 174 S.Diag(ValueLoc, diag::err_pragma_loop_compatibility) 175 << /*Duplicate=*/true << LoopHintAttr::getOptionName(Option) 176 << CategoryState.Value << LoopHintAttr::getOptionName(Option) 177 << ValueInt; 178 } 179 CategoryState.ValueIsSet = true; 180 CategoryState.Value = ValueInt; 181 } 182 183 if (CategoryState.EnabledIsSet && !CategoryState.Enabled && 184 CategoryState.ValueIsSet) { 185 // Disable hints are not compatible with numeric hints of the 186 // same category. 187 S.Diag(ValueLoc, diag::err_pragma_loop_compatibility) 188 << /*Duplicate=*/false 189 << LoopHintAttr::getOptionName(CategoryState.EnableOptionId) 190 << LoopHintAttr::getValueName(CategoryState.Enabled) 191 << LoopHintAttr::getOptionName(CategoryState.NumericOptionId) 192 << CategoryState.Value; 193 } 194 } 195 } 196 197 static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, 198 SourceRange Range) { 199 switch (A.getKind()) { 200 case AttributeList::UnknownAttribute: 201 S.Diag(A.getLoc(), A.isDeclspecAttribute() ? 202 diag::warn_unhandled_ms_attribute_ignored : 203 diag::warn_unknown_attribute_ignored) << A.getName(); 204 return nullptr; 205 case AttributeList::AT_FallThrough: 206 return handleFallThroughAttr(S, St, A, Range); 207 case AttributeList::AT_LoopHint: 208 return handleLoopHintAttr(S, St, A, Range); 209 default: 210 // if we're here, then we parsed a known attribute, but didn't recognize 211 // it as a statement attribute => it is declaration attribute 212 S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt) 213 << A.getName() << St->getLocStart(); 214 return nullptr; 215 } 216 } 217 218 StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList, 219 SourceRange Range) { 220 SmallVector<const Attr*, 8> Attrs; 221 for (const AttributeList* l = AttrList; l; l = l->getNext()) { 222 if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range)) 223 Attrs.push_back(a); 224 } 225 226 CheckForIncompatibleAttributes(*this, Attrs); 227 228 if (Attrs.empty()) 229 return S; 230 231 return ActOnAttributedStmt(Range.getBegin(), Attrs, S); 232 } 233