File: | tools/clang/lib/Sema/SemaStmtAttr.cpp |
Location: | line 171, column 27 |
Description: | Array subscript is undefined |
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 | 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::Spelling Spelling; | |||
69 | LoopHintAttr::OptionType Option; | |||
70 | LoopHintAttr::LoopHintState State; | |||
71 | if (PragmaNoUnroll) { | |||
72 | // #pragma nounroll | |||
73 | Spelling = LoopHintAttr::Pragma_nounroll; | |||
74 | Option = LoopHintAttr::Unroll; | |||
75 | State = LoopHintAttr::Disable; | |||
76 | } else if (PragmaUnroll) { | |||
77 | Spelling = LoopHintAttr::Pragma_unroll; | |||
78 | if (ValueExpr) { | |||
79 | // #pragma unroll N | |||
80 | Option = LoopHintAttr::UnrollCount; | |||
81 | State = LoopHintAttr::Numeric; | |||
82 | } else { | |||
83 | // #pragma unroll | |||
84 | Option = LoopHintAttr::Unroll; | |||
85 | State = LoopHintAttr::Enable; | |||
86 | } | |||
87 | } else { | |||
88 | // #pragma clang loop ... | |||
89 | Spelling = LoopHintAttr::Pragma_clang_loop; | |||
90 | assert(OptionLoc && OptionLoc->Ident &&((OptionLoc && OptionLoc->Ident && "Attribute must have valid option info." ) ? static_cast<void> (0) : __assert_fail ("OptionLoc && OptionLoc->Ident && \"Attribute must have valid option info.\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn255820/tools/clang/lib/Sema/SemaStmtAttr.cpp" , 91, __PRETTY_FUNCTION__)) | |||
91 | "Attribute must have valid option info.")((OptionLoc && OptionLoc->Ident && "Attribute must have valid option info." ) ? static_cast<void> (0) : __assert_fail ("OptionLoc && OptionLoc->Ident && \"Attribute must have valid option info.\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn255820/tools/clang/lib/Sema/SemaStmtAttr.cpp" , 91, __PRETTY_FUNCTION__)); | |||
92 | Option = llvm::StringSwitch<LoopHintAttr::OptionType>( | |||
93 | OptionLoc->Ident->getName()) | |||
94 | .Case("vectorize", LoopHintAttr::Vectorize) | |||
95 | .Case("vectorize_width", LoopHintAttr::VectorizeWidth) | |||
96 | .Case("interleave", LoopHintAttr::Interleave) | |||
97 | .Case("interleave_count", LoopHintAttr::InterleaveCount) | |||
98 | .Case("unroll", LoopHintAttr::Unroll) | |||
99 | .Case("unroll_count", LoopHintAttr::UnrollCount) | |||
100 | .Default(LoopHintAttr::Vectorize); | |||
101 | if (Option == LoopHintAttr::VectorizeWidth || | |||
102 | Option == LoopHintAttr::InterleaveCount || | |||
103 | Option == LoopHintAttr::UnrollCount) { | |||
104 | assert(ValueExpr && "Attribute must have a valid value expression.")((ValueExpr && "Attribute must have a valid value expression." ) ? static_cast<void> (0) : __assert_fail ("ValueExpr && \"Attribute must have a valid value expression.\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn255820/tools/clang/lib/Sema/SemaStmtAttr.cpp" , 104, __PRETTY_FUNCTION__)); | |||
105 | if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart())) | |||
106 | return nullptr; | |||
107 | State = LoopHintAttr::Numeric; | |||
108 | } else if (Option == LoopHintAttr::Vectorize || | |||
109 | Option == LoopHintAttr::Interleave || | |||
110 | Option == LoopHintAttr::Unroll) { | |||
111 | assert(StateLoc && StateLoc->Ident && "Loop hint must have an argument")((StateLoc && StateLoc->Ident && "Loop hint must have an argument" ) ? static_cast<void> (0) : __assert_fail ("StateLoc && StateLoc->Ident && \"Loop hint must have an argument\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn255820/tools/clang/lib/Sema/SemaStmtAttr.cpp" , 111, __PRETTY_FUNCTION__)); | |||
112 | if (StateLoc->Ident->isStr("disable")) | |||
113 | State = LoopHintAttr::Disable; | |||
114 | else if (StateLoc->Ident->isStr("assume_safety")) | |||
115 | State = LoopHintAttr::AssumeSafety; | |||
116 | else if (StateLoc->Ident->isStr("full")) | |||
117 | State = LoopHintAttr::Full; | |||
118 | else if (StateLoc->Ident->isStr("enable")) | |||
119 | State = LoopHintAttr::Enable; | |||
120 | else | |||
121 | llvm_unreachable("bad loop hint argument")::llvm::llvm_unreachable_internal("bad loop hint argument", "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn255820/tools/clang/lib/Sema/SemaStmtAttr.cpp" , 121); | |||
122 | } else | |||
123 | llvm_unreachable("bad loop hint")::llvm::llvm_unreachable_internal("bad loop hint", "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn255820/tools/clang/lib/Sema/SemaStmtAttr.cpp" , 123); | |||
124 | } | |||
125 | ||||
126 | return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State, | |||
127 | ValueExpr, A.getRange()); | |||
128 | } | |||
129 | ||||
130 | static void | |||
131 | CheckForIncompatibleAttributes(Sema &S, | |||
132 | const SmallVectorImpl<const Attr *> &Attrs) { | |||
133 | // There are 3 categories of loop hints attributes: vectorize, interleave, | |||
134 | // and unroll. Each comes in two variants: a state form and a numeric form. | |||
135 | // The state form selectively defaults/enables/disables the transformation | |||
136 | // for the loop (for unroll, default indicates full unrolling rather than | |||
137 | // enabling the transformation). The numeric form form provides an integer | |||
138 | // hint (for example, unroll count) to the transformer. The following array | |||
139 | // accumulates the hints encountered while iterating through the attributes | |||
140 | // to check for compatibility. | |||
141 | struct { | |||
142 | const LoopHintAttr *StateAttr; | |||
143 | const LoopHintAttr *NumericAttr; | |||
144 | } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}; | |||
145 | ||||
146 | for (const auto *I : Attrs) { | |||
147 | const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I); | |||
148 | ||||
149 | // Skip non loop hint attributes | |||
150 | if (!LH) | |||
151 | continue; | |||
152 | ||||
153 | int Option = LH->getOption(); | |||
154 | int Category; | |||
155 | enum { Vectorize, Interleave, Unroll }; | |||
156 | switch (Option) { | |||
157 | case LoopHintAttr::Vectorize: | |||
158 | case LoopHintAttr::VectorizeWidth: | |||
159 | Category = Vectorize; | |||
160 | break; | |||
161 | case LoopHintAttr::Interleave: | |||
162 | case LoopHintAttr::InterleaveCount: | |||
163 | Category = Interleave; | |||
164 | break; | |||
165 | case LoopHintAttr::Unroll: | |||
166 | case LoopHintAttr::UnrollCount: | |||
167 | Category = Unroll; | |||
168 | break; | |||
169 | }; | |||
170 | ||||
171 | auto &CategoryState = HintAttrs[Category]; | |||
| ||||
172 | const LoopHintAttr *PrevAttr; | |||
173 | if (Option == LoopHintAttr::Vectorize || | |||
174 | Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) { | |||
175 | // Enable|Disable|AssumeSafety hint. For example, vectorize(enable). | |||
176 | PrevAttr = CategoryState.StateAttr; | |||
177 | CategoryState.StateAttr = LH; | |||
178 | } else { | |||
179 | // Numeric hint. For example, vectorize_width(8). | |||
180 | PrevAttr = CategoryState.NumericAttr; | |||
181 | CategoryState.NumericAttr = LH; | |||
182 | } | |||
183 | ||||
184 | PrintingPolicy Policy(S.Context.getLangOpts()); | |||
185 | SourceLocation OptionLoc = LH->getRange().getBegin(); | |||
186 | if (PrevAttr) | |||
187 | // Cannot specify same type of attribute twice. | |||
188 | S.Diag(OptionLoc, diag::err_pragma_loop_compatibility) | |||
189 | << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy) | |||
190 | << LH->getDiagnosticName(Policy); | |||
191 | ||||
192 | if (CategoryState.StateAttr && CategoryState.NumericAttr && | |||
193 | (Category == Unroll || | |||
194 | CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) { | |||
195 | // Disable hints are not compatible with numeric hints of the same | |||
196 | // category. As a special case, numeric unroll hints are also not | |||
197 | // compatible with enable or full form of the unroll pragma because these | |||
198 | // directives indicate full unrolling. | |||
199 | S.Diag(OptionLoc, diag::err_pragma_loop_compatibility) | |||
200 | << /*Duplicate=*/false | |||
201 | << CategoryState.StateAttr->getDiagnosticName(Policy) | |||
202 | << CategoryState.NumericAttr->getDiagnosticName(Policy); | |||
203 | } | |||
204 | } | |||
205 | } | |||
206 | ||||
207 | static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, | |||
208 | SourceRange Range) { | |||
209 | switch (A.getKind()) { | |||
210 | case AttributeList::UnknownAttribute: | |||
211 | S.Diag(A.getLoc(), A.isDeclspecAttribute() ? | |||
212 | diag::warn_unhandled_ms_attribute_ignored : | |||
213 | diag::warn_unknown_attribute_ignored) << A.getName(); | |||
214 | return nullptr; | |||
215 | case AttributeList::AT_FallThrough: | |||
216 | return handleFallThroughAttr(S, St, A, Range); | |||
217 | case AttributeList::AT_LoopHint: | |||
218 | return handleLoopHintAttr(S, St, A, Range); | |||
219 | default: | |||
220 | // if we're here, then we parsed a known attribute, but didn't recognize | |||
221 | // it as a statement attribute => it is declaration attribute | |||
222 | S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt) | |||
223 | << A.getName() << St->getLocStart(); | |||
224 | return nullptr; | |||
225 | } | |||
226 | } | |||
227 | ||||
228 | StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList, | |||
229 | SourceRange Range) { | |||
230 | SmallVector<const Attr*, 8> Attrs; | |||
231 | for (const AttributeList* l = AttrList; l; l = l->getNext()) { | |||
| ||||
232 | if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range)) | |||
233 | Attrs.push_back(a); | |||
234 | } | |||
235 | ||||
236 | CheckForIncompatibleAttributes(*this, Attrs); | |||
237 | ||||
238 | if (Attrs.empty()) | |||
239 | return S; | |||
240 | ||||
241 | return ActOnAttributedStmt(Range.getBegin(), Attrs, S); | |||
242 | } |