clang API Documentation
00001 //===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements stmt-related attribute processing. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "clang/Sema/SemaInternal.h" 00015 #include "clang/AST/ASTContext.h" 00016 #include "clang/Basic/SourceManager.h" 00017 #include "clang/Sema/DelayedDiagnostic.h" 00018 #include "clang/Sema/Lookup.h" 00019 #include "clang/Sema/LoopHint.h" 00020 #include "clang/Sema/ScopeInfo.h" 00021 #include "llvm/ADT/StringExtras.h" 00022 00023 using namespace clang; 00024 using namespace sema; 00025 00026 static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, 00027 SourceRange Range) { 00028 if (!isa<NullStmt>(St)) { 00029 S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target) 00030 << St->getLocStart(); 00031 if (isa<SwitchCase>(St)) { 00032 SourceLocation L = S.getLocForEndOfToken(Range.getEnd()); 00033 S.Diag(L, diag::note_fallthrough_insert_semi_fixit) 00034 << FixItHint::CreateInsertion(L, ";"); 00035 } 00036 return nullptr; 00037 } 00038 if (S.getCurFunction()->SwitchStack.empty()) { 00039 S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch); 00040 return nullptr; 00041 } 00042 return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context, 00043 A.getAttributeSpellingListIndex()); 00044 } 00045 00046 static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, 00047 SourceRange) { 00048 IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0); 00049 IdentifierLoc *OptionLoc = A.getArgAsIdent(1); 00050 IdentifierLoc *StateLoc = A.getArgAsIdent(2); 00051 Expr *ValueExpr = A.getArgAsExpr(3); 00052 00053 bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll"; 00054 bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll"; 00055 if (St->getStmtClass() != Stmt::DoStmtClass && 00056 St->getStmtClass() != Stmt::ForStmtClass && 00057 St->getStmtClass() != Stmt::CXXForRangeStmtClass && 00058 St->getStmtClass() != Stmt::WhileStmtClass) { 00059 const char *Pragma = 00060 llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName()) 00061 .Case("unroll", "#pragma unroll") 00062 .Case("nounroll", "#pragma nounroll") 00063 .Default("#pragma clang loop"); 00064 S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma; 00065 return nullptr; 00066 } 00067 00068 LoopHintAttr::OptionType Option; 00069 LoopHintAttr::Spelling Spelling; 00070 if (PragmaUnroll) { 00071 Option = ValueExpr ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll; 00072 Spelling = LoopHintAttr::Pragma_unroll; 00073 } else if (PragmaNoUnroll) { 00074 Option = LoopHintAttr::Unroll; 00075 Spelling = LoopHintAttr::Pragma_nounroll; 00076 } else { 00077 assert(OptionLoc && OptionLoc->Ident && 00078 "Attribute must have valid option info."); 00079 IdentifierInfo *OptionInfo = OptionLoc->Ident; 00080 Option = llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName()) 00081 .Case("vectorize", LoopHintAttr::Vectorize) 00082 .Case("vectorize_width", LoopHintAttr::VectorizeWidth) 00083 .Case("interleave", LoopHintAttr::Interleave) 00084 .Case("interleave_count", LoopHintAttr::InterleaveCount) 00085 .Case("unroll", LoopHintAttr::Unroll) 00086 .Case("unroll_count", LoopHintAttr::UnrollCount) 00087 .Default(LoopHintAttr::Vectorize); 00088 Spelling = LoopHintAttr::Pragma_clang_loop; 00089 } 00090 00091 LoopHintAttr::LoopHintState State = LoopHintAttr::Default; 00092 if (PragmaNoUnroll) { 00093 State = LoopHintAttr::Disable; 00094 } else if (Option == LoopHintAttr::VectorizeWidth || 00095 Option == LoopHintAttr::InterleaveCount || 00096 Option == LoopHintAttr::UnrollCount) { 00097 assert(ValueExpr && "Attribute must have a valid value expression."); 00098 if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart())) 00099 return nullptr; 00100 } else if (Option == LoopHintAttr::Vectorize || 00101 Option == LoopHintAttr::Interleave || 00102 Option == LoopHintAttr::Unroll) { 00103 // Default state is assumed if StateLoc is not specified, such as with 00104 // '#pragma unroll'. 00105 if (StateLoc && StateLoc->Ident) { 00106 if (StateLoc->Ident->isStr("disable")) 00107 State = LoopHintAttr::Disable; 00108 else 00109 State = LoopHintAttr::Enable; 00110 } 00111 } 00112 00113 return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State, 00114 ValueExpr, A.getRange()); 00115 } 00116 00117 static void 00118 CheckForIncompatibleAttributes(Sema &S, 00119 const SmallVectorImpl<const Attr *> &Attrs) { 00120 // There are 3 categories of loop hints attributes: vectorize, interleave, 00121 // and unroll. Each comes in two variants: a state form and a numeric form. 00122 // The state form selectively defaults/enables/disables the transformation 00123 // for the loop (for unroll, default indicates full unrolling rather than 00124 // enabling the transformation). The numeric form form provides an integer 00125 // hint (for example, unroll count) to the transformer. The following array 00126 // accumulates the hints encountered while iterating through the attributes 00127 // to check for compatibility. 00128 struct { 00129 const LoopHintAttr *StateAttr; 00130 const LoopHintAttr *NumericAttr; 00131 } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}; 00132 00133 for (const auto *I : Attrs) { 00134 const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I); 00135 00136 // Skip non loop hint attributes 00137 if (!LH) 00138 continue; 00139 00140 int Option = LH->getOption(); 00141 int Category; 00142 enum { Vectorize, Interleave, Unroll }; 00143 switch (Option) { 00144 case LoopHintAttr::Vectorize: 00145 case LoopHintAttr::VectorizeWidth: 00146 Category = Vectorize; 00147 break; 00148 case LoopHintAttr::Interleave: 00149 case LoopHintAttr::InterleaveCount: 00150 Category = Interleave; 00151 break; 00152 case LoopHintAttr::Unroll: 00153 case LoopHintAttr::UnrollCount: 00154 Category = Unroll; 00155 break; 00156 }; 00157 00158 auto &CategoryState = HintAttrs[Category]; 00159 const LoopHintAttr *PrevAttr; 00160 if (Option == LoopHintAttr::Vectorize || 00161 Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) { 00162 // Enable|disable hint. For example, vectorize(enable). 00163 PrevAttr = CategoryState.StateAttr; 00164 CategoryState.StateAttr = LH; 00165 } else { 00166 // Numeric hint. For example, vectorize_width(8). 00167 PrevAttr = CategoryState.NumericAttr; 00168 CategoryState.NumericAttr = LH; 00169 } 00170 00171 PrintingPolicy Policy(S.Context.getLangOpts()); 00172 SourceLocation OptionLoc = LH->getRange().getBegin(); 00173 if (PrevAttr) 00174 // Cannot specify same type of attribute twice. 00175 S.Diag(OptionLoc, diag::err_pragma_loop_compatibility) 00176 << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy) 00177 << LH->getDiagnosticName(Policy); 00178 00179 if (CategoryState.StateAttr && CategoryState.NumericAttr && 00180 (Category == Unroll || 00181 CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) { 00182 // Disable hints are not compatible with numeric hints of the same 00183 // category. As a special case, numeric unroll hints are also not 00184 // compatible with "enable" form of the unroll pragma, unroll(full). 00185 S.Diag(OptionLoc, diag::err_pragma_loop_compatibility) 00186 << /*Duplicate=*/false 00187 << CategoryState.StateAttr->getDiagnosticName(Policy) 00188 << CategoryState.NumericAttr->getDiagnosticName(Policy); 00189 } 00190 } 00191 } 00192 00193 static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, 00194 SourceRange Range) { 00195 switch (A.getKind()) { 00196 case AttributeList::UnknownAttribute: 00197 S.Diag(A.getLoc(), A.isDeclspecAttribute() ? 00198 diag::warn_unhandled_ms_attribute_ignored : 00199 diag::warn_unknown_attribute_ignored) << A.getName(); 00200 return nullptr; 00201 case AttributeList::AT_FallThrough: 00202 return handleFallThroughAttr(S, St, A, Range); 00203 case AttributeList::AT_LoopHint: 00204 return handleLoopHintAttr(S, St, A, Range); 00205 default: 00206 // if we're here, then we parsed a known attribute, but didn't recognize 00207 // it as a statement attribute => it is declaration attribute 00208 S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt) 00209 << A.getName() << St->getLocStart(); 00210 return nullptr; 00211 } 00212 } 00213 00214 StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList, 00215 SourceRange Range) { 00216 SmallVector<const Attr*, 8> Attrs; 00217 for (const AttributeList* l = AttrList; l; l = l->getNext()) { 00218 if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range)) 00219 Attrs.push_back(a); 00220 } 00221 00222 CheckForIncompatibleAttributes(*this, Attrs); 00223 00224 if (Attrs.empty()) 00225 return S; 00226 00227 return ActOnAttributedStmt(Range.getBegin(), Attrs, S); 00228 }