This revision was automatically updated to reflect the committed changes. Closed by commit rL307051: [Sema] Make BreakContinueFinder handle nested loops. (authored by efriedma).
Changed prior to commit: https://reviews.llvm.org/D34568?vs=103761&id=105128#toc Repository: rL LLVM https://reviews.llvm.org/D34568 Files: cfe/trunk/lib/Sema/SemaStmt.cpp cfe/trunk/test/Sema/loop-control.c cfe/trunk/test/SemaCXX/warn-loop-analysis.cpp
Index: cfe/trunk/lib/Sema/SemaStmt.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaStmt.cpp +++ cfe/trunk/lib/Sema/SemaStmt.cpp @@ -1544,23 +1544,78 @@ // A visitor to determine if a continue or break statement is a // subexpression. - class BreakContinueFinder : public EvaluatedExprVisitor<BreakContinueFinder> { + class BreakContinueFinder : public ConstEvaluatedExprVisitor<BreakContinueFinder> { SourceLocation BreakLoc; SourceLocation ContinueLoc; + bool InSwitch = false; + public: - BreakContinueFinder(Sema &S, Stmt* Body) : + BreakContinueFinder(Sema &S, const Stmt* Body) : Inherited(S.Context) { Visit(Body); } - typedef EvaluatedExprVisitor<BreakContinueFinder> Inherited; + typedef ConstEvaluatedExprVisitor<BreakContinueFinder> Inherited; - void VisitContinueStmt(ContinueStmt* E) { + void VisitContinueStmt(const ContinueStmt* E) { ContinueLoc = E->getContinueLoc(); } - void VisitBreakStmt(BreakStmt* E) { - BreakLoc = E->getBreakLoc(); + void VisitBreakStmt(const BreakStmt* E) { + if (!InSwitch) + BreakLoc = E->getBreakLoc(); + } + + void VisitSwitchStmt(const SwitchStmt* S) { + if (const Stmt *Init = S->getInit()) + Visit(Init); + if (const Stmt *CondVar = S->getConditionVariableDeclStmt()) + Visit(CondVar); + if (const Stmt *Cond = S->getCond()) + Visit(Cond); + + // Don't return break statements from the body of a switch. + InSwitch = true; + if (const Stmt *Body = S->getBody()) + Visit(Body); + InSwitch = false; + } + + void VisitForStmt(const ForStmt *S) { + // Only visit the init statement of a for loop; the body + // has a different break/continue scope. + if (const Stmt *Init = S->getInit()) + Visit(Init); + } + + void VisitWhileStmt(const WhileStmt *) { + // Do nothing; the children of a while loop have a different + // break/continue scope. + } + + void VisitDoStmt(const DoStmt *) { + // Do nothing; the children of a while loop have a different + // break/continue scope. + } + + void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { + // Only visit the initialization of a for loop; the body + // has a different break/continue scope. + if (const Stmt *Range = S->getRangeStmt()) + Visit(Range); + if (const Stmt *Begin = S->getBeginStmt()) + Visit(Begin); + if (const Stmt *End = S->getEndStmt()) + Visit(End); + } + + void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { + // Only visit the initialization of a for loop; the body + // has a different break/continue scope. + if (const Stmt *Element = S->getElement()) + Visit(Element); + if (const Stmt *Collection = S->getCollection()) + Visit(Collection); } bool ContinueFound() { return ContinueLoc.isValid(); } Index: cfe/trunk/test/SemaCXX/warn-loop-analysis.cpp =================================================================== --- cfe/trunk/test/SemaCXX/warn-loop-analysis.cpp +++ cfe/trunk/test/SemaCXX/warn-loop-analysis.cpp @@ -202,6 +202,12 @@ if (true) continue; i--; } + + // But do warn if the continue is in a nested loop. + for (;;i--) { // expected-note{{decremented here}} + for (int j = 0; j < 10; ++j) continue; + i--; // expected-warning{{decremented both}} + } } struct iterator { @@ -259,6 +265,12 @@ if (true) continue; i--; } + + // But do warn if the continue is in a nested loop. + for (;;i--) { // expected-note{{decremented here}} + for (int j = 0; j < 10; ++j) continue; + i--; // expected-warning{{decremented both}} + } } int f(int); Index: cfe/trunk/test/Sema/loop-control.c =================================================================== --- cfe/trunk/test/Sema/loop-control.c +++ cfe/trunk/test/Sema/loop-control.c @@ -119,3 +119,51 @@ for ( ; ({ ++y; break; y;}); ++y) {} // expected-warning{{'break' is bound to loop, GCC binds it to switch}} } } + +void pr32648_1(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; switch (y) { case 0: break; } y;}); ++y) {} // no warning + } +} + +void pr32648_2(int x, int y) { + while(x) { + for ( ; ({ ++y; switch (y) { case 0: continue; } y;}); ++y) {} // expected-warning {{'continue' is bound to current loop, GCC binds it to the enclosing loop}} + } +} + +void pr32648_3(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; for (; y; y++) { break; } y;}); ++y) {} // no warning + } +} + +void pr32648_4(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; for (({ break; }); y; y++) { } y;}); ++y) {} // expected-warning{{'break' is bound to loop, GCC binds it to switch}} + } +} + +void pr32648_5(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; while (({ break; y; })) {} y;}); ++y) {} // expected-warning{{'break' is bound to current loop, GCC binds it to the enclosing loop}} + } +} + +void pr32648_6(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; do {} while (({ break; y; })); y;}); ++y) {} // expected-warning{{'break' is bound to current loop, GCC binds it to the enclosing loop}} + } +} + +void pr32648_7(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; do { break; } while (y); y;}); ++y) {} // no warning + } +}
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits