1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #include "clang/Sema/SemaInternal.h" |
15 | #include "clang/AST/DeclCXX.h" |
16 | #include "clang/AST/Expr.h" |
17 | #include "clang/AST/ExprCXX.h" |
18 | #include "clang/AST/StmtCXX.h" |
19 | #include "clang/AST/StmtObjC.h" |
20 | #include "llvm/ADT/BitVector.h" |
21 | using namespace clang; |
22 | |
23 | namespace { |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | class JumpScopeChecker { |
32 | Sema &S; |
33 | |
34 | |
35 | |
36 | const bool Permissive; |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | struct GotoScope { |
44 | |
45 | |
46 | unsigned ParentScope; |
47 | |
48 | |
49 | unsigned InDiag; |
50 | |
51 | |
52 | |
53 | |
54 | unsigned OutDiag; |
55 | |
56 | |
57 | SourceLocation Loc; |
58 | |
59 | GotoScope(unsigned parentScope, unsigned InDiag, unsigned OutDiag, |
60 | SourceLocation L) |
61 | : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {} |
62 | }; |
63 | |
64 | SmallVector<GotoScope, 48> Scopes; |
65 | llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes; |
66 | SmallVector<Stmt*, 16> Jumps; |
67 | |
68 | SmallVector<IndirectGotoStmt*, 4> IndirectJumps; |
69 | SmallVector<LabelDecl*, 4> IndirectJumpTargets; |
70 | public: |
71 | JumpScopeChecker(Stmt *Body, Sema &S); |
72 | private: |
73 | void BuildScopeInformation(Decl *D, unsigned &ParentScope); |
74 | void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl, |
75 | unsigned &ParentScope); |
76 | void BuildScopeInformation(Stmt *S, unsigned &origParentScope); |
77 | |
78 | void VerifyJumps(); |
79 | void VerifyIndirectJumps(); |
80 | void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes); |
81 | void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope, |
82 | LabelDecl *Target, unsigned TargetScope); |
83 | void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, |
84 | unsigned JumpDiag, unsigned JumpDiagWarning, |
85 | unsigned JumpDiagCXX98Compat); |
86 | void CheckGotoStmt(GotoStmt *GS); |
87 | |
88 | unsigned GetDeepestCommonScope(unsigned A, unsigned B); |
89 | }; |
90 | } |
91 | |
92 | #define CHECK_PERMISSIVE(x) (assert(Permissive || !(x)), (Permissive && (x))) |
93 | |
94 | JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) |
95 | : S(s), Permissive(s.hasAnyUnrecoverableErrorsInThisFunction()) { |
96 | |
97 | Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation())); |
98 | |
99 | |
100 | |
101 | unsigned BodyParentScope = 0; |
102 | BuildScopeInformation(Body, BodyParentScope); |
103 | |
104 | |
105 | VerifyJumps(); |
106 | VerifyIndirectJumps(); |
107 | } |
108 | |
109 | |
110 | |
111 | unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) { |
112 | while (A != B) { |
113 | |
114 | |
115 | if (A < B) { |
116 | assert(Scopes[B].ParentScope < B); |
117 | B = Scopes[B].ParentScope; |
118 | } else { |
119 | assert(Scopes[A].ParentScope < A); |
120 | A = Scopes[A].ParentScope; |
121 | } |
122 | } |
123 | return A; |
124 | } |
125 | |
126 | typedef std::pair<unsigned,unsigned> ScopePair; |
127 | |
128 | |
129 | |
130 | static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D) { |
131 | if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { |
132 | unsigned InDiag = 0; |
133 | unsigned OutDiag = 0; |
134 | |
135 | if (VD->getType()->isVariablyModifiedType()) |
136 | InDiag = diag::note_protected_by_vla; |
137 | |
138 | if (VD->hasAttr<BlocksAttr>()) |
139 | return ScopePair(diag::note_protected_by___block, |
140 | diag::note_exits___block); |
141 | |
142 | if (VD->hasAttr<CleanupAttr>()) |
143 | return ScopePair(diag::note_protected_by_cleanup, |
144 | diag::note_exits_cleanup); |
145 | |
146 | if (VD->hasLocalStorage()) { |
147 | switch (VD->getType().isDestructedType()) { |
148 | case QualType::DK_objc_strong_lifetime: |
149 | return ScopePair(diag::note_protected_by_objc_strong_init, |
150 | diag::note_exits_objc_strong); |
151 | |
152 | case QualType::DK_objc_weak_lifetime: |
153 | return ScopePair(diag::note_protected_by_objc_weak_init, |
154 | diag::note_exits_objc_weak); |
155 | |
156 | case QualType::DK_nontrivial_c_struct: |
157 | return ScopePair(diag::note_protected_by_non_trivial_c_struct_init, |
158 | diag::note_exits_dtor); |
159 | |
160 | case QualType::DK_cxx_destructor: |
161 | OutDiag = diag::note_exits_dtor; |
162 | break; |
163 | |
164 | case QualType::DK_none: |
165 | break; |
166 | } |
167 | } |
168 | |
169 | const Expr *Init = VD->getInit(); |
170 | if (S.Context.getLangOpts().CPlusPlus && VD->hasLocalStorage() && Init) { |
171 | |
172 | |
173 | |
174 | |
175 | |
176 | |
177 | |
178 | |
179 | |
180 | |
181 | |
182 | |
183 | |
184 | |
185 | InDiag = diag::note_protected_by_variable_init; |
186 | |
187 | |
188 | |
189 | |
190 | if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) { |
191 | const CXXConstructorDecl *Ctor = CCE->getConstructor(); |
192 | if (Ctor->isTrivial() && Ctor->isDefaultConstructor() && |
193 | VD->getInitStyle() == VarDecl::CallInit) { |
194 | if (OutDiag) |
195 | InDiag = diag::note_protected_by_variable_nontriv_destructor; |
196 | else if (!Ctor->getParent()->isPOD()) |
197 | InDiag = diag::note_protected_by_variable_non_pod; |
198 | else |
199 | InDiag = 0; |
200 | } |
201 | } |
202 | } |
203 | |
204 | return ScopePair(InDiag, OutDiag); |
205 | } |
206 | |
207 | if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { |
208 | if (TD->getUnderlyingType()->isVariablyModifiedType()) |
209 | return ScopePair(isa<TypedefDecl>(TD) |
210 | ? diag::note_protected_by_vla_typedef |
211 | : diag::note_protected_by_vla_type_alias, |
212 | 0); |
213 | } |
214 | |
215 | return ScopePair(0U, 0U); |
216 | } |
217 | |
218 | |
219 | void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) { |
220 | |
221 | std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S, D); |
222 | if (Diags.first || Diags.second) { |
223 | Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second, |
224 | D->getLocation())); |
225 | ParentScope = Scopes.size()-1; |
226 | } |
227 | |
228 | |
229 | |
230 | if (VarDecl *VD = dyn_cast<VarDecl>(D)) |
231 | if (Expr *Init = VD->getInit()) |
232 | BuildScopeInformation(Init, ParentScope); |
233 | } |
234 | |
235 | |
236 | void JumpScopeChecker::BuildScopeInformation(VarDecl *D, |
237 | const BlockDecl *BDecl, |
238 | unsigned &ParentScope) { |
239 | |
240 | |
241 | if (D->hasAttr<BlocksAttr>()) |
242 | return; |
243 | QualType T = D->getType(); |
244 | QualType::DestructionKind destructKind = T.isDestructedType(); |
245 | if (destructKind != QualType::DK_none) { |
246 | std::pair<unsigned,unsigned> Diags; |
247 | switch (destructKind) { |
248 | case QualType::DK_cxx_destructor: |
249 | Diags = ScopePair(diag::note_enters_block_captures_cxx_obj, |
250 | diag::note_exits_block_captures_cxx_obj); |
251 | break; |
252 | case QualType::DK_objc_strong_lifetime: |
253 | Diags = ScopePair(diag::note_enters_block_captures_strong, |
254 | diag::note_exits_block_captures_strong); |
255 | break; |
256 | case QualType::DK_objc_weak_lifetime: |
257 | Diags = ScopePair(diag::note_enters_block_captures_weak, |
258 | diag::note_exits_block_captures_weak); |
259 | break; |
260 | case QualType::DK_nontrivial_c_struct: |
261 | Diags = ScopePair(diag::note_enters_block_captures_non_trivial_c_struct, |
262 | diag::note_exits_block_captures_non_trivial_c_struct); |
263 | break; |
264 | case QualType::DK_none: |
265 | llvm_unreachable("non-lifetime captured variable"); |
266 | } |
267 | SourceLocation Loc = D->getLocation(); |
268 | if (Loc.isInvalid()) |
269 | Loc = BDecl->getLocation(); |
270 | Scopes.push_back(GotoScope(ParentScope, |
271 | Diags.first, Diags.second, Loc)); |
272 | ParentScope = Scopes.size()-1; |
273 | } |
274 | } |
275 | |
276 | |
277 | |
278 | |
279 | |
280 | void JumpScopeChecker::BuildScopeInformation(Stmt *S, |
281 | unsigned &origParentScope) { |
282 | |
283 | |
284 | |
285 | unsigned independentParentScope = origParentScope; |
286 | unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S)) |
287 | ? origParentScope : independentParentScope); |
288 | |
289 | unsigned StmtsToSkip = 0u; |
290 | |
291 | |
292 | switch (S->getStmtClass()) { |
293 | case Stmt::AddrLabelExprClass: |
294 | IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel()); |
295 | break; |
296 | |
297 | case Stmt::ObjCForCollectionStmtClass: { |
298 | auto *CS = cast<ObjCForCollectionStmt>(S); |
299 | unsigned Diag = diag::note_protected_by_objc_fast_enumeration; |
300 | unsigned NewParentScope = Scopes.size(); |
301 | Scopes.push_back(GotoScope(ParentScope, Diag, 0, S->getBeginLoc())); |
302 | BuildScopeInformation(CS->getBody(), NewParentScope); |
303 | return; |
304 | } |
305 | |
306 | case Stmt::IndirectGotoStmtClass: |
307 | |
308 | |
309 | |
310 | |
311 | |
312 | if (cast<IndirectGotoStmt>(S)->getConstantTarget()) { |
313 | LabelAndGotoScopes[S] = ParentScope; |
314 | Jumps.push_back(S); |
315 | return; |
316 | } |
317 | |
318 | LabelAndGotoScopes[S] = ParentScope; |
319 | IndirectJumps.push_back(cast<IndirectGotoStmt>(S)); |
320 | break; |
321 | |
322 | case Stmt::SwitchStmtClass: |
323 | |
324 | |
325 | if (Stmt *Init = cast<SwitchStmt>(S)->getInit()) { |
326 | BuildScopeInformation(Init, ParentScope); |
327 | ++StmtsToSkip; |
328 | } |
329 | if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) { |
330 | BuildScopeInformation(Var, ParentScope); |
331 | ++StmtsToSkip; |
332 | } |
333 | LLVM_FALLTHROUGH; |
334 | |
335 | case Stmt::GotoStmtClass: |
336 | |
337 | |
338 | LabelAndGotoScopes[S] = ParentScope; |
339 | Jumps.push_back(S); |
340 | break; |
341 | |
342 | case Stmt::IfStmtClass: { |
343 | IfStmt *IS = cast<IfStmt>(S); |
344 | if (!(IS->isConstexpr() || IS->isObjCAvailabilityCheck())) |
345 | break; |
346 | |
347 | unsigned Diag = IS->isConstexpr() ? diag::note_protected_by_constexpr_if |
348 | : diag::note_protected_by_if_available; |
349 | |
350 | if (VarDecl *Var = IS->getConditionVariable()) |
351 | BuildScopeInformation(Var, ParentScope); |
352 | |
353 | |
354 | unsigned NewParentScope = Scopes.size(); |
355 | Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getBeginLoc())); |
356 | BuildScopeInformation(IS->getCond(), NewParentScope); |
357 | |
358 | |
359 | NewParentScope = Scopes.size(); |
360 | Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getBeginLoc())); |
361 | BuildScopeInformation(IS->getThen(), NewParentScope); |
362 | if (Stmt *Else = IS->getElse()) { |
363 | NewParentScope = Scopes.size(); |
364 | Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getBeginLoc())); |
365 | BuildScopeInformation(Else, NewParentScope); |
366 | } |
367 | return; |
368 | } |
369 | |
370 | case Stmt::CXXTryStmtClass: { |
371 | CXXTryStmt *TS = cast<CXXTryStmt>(S); |
372 | { |
373 | unsigned NewParentScope = Scopes.size(); |
374 | Scopes.push_back(GotoScope(ParentScope, |
375 | diag::note_protected_by_cxx_try, |
376 | diag::note_exits_cxx_try, |
377 | TS->getSourceRange().getBegin())); |
378 | if (Stmt *TryBlock = TS->getTryBlock()) |
379 | BuildScopeInformation(TryBlock, NewParentScope); |
380 | } |
381 | |
382 | |
383 | for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { |
384 | CXXCatchStmt *CS = TS->getHandler(I); |
385 | unsigned NewParentScope = Scopes.size(); |
386 | Scopes.push_back(GotoScope(ParentScope, |
387 | diag::note_protected_by_cxx_catch, |
388 | diag::note_exits_cxx_catch, |
389 | CS->getSourceRange().getBegin())); |
390 | BuildScopeInformation(CS->getHandlerBlock(), NewParentScope); |
391 | } |
392 | return; |
393 | } |
394 | |
395 | case Stmt::SEHTryStmtClass: { |
396 | SEHTryStmt *TS = cast<SEHTryStmt>(S); |
397 | { |
398 | unsigned NewParentScope = Scopes.size(); |
399 | Scopes.push_back(GotoScope(ParentScope, |
400 | diag::note_protected_by_seh_try, |
401 | diag::note_exits_seh_try, |
402 | TS->getSourceRange().getBegin())); |
403 | if (Stmt *TryBlock = TS->getTryBlock()) |
404 | BuildScopeInformation(TryBlock, NewParentScope); |
405 | } |
406 | |
407 | |
408 | if (SEHExceptStmt *Except = TS->getExceptHandler()) { |
409 | unsigned NewParentScope = Scopes.size(); |
410 | Scopes.push_back(GotoScope(ParentScope, |
411 | diag::note_protected_by_seh_except, |
412 | diag::note_exits_seh_except, |
413 | Except->getSourceRange().getBegin())); |
414 | BuildScopeInformation(Except->getBlock(), NewParentScope); |
415 | } else if (SEHFinallyStmt *Finally = TS->getFinallyHandler()) { |
416 | unsigned NewParentScope = Scopes.size(); |
417 | Scopes.push_back(GotoScope(ParentScope, |
418 | diag::note_protected_by_seh_finally, |
419 | diag::note_exits_seh_finally, |
420 | Finally->getSourceRange().getBegin())); |
421 | BuildScopeInformation(Finally->getBlock(), NewParentScope); |
422 | } |
423 | |
424 | return; |
425 | } |
426 | |
427 | case Stmt::DeclStmtClass: { |
428 | |
429 | |
430 | DeclStmt *DS = cast<DeclStmt>(S); |
431 | |
432 | |
433 | for (auto *I : DS->decls()) |
434 | BuildScopeInformation(I, origParentScope); |
435 | return; |
436 | } |
437 | |
438 | case Stmt::ObjCAtTryStmtClass: { |
439 | |
440 | |
441 | ObjCAtTryStmt *AT = cast<ObjCAtTryStmt>(S); |
442 | |
443 | { |
444 | unsigned NewParentScope = Scopes.size(); |
445 | Scopes.push_back(GotoScope(ParentScope, |
446 | diag::note_protected_by_objc_try, |
447 | diag::note_exits_objc_try, |
448 | AT->getAtTryLoc())); |
449 | if (Stmt *TryPart = AT->getTryBody()) |
450 | BuildScopeInformation(TryPart, NewParentScope); |
451 | } |
452 | |
453 | |
454 | for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) { |
455 | ObjCAtCatchStmt *AC = AT->getCatchStmt(I); |
456 | unsigned NewParentScope = Scopes.size(); |
457 | Scopes.push_back(GotoScope(ParentScope, |
458 | diag::note_protected_by_objc_catch, |
459 | diag::note_exits_objc_catch, |
460 | AC->getAtCatchLoc())); |
461 | |
462 | BuildScopeInformation(AC->getCatchBody(), NewParentScope); |
463 | } |
464 | |
465 | |
466 | if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { |
467 | unsigned NewParentScope = Scopes.size(); |
468 | Scopes.push_back(GotoScope(ParentScope, |
469 | diag::note_protected_by_objc_finally, |
470 | diag::note_exits_objc_finally, |
471 | AF->getAtFinallyLoc())); |
472 | BuildScopeInformation(AF, NewParentScope); |
473 | } |
474 | |
475 | return; |
476 | } |
477 | |
478 | case Stmt::ObjCAtSynchronizedStmtClass: { |
479 | |
480 | |
481 | ObjCAtSynchronizedStmt *AS = cast<ObjCAtSynchronizedStmt>(S); |
482 | |
483 | |
484 | BuildScopeInformation(AS->getSynchExpr(), ParentScope); |
485 | |
486 | |
487 | |
488 | unsigned NewParentScope = Scopes.size(); |
489 | Scopes.push_back(GotoScope(ParentScope, |
490 | diag::note_protected_by_objc_synchronized, |
491 | diag::note_exits_objc_synchronized, |
492 | AS->getAtSynchronizedLoc())); |
493 | BuildScopeInformation(AS->getSynchBody(), NewParentScope); |
494 | return; |
495 | } |
496 | |
497 | case Stmt::ObjCAutoreleasePoolStmtClass: { |
498 | |
499 | ObjCAutoreleasePoolStmt *AS = cast<ObjCAutoreleasePoolStmt>(S); |
500 | |
501 | |
502 | unsigned NewParentScope = Scopes.size(); |
503 | Scopes.push_back(GotoScope(ParentScope, |
504 | diag::note_protected_by_objc_autoreleasepool, |
505 | diag::note_exits_objc_autoreleasepool, |
506 | AS->getAtLoc())); |
507 | BuildScopeInformation(AS->getSubStmt(), NewParentScope); |
508 | return; |
509 | } |
510 | |
511 | case Stmt::ExprWithCleanupsClass: { |
512 | |
513 | |
514 | |
515 | ExprWithCleanups *EWC = cast<ExprWithCleanups>(S); |
516 | for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) { |
517 | const BlockDecl *BDecl = EWC->getObject(i); |
518 | for (const auto &CI : BDecl->captures()) { |
519 | VarDecl *variable = CI.getVariable(); |
520 | BuildScopeInformation(variable, BDecl, origParentScope); |
521 | } |
522 | } |
523 | break; |
524 | } |
525 | |
526 | case Stmt::MaterializeTemporaryExprClass: { |
527 | |
528 | |
529 | MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(S); |
530 | if (MTE->getStorageDuration() == SD_Automatic) { |
531 | SmallVector<const Expr *, 4> CommaLHS; |
532 | SmallVector<SubobjectAdjustment, 4> Adjustments; |
533 | const Expr *ExtendedObject = |
534 | MTE->GetTemporaryExpr()->skipRValueSubobjectAdjustments( |
535 | CommaLHS, Adjustments); |
536 | if (ExtendedObject->getType().isDestructedType()) { |
537 | Scopes.push_back(GotoScope(ParentScope, 0, |
538 | diag::note_exits_temporary_dtor, |
539 | ExtendedObject->getExprLoc())); |
540 | origParentScope = Scopes.size()-1; |
541 | } |
542 | } |
543 | break; |
544 | } |
545 | |
546 | case Stmt::CaseStmtClass: |
547 | case Stmt::DefaultStmtClass: |
548 | case Stmt::LabelStmtClass: |
549 | LabelAndGotoScopes[S] = ParentScope; |
550 | break; |
551 | |
552 | default: |
553 | break; |
554 | } |
555 | |
556 | for (Stmt *SubStmt : S->children()) { |
557 | if (!SubStmt) |
558 | continue; |
559 | if (StmtsToSkip) { |
560 | --StmtsToSkip; |
561 | continue; |
562 | } |
563 | |
564 | |
565 | |
566 | |
567 | while (true) { |
568 | Stmt *Next; |
569 | if (SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt)) |
570 | Next = SC->getSubStmt(); |
571 | else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt)) |
572 | Next = LS->getSubStmt(); |
573 | else |
574 | break; |
575 | |
576 | LabelAndGotoScopes[SubStmt] = ParentScope; |
577 | SubStmt = Next; |
578 | } |
579 | |
580 | |
581 | BuildScopeInformation(SubStmt, ParentScope); |
582 | } |
583 | } |
584 | |
585 | |
586 | |
587 | void JumpScopeChecker::VerifyJumps() { |
588 | while (!Jumps.empty()) { |
589 | Stmt *Jump = Jumps.pop_back_val(); |
590 | |
591 | |
592 | if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { |
593 | |
594 | if (GS->getLabel()->getStmt()) { |
595 | CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), |
596 | diag::err_goto_into_protected_scope, |
597 | diag::ext_goto_into_protected_scope, |
598 | diag::warn_cxx98_compat_goto_into_protected_scope); |
599 | } |
600 | CheckGotoStmt(GS); |
601 | continue; |
602 | } |
603 | |
604 | |
605 | if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) { |
606 | LabelDecl *Target = IGS->getConstantTarget(); |
607 | CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(), |
608 | diag::err_goto_into_protected_scope, |
609 | diag::ext_goto_into_protected_scope, |
610 | diag::warn_cxx98_compat_goto_into_protected_scope); |
611 | continue; |
612 | } |
613 | |
614 | SwitchStmt *SS = cast<SwitchStmt>(Jump); |
615 | for (SwitchCase *SC = SS->getSwitchCaseList(); SC; |
616 | SC = SC->getNextSwitchCase()) { |
617 | if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(SC))) |
618 | continue; |
619 | SourceLocation Loc; |
620 | if (CaseStmt *CS = dyn_cast<CaseStmt>(SC)) |
621 | Loc = CS->getBeginLoc(); |
622 | else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) |
623 | Loc = DS->getBeginLoc(); |
624 | else |
625 | Loc = SC->getBeginLoc(); |
626 | CheckJump(SS, SC, Loc, diag::err_switch_into_protected_scope, 0, |
627 | diag::warn_cxx98_compat_switch_into_protected_scope); |
628 | } |
629 | } |
630 | } |
631 | |
632 | |
633 | |
634 | |
635 | |
636 | |
637 | |
638 | |
639 | |
640 | |
641 | |
642 | |
643 | |
644 | |
645 | |
646 | |
647 | |
648 | |
649 | |
650 | |
651 | void JumpScopeChecker::VerifyIndirectJumps() { |
652 | if (IndirectJumps.empty()) return; |
653 | |
654 | |
655 | |
656 | if (IndirectJumpTargets.empty()) { |
657 | S.Diag(IndirectJumps[0]->getGotoLoc(), |
658 | diag::err_indirect_goto_without_addrlabel); |
659 | return; |
660 | } |
661 | |
662 | |
663 | |
664 | |
665 | typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope; |
666 | SmallVector<JumpScope, 32> JumpScopes; |
667 | { |
668 | llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap; |
669 | for (SmallVectorImpl<IndirectGotoStmt*>::iterator |
670 | I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) { |
671 | IndirectGotoStmt *IG = *I; |
672 | if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(IG))) |
673 | continue; |
674 | unsigned IGScope = LabelAndGotoScopes[IG]; |
675 | IndirectGotoStmt *&Entry = JumpScopesMap[IGScope]; |
676 | if (!Entry) Entry = IG; |
677 | } |
678 | JumpScopes.reserve(JumpScopesMap.size()); |
679 | for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator |
680 | I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I) |
681 | JumpScopes.push_back(*I); |
682 | } |
683 | |
684 | |
685 | |
686 | |
687 | llvm::DenseMap<unsigned, LabelDecl*> TargetScopes; |
688 | for (SmallVectorImpl<LabelDecl*>::iterator |
689 | I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end(); |
690 | I != E; ++I) { |
691 | LabelDecl *TheLabel = *I; |
692 | if (getStmt()))", "/home/seafit/code_projects/clang_source/clang/lib/Sema/JumpDiagnostics.cpp", 692, __PRETTY_FUNCTION__)), (Permissive && (!LabelAndGotoScopes.count(TheLabel->getStmt()))))" file_link="#92" macro="true">CHECK_PERMISSIVE(!LabelAndGotoScopes.count(TheLabel->getStmt()))) |
693 | continue; |
694 | unsigned LabelScope = LabelAndGotoScopes[TheLabel->getStmt()]; |
695 | LabelDecl *&Target = TargetScopes[LabelScope]; |
696 | if (!Target) Target = TheLabel; |
697 | } |
698 | |
699 | |
700 | |
701 | |
702 | |
703 | |
704 | |
705 | |
706 | |
707 | llvm::BitVector Reachable(Scopes.size(), false); |
708 | for (llvm::DenseMap<unsigned,LabelDecl*>::iterator |
709 | TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) { |
710 | unsigned TargetScope = TI->first; |
711 | LabelDecl *TargetLabel = TI->second; |
712 | |
713 | Reachable.reset(); |
714 | |
715 | |
716 | |
717 | |
718 | unsigned Min = TargetScope; |
719 | while (true) { |
720 | Reachable.set(Min); |
721 | |
722 | |
723 | if (Min == 0) break; |
724 | |
725 | |
726 | if (Scopes[Min].InDiag) break; |
727 | |
728 | Min = Scopes[Min].ParentScope; |
729 | } |
730 | |
731 | |
732 | |
733 | for (SmallVectorImpl<JumpScope>::iterator |
734 | I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) { |
735 | unsigned Scope = I->first; |
736 | |
737 | |
738 | |
739 | |
740 | |
741 | |
742 | bool IsReachable = false; |
743 | while (true) { |
744 | if (Reachable.test(Scope)) { |
745 | |
746 | |
747 | for (unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope) |
748 | Reachable.set(S); |
749 | IsReachable = true; |
750 | break; |
751 | } |
752 | |
753 | |
754 | |
755 | if (Scope == 0 || Scope < Min) break; |
756 | |
757 | |
758 | if (Scopes[Scope].OutDiag) break; |
759 | |
760 | Scope = Scopes[Scope].ParentScope; |
761 | } |
762 | |
763 | |
764 | if (IsReachable) continue; |
765 | |
766 | DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope); |
767 | } |
768 | } |
769 | } |
770 | |
771 | |
772 | |
773 | static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote) { |
774 | return (JumpDiag == diag::err_goto_into_protected_scope && |
775 | (InDiagNote == diag::note_protected_by_variable_init || |
776 | InDiagNote == diag::note_protected_by_variable_nontriv_destructor)); |
777 | } |
778 | |
779 | |
780 | |
781 | static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) { |
782 | return S.getLangOpts().CPlusPlus11 && |
783 | InDiagNote == diag::note_protected_by_variable_non_pod; |
784 | } |
785 | |
786 | |
787 | static void DiagnoseIndirectJumpStmt(Sema &S, IndirectGotoStmt *Jump, |
788 | LabelDecl *Target, bool &Diagnosed) { |
789 | if (Diagnosed) |
790 | return; |
791 | S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope); |
792 | S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target); |
793 | Diagnosed = true; |
794 | } |
795 | |
796 | |
797 | void JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) { |
798 | if (CHECK_PERMISSIVE(ToScopes.empty())) |
799 | return; |
800 | for (unsigned I = 0, E = ToScopes.size(); I != E; ++I) |
801 | if (Scopes[ToScopes[I]].InDiag) |
802 | S.Diag(Scopes[ToScopes[I]].Loc, Scopes[ToScopes[I]].InDiag); |
803 | } |
804 | |
805 | |
806 | void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, |
807 | unsigned JumpScope, |
808 | LabelDecl *Target, |
809 | unsigned TargetScope) { |
810 | if (CHECK_PERMISSIVE(JumpScope == TargetScope)) |
811 | return; |
812 | |
813 | unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope); |
814 | bool Diagnosed = false; |
815 | |
816 | |
817 | for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope) |
818 | if (Scopes[I].OutDiag) { |
819 | DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed); |
820 | S.Diag(Scopes[I].Loc, Scopes[I].OutDiag); |
821 | } |
822 | |
823 | SmallVector<unsigned, 10> ToScopesCXX98Compat; |
824 | |
825 | |
826 | for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope) |
827 | if (IsCXX98CompatWarning(S, Scopes[I].InDiag)) |
828 | ToScopesCXX98Compat.push_back(I); |
829 | else if (Scopes[I].InDiag) { |
830 | DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed); |
831 | S.Diag(Scopes[I].Loc, Scopes[I].InDiag); |
832 | } |
833 | |
834 | |
835 | if (!Diagnosed && !ToScopesCXX98Compat.empty()) { |
836 | S.Diag(Jump->getGotoLoc(), |
837 | diag::warn_cxx98_compat_indirect_goto_in_protected_scope); |
838 | S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target); |
839 | NoteJumpIntoScopes(ToScopesCXX98Compat); |
840 | } |
841 | } |
842 | |
843 | |
844 | |
845 | void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, |
846 | unsigned JumpDiagError, unsigned JumpDiagWarning, |
847 | unsigned JumpDiagCXX98Compat) { |
848 | if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(From))) |
849 | return; |
850 | if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(To))) |
851 | return; |
852 | |
853 | unsigned FromScope = LabelAndGotoScopes[From]; |
854 | unsigned ToScope = LabelAndGotoScopes[To]; |
855 | |
856 | |
857 | if (FromScope == ToScope) return; |
858 | |
859 | |
860 | if (isa<GotoStmt>(From) || isa<IndirectGotoStmt>(From)) { |
861 | |
862 | |
863 | for (unsigned I = FromScope; I > ToScope; I = Scopes[I].ParentScope) { |
864 | if (Scopes[I].InDiag == diag::note_protected_by_seh_finally) { |
865 | S.Diag(From->getBeginLoc(), diag::warn_jump_out_of_seh_finally); |
866 | break; |
867 | } |
868 | } |
869 | } |
870 | |
871 | unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope); |
872 | |
873 | |
874 | if (CommonScope == ToScope) return; |
875 | |
876 | |
877 | SmallVector<unsigned, 10> ToScopesCXX98Compat; |
878 | SmallVector<unsigned, 10> ToScopesError; |
879 | SmallVector<unsigned, 10> ToScopesWarning; |
880 | for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) { |
881 | if (S.getLangOpts().MSVCCompat && JumpDiagWarning != 0 && |
882 | IsMicrosoftJumpWarning(JumpDiagError, Scopes[I].InDiag)) |
883 | ToScopesWarning.push_back(I); |
884 | else if (IsCXX98CompatWarning(S, Scopes[I].InDiag)) |
885 | ToScopesCXX98Compat.push_back(I); |
886 | else if (Scopes[I].InDiag) |
887 | ToScopesError.push_back(I); |
888 | } |
889 | |
890 | |
891 | if (!ToScopesWarning.empty()) { |
892 | S.Diag(DiagLoc, JumpDiagWarning); |
893 | NoteJumpIntoScopes(ToScopesWarning); |
894 | } |
895 | |
896 | |
897 | if (!ToScopesError.empty()) { |
898 | S.Diag(DiagLoc, JumpDiagError); |
899 | NoteJumpIntoScopes(ToScopesError); |
900 | } |
901 | |
902 | |
903 | if (ToScopesError.empty() && !ToScopesCXX98Compat.empty()) { |
904 | S.Diag(DiagLoc, JumpDiagCXX98Compat); |
905 | NoteJumpIntoScopes(ToScopesCXX98Compat); |
906 | } |
907 | } |
908 | |
909 | void JumpScopeChecker::CheckGotoStmt(GotoStmt *GS) { |
910 | if (GS->getLabel()->isMSAsmLabel()) { |
911 | S.Diag(GS->getGotoLoc(), diag::err_goto_ms_asm_label) |
912 | << GS->getLabel()->getIdentifier(); |
913 | S.Diag(GS->getLabel()->getLocation(), diag::note_goto_ms_asm_label) |
914 | << GS->getLabel()->getIdentifier(); |
915 | } |
916 | } |
917 | |
918 | void Sema::DiagnoseInvalidJumps(Stmt *Body) { |
919 | (void)JumpScopeChecker(Body, *this); |
920 | } |
921 | |