diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index 20618d8bb..e2d55a082 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -229,8 +229,10 @@ static int IfStatement (void) g_defcodelabel (Label2); } - /* Done */ - return StmtFlags; + /* Done. We will never return "empty" for an if statement because of side + ** effects when evaluating the condition. + */ + return StmtFlags & ~SF_EMPTY; } @@ -299,8 +301,10 @@ static int DoStatement (void) } } - /* "break" and "continue" are not relevant for the following code */ - StmtFlags &= ~(SF_ANY_BREAK | SF_ANY_CONTINUE); + /* "break" and "continue" are not relevant for the following code. "empty" + ** is removed because of side effects when evaluating the condition. + */ + StmtFlags &= ~(SF_ANY_BREAK | SF_ANY_CONTINUE | SF_EMPTY); /* Done */ return StmtFlags; @@ -393,8 +397,10 @@ static int WhileStatement (void) */ StmtFlags &= ~SF_MASK_UNREACH; } - /* "break" and "continue" are not relevant for the following code */ - StmtFlags &= ~(SF_ANY_BREAK | SF_ANY_CONTINUE); + /* "break" and "continue" are not relevant for the following code. "empty" + ** is removed because of side effects when evaluating the condition. + */ + StmtFlags &= ~(SF_ANY_BREAK | SF_ANY_CONTINUE | SF_EMPTY); /* Done */ return StmtFlags; @@ -602,6 +608,11 @@ static int ForStatement (void) /* Skip the closing paren */ ConsumeRParen (); + /* Output a warning if the loop body is never executed */ + if (TestResult == TESTEXPR_FALSE) { + UnreachableCodeWarning (); + } + /* Loop body */ g_defcodelabel (BodyLabel); StmtFlags = AnyStatement (&PendingToken, 0); @@ -628,10 +639,30 @@ static int ForStatement (void) /* Remove the loop from the loop stack */ DelLoop (); - /* If the condition is always true, any special statements are always - ** executed. Otherwise we don't know. + /* Fix the flags for the loop. */ + if (TestResult == TESTEXPR_TRUE) { + /* If the loop condition is always true, and we do not have a + ** "break" statement, the loop won't terminate. So the only valid + ** "unreach" flag is that for the endless loop. Otherwise - if there + ** is a "break" statement, the code after the loop is reachable. + */ + StmtFlags &= ~SF_MASK_UNREACH; + if (!SF_Any_Break (StmtFlags)) { + StmtFlags |= (SF_OTHER | SF_ANY_OTHER); + } + } else { + /* If the loop condition is not always true, the code after the loop + ** is always reachable. + */ + StmtFlags &= ~SF_MASK_UNREACH; + } + /* "break" and "continue" are not relevant for the following code. "empty" + ** is removed because of side effects when evaluating the condition. */ - return (TestResult == TESTEXPR_TRUE)? StmtFlags : SF_NONE; + StmtFlags &= ~(SF_ANY_BREAK | SF_ANY_CONTINUE | SF_EMPTY); + + /* Done */ + return StmtFlags; } @@ -641,15 +672,23 @@ static int CompoundStatement (int* PendingToken, struct SwitchCtrl* Switch) ** function returns true if the last statement was a break or return. */ { + int OldStack; + unsigned OldBlockStackSize; int StmtFlags; - /* Remember the stack at block entry */ - int OldStack = StackPtr; - unsigned OldBlockStackSize = CollCount (&CurrentFunc->LocalsBlockStack); - /* Skip '{' */ NextToken (); + /* If the closing curly bracket follows we have an empty statement */ + if (CurTok.Tok == TOK_RCURLY) { + NextToken (); + return SF_EMPTY; + } + + /* Remember the stack at block entry */ + OldStack = StackPtr; + OldBlockStackSize = CollCount (&CurrentFunc->LocalsBlockStack); + /* Enter a new lexical level */ EnterBlockLevel (); @@ -741,25 +780,45 @@ int StatementBlock (struct SwitchCtrl* Switch) if (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) { LineInfo* LI1 = UseLineInfo (GetDiagnosticLI ()); int StmtFlags1 = AnyStatement (0, Switch); - int UnreachableWarning = 0; + int Unreachable = 0; /* True if code is unreachable */ + int Warning = 0; /* True if warning was output */ while (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) { LineInfo* LI2 = UseLineInfo (GetDiagnosticLI ()); int StmtFlags2 = AnyStatement (0, Switch); - if (!UnreachableWarning) { - /* Check if the code is unreachable because of a preceeding - ** jump and if the code doesn't have a jump label. - */ - if ((StmtFlags1 & SF_MASK_UNREACH) != SF_NONE && - (StmtFlags2 & SF_MASK_LABEL) == SF_NONE) { - LIUnreachableCodeWarning (LI2); - UnreachableWarning = 1; - } + + /* If this statement is not already unreachable, check if the + ** previous statement made it unreachable. + */ + if (!Unreachable) { + Unreachable = SF_Unreach (StmtFlags1); } + /* If the previous statement made this one unreachable, but this + ** one has a label, it is not unreachable. If we've output a + ** warning before, reset the warning flag so a new warning is + ** output if code becomes unreachable again. + */ + if (Unreachable && SF_Label (StmtFlags2)) { + Unreachable = 0; + Warning = 0; + } + /* If this statement is unreachable but not the empty statement, + ** and we didn't give a warning before, to that now + */ + if (Unreachable && !SF_Empty (StmtFlags2) && !Warning) { + LIUnreachableCodeWarning (LI2); + Warning = 1; + } + + /* If the current statement wasn't unreachable update the flags */ + if (!Unreachable) { + StmtFlags1 = SF_Any (StmtFlags1) | StmtFlags2; + } + + /* Prepare for the next round */ if (LI1) { ReleaseLineInfo (LI1); } LI1 = LI2; - StmtFlags1 = (StmtFlags1 & SF_MASK_ANY) | StmtFlags2; } if (LI1) { ReleaseLineInfo (LI1); @@ -873,7 +932,7 @@ int AnyStatement (int* PendingToken, struct SwitchCtrl* Switch) case TOK_SEMI: /* Empty statement. Ignore it */ CheckSemi (PendingToken); - StmtFlags = SF_NONE; + StmtFlags = SF_EMPTY; break; case TOK_LCURLY: diff --git a/src/cc65/stmt.h b/src/cc65/stmt.h index eaaf235d5..3528602a8 100644 --- a/src/cc65/stmt.h +++ b/src/cc65/stmt.h @@ -88,6 +88,9 @@ enum { SF_LABEL_CASE = 0x20000, /* Statement preceeded by case label */ SF_LABEL_DEFAULT = 0x40000, /* Statement preceeded by default label */ SF_MASK_LABEL = 0x70000, /* Mask for any label */ + + /* And a flag to mark an empty statement */ + SF_EMPTY = 0x80000, /* Empty statement */ }; /* Forward */ @@ -125,6 +128,12 @@ static inline int SF_Any_Break (int F) return (F & SF_ANY_BREAK); } +static inline int SF_Any_Goto (int F) +/* Check if there was any "goto" statement */ +{ + return (F & SF_ANY_GOTO); +} + static inline int SF_Any (int F) /* Return just the "any" part of the given flags */ { @@ -137,6 +146,12 @@ static inline int SF_Label (int F) return (F & SF_MASK_LABEL); } +static inline int SF_Empty (int F) +/* Check if this is the empty statement */ +{ + return (F & SF_EMPTY); +} + /*****************************************************************************/ diff --git a/src/cc65/swstmt.c b/src/cc65/swstmt.c index 591c893a4..a383993ae 100644 --- a/src/cc65/swstmt.c +++ b/src/cc65/swstmt.c @@ -61,23 +61,35 @@ -/* Some bitmapped flags for use in SwitchCtrl */ -#define SC_NONE 0x0000 -#define SC_CASE 0x0001 /* We had a case label */ -#define SC_DEFAULT 0x0002 /* We had a default label */ -#define SC_MASK_LABEL 0x0003 /* Mask for the labels */ -#define SC_WEIRD 0x0004 /* Flag for a weird switch that contains code - ** outside of any label. - */ +/* Flow control data for one switch label */ +typedef struct LabelCtrl LabelCtrl; +struct LabelCtrl { + long Value; /* Numeric value if any */ + int StmtFlags; /* Collected statement flags for this label */ + uint8_t Default; /* Is this the default label? */ + uint8_t Unreachable; /* Label is unreachable */ + uint8_t Warning; /* We've output a warning for this label */ + uint8_t Breaks; /* Code after this label contains a "break" */ +}; +/* Switch control data */ typedef struct SwitchCtrl SwitchCtrl; struct SwitchCtrl { Collection* Nodes; /* CaseNode tree */ const Type* ExprType; /* Switch controlling expression type */ unsigned Depth; /* Number of bytes the selector type has */ unsigned DefaultLabel; /* Label for the default branch */ - unsigned CtrlFlags; /* Bitmapped flags as defined above */ + + /* Data for flow control analysis. The Labels collection will contain + ** allocated but the ActiveLabels will contain just pointers to data + ** owned by the Labels collection. + */ + int Weird; /* Flag for a weird switch that contains gotos + ** or code outside of any label. + */ int StmtFlags; /* Collected statement flags */ + Collection Labels; /* Collection with all labels */ + Collection ActiveLabels; /* Collection with currently active labels */ }; /* Pointer to current switch control struct */ @@ -86,47 +98,46 @@ static SwitchCtrl* Switch = 0; /*****************************************************************************/ -/* Functions that work with struct SwitchExpr */ +/* struct LabelCtrl */ /*****************************************************************************/ -static int SC_Label (const SwitchCtrl* S) -/* Check if we had a switch label */ +static void AddLabelCtrl (SwitchCtrl* Switch, uint8_t Default, long Value, + uint8_t Unreachable) +/* Create a new LabelCtrl structure and add it to the current switch */ { - return (S->CtrlFlags & SC_MASK_LABEL) != SC_NONE; + /* Allocate */ + LabelCtrl* LC = xmalloc (sizeof (*LC)); + + /* Initialize */ + LC->Value = Value; + LC->StmtFlags = SF_NONE; + LC->Default = Default; + LC->Unreachable = Unreachable; + LC->Warning = 0; + LC->Breaks = 0; + + /* Add it to the labels. If the label isn't unreachable, do also add it + ** to the active labels. + */ + CollAppend (&Switch->Labels, LC); + if (!LC->Unreachable) { + CollAppend (&Switch->ActiveLabels, LC); + } } -static int SC_IsWeird (const SwitchCtrl* S) -/* Check if this switch is weird */ +static void FreeLabels (SwitchCtrl* Switch) +/* Delete all labels in the given switch control structure */ { - return (S->CtrlFlags & SC_WEIRD) != SC_NONE; -} - - - -static void SC_SetCase (SwitchCtrl* S) -/* Set the current label type to "case" */ -{ - S->CtrlFlags |= SC_CASE; -} - - - -static void SC_SetDefault (SwitchCtrl* S) -/* Set the current label type to "default" */ -{ - S->CtrlFlags |= SC_DEFAULT; -} - - - -static void SC_MakeWeird (SwitchCtrl* S) -/* Mark the switch as weird */ -{ - S->CtrlFlags |= SC_WEIRD; + unsigned I; + for (I = 0; I < CollCount (&Switch->Labels); ++I) { + xfree (CollAtUnchecked (&Switch->Labels, I)); + } + CollDeleteAll (&Switch->Labels); + CollDeleteAll (&Switch->ActiveLabels); } @@ -190,8 +201,10 @@ int SwitchStatement (void) SwitchData.ExprType = SwitchExpr.Type; SwitchData.Depth = SizeOf (SwitchExpr.Type); SwitchData.DefaultLabel = 0; - SwitchData.CtrlFlags = SC_NONE; + SwitchData.Weird = 0; SwitchData.StmtFlags = SF_NONE; + SwitchData.Labels = EmptyCollection; + SwitchData.ActiveLabels = EmptyCollection; OldSwitch = Switch; Switch = &SwitchData; @@ -251,17 +264,63 @@ int SwitchStatement (void) /* Free the case value tree */ FreeCaseNodeColl (SwitchData.Nodes); - /* If the case statement was terminated by a closing curly - ** brace, skip it now. + /* If the case statement was terminated by a closing curly brace, skip + ** it now. */ if (RCurlyBrace) { NextToken (); } + /* Remove "break" from the flags since it is handled completely inside the + ** switch statement. + */ + StmtFlags = SwitchData.StmtFlags & ~(SF_ANY_BREAK | SF_BREAK); + + /* If the switch was weird, we cannot really tell if the following code is + ** unreachable. + */ + if (!SwitchData.Weird) { + + /* Check the labels. If there is no default label, the code after the + ** switch is always reachable. If there is a default label, the code + ** after the switch is reachable if the default label code ends with a + ** break or no statement that makes following instructions unreachable. + ** Otherwise the code after the switch is reachable if any of the + ** labels contains a "break" statement. + */ + StmtFlags = SF_NONE; + int Reachable = 0; + int Default = 0; + for (unsigned I = 0; I < CollCount (&SwitchData.Labels); ++I) { + const LabelCtrl* LC = CollAtUnchecked (&SwitchData.Labels, I); + if (LC->Default) { + Default = 1; + if (!SF_Unreach (LC->StmtFlags)) { + Reachable = 1; + } + } + if (SF_Any_Break (LC->StmtFlags)) { + Reachable = 1; + } + StmtFlags |= (LC->StmtFlags & ~(SF_ANY_BREAK | SF_BREAK)); + } + if (!Default) { + Reachable = 1; + } + if (Reachable) { + StmtFlags &= ~SF_MASK_UNREACH; + } + } + + /* Now free the labels */ + FreeLabels (&SwitchData); + DoneCollection (&SwitchData.Labels); + DoneCollection (&SwitchData.ActiveLabels); + /* We only return the combined "any" flags from all the statements within ** the switch. Minus "break" which is handled inside the switch. */ - return SwitchData.StmtFlags & ~SF_ANY_BREAK; + return StmtFlags; } @@ -284,7 +343,6 @@ void CaseLabel (void) const Type* CaseT = CaseExpr.Type; long CaseVal = CaseExpr.IVal; int OutOfRange = 0; - const char* DiagMsg = 0; CaseExpr.Type = IntPromotion (Switch->ExprType); LimitExprValue (&CaseExpr, 1); @@ -305,18 +363,21 @@ void CaseLabel (void) /* Check the range of the expression */ if (IsSignSigned (CaseExpr.Type)) { if (CaseExpr.IVal < GetIntegerTypeMin (Switch->ExprType)) { - DiagMsg = "Case value (%ld) out of range for switch condition type"; OutOfRange = 1; + Warning ("Case value (%ld) out of range for switch condition type", + CaseExpr.IVal); } else if (IsSignSigned (Switch->ExprType) ? CaseExpr.IVal > (long)GetIntegerTypeMax (Switch->ExprType) : SizeOf (CaseExpr.Type) > SizeOf (Switch->ExprType) && (unsigned long)CaseExpr.IVal > GetIntegerTypeMax (Switch->ExprType)) { - DiagMsg = "Case value (%ld) out of range for switch condition type"; OutOfRange = 1; + Warning ("Case value (%ld) out of range for switch condition type", + CaseExpr.IVal); } } else if ((unsigned long)CaseExpr.IVal > GetIntegerTypeMax (Switch->ExprType)) { - DiagMsg = "Case value (%lu) out of range for switch condition type"; OutOfRange = 1; + Warning ("Case value (%lu) out of range for switch condition type", + (unsigned long) CaseExpr.IVal); } if (OutOfRange == 0) { @@ -325,12 +386,10 @@ void CaseLabel (void) /* Define this label */ g_defcodelabel (CodeLabel); - } else { - Warning (DiagMsg, CaseExpr.IVal); } - /* Remember that we're in a case label section now */ - SC_SetCase (Switch); + /* Add a label control structure for this label */ + AddLabelCtrl (Switch, 0, CaseExpr.IVal, OutOfRange); } else { @@ -361,8 +420,8 @@ void DefaultLabel (void) Switch->DefaultLabel = GetLocalLabel (); g_defcodelabel (Switch->DefaultLabel); - /* Remember that we're in the default label section now */ - SC_SetDefault (Switch); + /* Add a label control structure for this label */ + AddLabelCtrl (Switch, 1, 0, 0); } else { /* We had the default label already */ @@ -387,20 +446,57 @@ void SwitchBodyStatement (struct SwitchCtrl* S, LineInfo* LI, int StmtFlags) ** a switch passing the flags for special statements. */ { + unsigned I; + /* The control structure passed must be the current one */ PRECONDITION (S == Switch); /* Handle code without a label in the switch */ - if (SC_Label (S) == SC_NONE) { + if (CollCount (&S->Labels) == 0) { /* This is a statement that preceedes any switch labels. If the - ** switch is not already marked as weird, output and the current - ** statement has no label, output a warning about unreachable code. + ** switch is not already marked as weird and the current statement + ** has no label, output a warning about unreachable code. */ - if (!SC_IsWeird (S)) { + if (!S->Weird) { if (!SF_Label (StmtFlags)) { LIUnreachableCodeWarning (LI); } - SC_MakeWeird (S); + S->Weird = 1; + } + } + + /* If the new statement contains a "goto", mark the switch as "weird" */ + if (SF_Any_Goto (StmtFlags)) { + S->Weird = 1; + } + + /* If the switch is marked as weird, no further action */ + if (S->Weird) { + return; + } + + /* Handle all currently active labels. Walk from the end since we're + ** deleting stuff from the array. + */ + I = CollCount (&S->ActiveLabels); + while (I > 0) { + LabelCtrl* LC = CollAtUnchecked (&S->ActiveLabels, --I); + + /* Collect the flags for this label */ + LC->StmtFlags = SF_Any (LC->StmtFlags) | (StmtFlags & ~SF_EMPTY); + + /* If the new statement contains a "break", mark the label code as + ** "breaking". + */ + if (SF_Any_Break (StmtFlags)) { + LC->Breaks = 1; + } + + /* If the new statement makes the following ones unreachable, remove + ** the label from the active ones. + */ + if (SF_Unreach (StmtFlags)) { + CollDelete (&S->ActiveLabels, I); } } diff --git a/test/misc/Makefile b/test/misc/Makefile index a595d82a9..089159cfd 100644 --- a/test/misc/Makefile +++ b/test/misc/Makefile @@ -157,6 +157,11 @@ $(WORKDIR)/flow-do-01.$1.$2.prg: flow-do-01.c $(ISEQUAL) | $(WORKDIR) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLOUT) 2>$(WORKDIR)/flow-do-01.$1.$2.out $(ISEQUAL) $(WORKDIR)/flow-do-01.$1.$2.out flow-do-01.ref +$(WORKDIR)/flow-for-01.$1.$2.prg: flow-for-01.c $(ISEQUAL) | $(WORKDIR) + $(if $(QUIET),echo misc/flow-for-01.$1.$2.prg) + $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLOUT) 2>$(WORKDIR)/flow-for-01.$1.$2.out + $(ISEQUAL) $(WORKDIR)/flow-for-01.$1.$2.out flow-for-01.ref + $(WORKDIR)/flow-if-01.$1.$2.prg: flow-if-01.c $(ISEQUAL) | $(WORKDIR) $(if $(QUIET),echo misc/flow-if-01.$1.$2.prg) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLOUT) 2>$(WORKDIR)/flow-if-01.$1.$2.out @@ -172,6 +177,11 @@ $(WORKDIR)/flow-switch-01.$1.$2.prg: flow-switch-01.c $(ISEQUAL) | $(WORKDIR) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLOUT) 2>$(WORKDIR)/flow-switch-01.$1.$2.out $(ISEQUAL) $(WORKDIR)/flow-switch-01.$1.$2.out flow-switch-01.ref +$(WORKDIR)/flow-switch-02.$1.$2.prg: flow-switch-02.c $(ISEQUAL) | $(WORKDIR) + $(if $(QUIET),echo misc/flow-switch-02.$1.$2.prg) + $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLOUT) 2>$(WORKDIR)/flow-switch-02.$1.$2.out + $(ISEQUAL) $(WORKDIR)/flow-switch-02.$1.$2.out flow-switch-02.ref + $(WORKDIR)/flow-while-01.$1.$2.prg: flow-while-01.c $(ISEQUAL) | $(WORKDIR) $(if $(QUIET),echo misc/flow-while-01.$1.$2.prg) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLOUT) 2>$(WORKDIR)/flow-while-01.$1.$2.out diff --git a/test/misc/flow-for-01.c b/test/misc/flow-for-01.c new file mode 100644 index 000000000..ace6269d6 --- /dev/null +++ b/test/misc/flow-for-01.c @@ -0,0 +1,90 @@ +int a; + +static int f1(void) +{ + for (;;) { + ++a; + } + /* Unreachable */ + a = 2; + return a; +} + +static int f2(void) +{ + for (;1;) { + ++a; + } + /* Unreachable */ + a = 2; + return a; +} + +static int f3(void) +{ + for (;;) { + ++a; + if (a == 5) break; + } + /* Reachable */ + a = 2; + return a; +} + +static int f4(void) +{ + for (;;) { + ++a; + return a; + } + /* Unreachable */ + a = 2; +} + +static int f5(void) +{ + for (;0;) { + /* Unreachable */ + ++a; + return a; + } + /* Reachable */ + a = 2; + return 0; +} + +static int f6(void) +{ + for (;;) { + ++a; + if (a == 4) goto L; + return a; + } + /* Reachable via L */ +L: a = 2; +} + +static int f7(void) +{ + for (;0;) { + /* Unreachable but no warning */ + } + a = 2; + return a; +} + +static int f8(void) +{ + for (;a;) { + return a; + } + /* Reachable */ + a = 2; + return a; +} + +int main(void) +{ + return f1() + f2() + f3() + f4() + f5() + f6() + f7() + f8(); +} + diff --git a/test/misc/flow-for-01.ref b/test/misc/flow-for-01.ref new file mode 100644 index 000000000..4425066ac --- /dev/null +++ b/test/misc/flow-for-01.ref @@ -0,0 +1,4 @@ +flow-for-01.c:9: Warning: Unreachable code +flow-for-01.c:19: Warning: Unreachable code +flow-for-01.c:41: Warning: Unreachable code +flow-for-01.c:48: Warning: Unreachable code diff --git a/test/misc/flow-switch-01.c b/test/misc/flow-switch-01.c index b55c2f70f..1f478589f 100644 --- a/test/misc/flow-switch-01.c +++ b/test/misc/flow-switch-01.c @@ -44,7 +44,7 @@ static int f3(void) case 2: return a+1; default: return a+2; } - /* Unreachable but no warning */ + /* Unreachable */ return a; } @@ -58,11 +58,71 @@ static int f4(void) default: return a+2; } while (1); } - /* Unreachable but no warning */ + /* Unreachable */ return a; } +static int f5(void) +{ + do { + switch (a) { + case 1: return a; + case 2: ++a; continue; + default: return 1; + } + } while (0); + /* Unreachable */ + return 2; +} + +static int f6(void) +{ + do { +L: switch (a) { + case 1: return a; + case 2: ++a; goto L; + default: return 1; + } + } while (0); + /* Unreachable but no warning because of "goto" */ + return 2; +} + +static int f7(void) +{ + do { + switch (a) { + /* Unreachable */ + a = 3; + case 1: return a; + case 2: ++a; continue; + default: return 1; + } + } while (0); + /* Unreachable but no warning because of weird switch */ + return 2; +} + +static void duff(char* to, char* from, unsigned count) +{ + unsigned n = (count+7)/8; + switch (count%8) { + case 0: do { *to = *from++; + case 7: *to = *from++; + case 6: *to = *from++; + case 5: *to = *from++; + case 4: *to = *from++; + case 3: *to = *from++; + case 2: *to = *from++; + case 1: *to = *from++; + } while (--n>0); + } +} + int main(void) { - return f1() + f2() + f3() + f4(); + char x[11]; + char y[11]; + duff(x, y, 11); + return f1() + f2() + f3() + f4() + f5() + f6() + f7(); } diff --git a/test/misc/flow-switch-01.ref b/test/misc/flow-switch-01.ref index 61391476b..3c9b372e4 100644 --- a/test/misc/flow-switch-01.ref +++ b/test/misc/flow-switch-01.ref @@ -1 +1,5 @@ flow-switch-01.c:7: Warning: Unreachable code +flow-switch-01.c:48: Warning: Unreachable code +flow-switch-01.c:62: Warning: Unreachable code +flow-switch-01.c:75: Warning: Unreachable code +flow-switch-01.c:96: Warning: Unreachable code diff --git a/test/misc/flow-switch-02.c b/test/misc/flow-switch-02.c new file mode 100644 index 000000000..f54a456b2 --- /dev/null +++ b/test/misc/flow-switch-02.c @@ -0,0 +1,107 @@ +char a, b; + +static int f1(void) +{ + switch (a) { + case 1: return 1; + case 0xFF: break; + default: return 2; + } + /* Reachable */ + return a; +} + +static int f2(void) +{ + switch (a) { + case 1: return 1; + case 0x100: break; /* Unreachable */ + default: return 2; + } + /* Unreachable despite the "break" above */ + return a; +} + +static int f3(void) +{ + + switch (a) { + case 1: + if (b > 128) { + a = 2; + break; + } else { + a = 1; + } + return a; + default: + return 2; + } + /* Reachable */ + return a; +} + +static int f4(void) +{ + + switch (a) { + case 1: + if (b > 255) { + /* Unreachable */ + a = 2; + break; + } else { + a = 1; + } + return a; + default: + return 2; + } + /* Unreachable despite the "break" above */ + return a; +} + +static int f5(void) +{ + + switch (a) { + case 1: + if (b >= 0) { + a = 2; + } else { + /* Unreachable */ + a = 1; + break; + } + return a; + default: + return 2; + } + /* Unreachable despite the "break" above */ + return a; +} + +static int f6(void) +{ + + switch (a) { + case 1: + while (0) { + /* Unreachable */ + if (b >= 128) { + a = 2; + break; + } + } + return a; + default: + return 2; + } + /* Unreachable despite the "break" above */ + return a; +} + +int main(void) +{ + return f1() + f2() + f3() + f4() + f5() + f6(); +} diff --git a/test/misc/flow-switch-02.ref b/test/misc/flow-switch-02.ref new file mode 100644 index 000000000..1012c9b42 --- /dev/null +++ b/test/misc/flow-switch-02.ref @@ -0,0 +1,10 @@ +flow-switch-02.c:18: Warning: Case value (256) out of range for switch condition type +flow-switch-02.c:22: Warning: Unreachable code +flow-switch-02.c:49: Warning: Result of comparison is always false +flow-switch-02.c:51: Warning: Unreachable code +flow-switch-02.c:61: Warning: Unreachable code +flow-switch-02.c:69: Warning: Result of comparison is always true +flow-switch-02.c:73: Warning: Unreachable code +flow-switch-02.c:81: Warning: Unreachable code +flow-switch-02.c:91: Warning: Unreachable code +flow-switch-02.c:101: Warning: Unreachable code diff --git a/test/misc/flow-while-01.c b/test/misc/flow-while-01.c index 91d1454a9..3c354942c 100644 --- a/test/misc/flow-while-01.c +++ b/test/misc/flow-while-01.c @@ -63,8 +63,18 @@ static int f6(void) return a; } -int main(void) +static int f7(void) { - return f1() + f2() + f3() + f4() + f5() + f6(); + while (a) { + return a; + } + /* Reachable */ + a = 2; + return a; +} + +int main(void) +{ + return f1() + f2() + f3() + f4() + f5() + f6() + f7(); } diff --git a/test/misc/flow-while-02.c b/test/misc/flow-while-02.c index 11ea2c0c4..17f835005 100644 --- a/test/misc/flow-while-02.c +++ b/test/misc/flow-while-02.c @@ -22,7 +22,7 @@ static int f2(void) /* Unreachable */ break; } - /* Unreachable but no warning */ + /* Unreachable */ a = 2; return a; } diff --git a/test/misc/flow-while-02.ref b/test/misc/flow-while-02.ref index 2609f395a..ad5587257 100644 --- a/test/misc/flow-while-02.ref +++ b/test/misc/flow-while-02.ref @@ -1,6 +1,7 @@ flow-while-02.c:8: Warning: Unreachable code flow-while-02.c:12: Warning: Unreachable code flow-while-02.c:23: Warning: Unreachable code +flow-while-02.c:26: Warning: Unreachable code flow-while-02.c:38: Warning: Unreachable code flow-while-02.c:50: Warning: Unreachable code flow-while-02.c:66: Warning: Unreachable code diff --git a/test/misc/goto.ref b/test/misc/goto.ref index d1fd3a793..685287249 100644 --- a/test/misc/goto.ref +++ b/test/misc/goto.ref @@ -5,8 +5,11 @@ goto.c:38: Warning: Unreachable code goto.c:59: Warning: Unreachable code goto.c:80: Warning: Unreachable code goto.c:97: Warning: Variable 'a' is defined but never used +goto.c:100: Warning: Unreachable code goto.c:117: Warning: Variable 'a' is defined but never used +goto.c:120: Warning: Unreachable code goto.c:137: Warning: Variable 'a' is defined but never used +goto.c:140: Warning: Unreachable code goto.c:159: Warning: Goto at line 23 to label l8 jumps into a block with initialization of an object that has automatic storage duration goto.c:159: Warning: Goto at line 44 to label l8 jumps into a block with initialization of an object that has automatic storage duration goto.c:159: Warning: Goto at line 65 to label l8 jumps into a block with initialization of an object that has automatic storage duration @@ -42,6 +45,7 @@ goto.c:221: Warning: Goto at line 109 to label lb jumps into a block with initia goto.c:221: Warning: Goto at line 129 to label lb jumps into a block with initialization of an object that has automatic storage duration goto.c:221: Warning: Goto at line 149 to label lb jumps into a block with initialization of an object that has automatic storage duration goto.c:221: Warning: Goto at line 170 to label lb jumps into a block with initialization of an object that has automatic storage duration +goto.c:223: Warning: Unreachable code goto.c:231: Warning: Goto at line 231 to label la jumps into a block with initialization of an object that has automatic storage duration goto.c:241: Warning: Goto at line 27 to label lc jumps into a block with initialization of an object that has automatic storage duration goto.c:241: Warning: Goto at line 48 to label lc jumps into a block with initialization of an object that has automatic storage duration @@ -50,6 +54,7 @@ goto.c:241: Warning: Goto at line 90 to label lc jumps into a block with initial goto.c:241: Warning: Goto at line 110 to label lc jumps into a block with initialization of an object that has automatic storage duration goto.c:241: Warning: Goto at line 130 to label lc jumps into a block with initialization of an object that has automatic storage duration goto.c:241: Warning: Goto at line 150 to label lc jumps into a block with initialization of an object that has automatic storage duration +goto.c:243: Warning: Unreachable code goto.c:250: Warning: Goto at line 250 to label l9 jumps into a block with initialization of an object that has automatic storage duration goto.c:251: Warning: Goto at line 251 to label la jumps into a block with initialization of an object that has automatic storage duration goto.c:252: Warning: Goto at line 252 to label lb jumps into a block with initialization of an object that has automatic storage duration @@ -123,6 +128,7 @@ goto.c:325: Warning: Goto at line 217 to label lg jumps into a block with initia goto.c:325: Warning: Goto at line 237 to label lg jumps into a block with initialization of an object that has automatic storage duration goto.c:325: Warning: Goto at line 257 to label lg jumps into a block with initialization of an object that has automatic storage duration goto.c:325: Warning: Goto at line 279 to label lg jumps into a block with initialization of an object that has automatic storage duration +goto.c:327: Warning: Unreachable code goto.c:333: Warning: Goto at line 333 to label l8 jumps into a block with initialization of an object that has automatic storage duration goto.c:334: Warning: Goto at line 334 to label l9 jumps into a block with initialization of an object that has automatic storage duration goto.c:335: Warning: Goto at line 335 to label la jumps into a block with initialization of an object that has automatic storage duration @@ -141,6 +147,7 @@ goto.c:345: Warning: Goto at line 197 to label lh jumps into a block with initia goto.c:345: Warning: Goto at line 218 to label lh jumps into a block with initialization of an object that has automatic storage duration goto.c:345: Warning: Goto at line 238 to label lh jumps into a block with initialization of an object that has automatic storage duration goto.c:345: Warning: Goto at line 258 to label lh jumps into a block with initialization of an object that has automatic storage duration +goto.c:347: Warning: Unreachable code goto.c:353: Warning: Goto at line 353 to label l8 jumps into a block with initialization of an object that has automatic storage duration goto.c:354: Warning: Goto at line 354 to label l9 jumps into a block with initialization of an object that has automatic storage duration goto.c:355: Warning: Goto at line 355 to label la jumps into a block with initialization of an object that has automatic storage duration @@ -149,6 +156,7 @@ goto.c:357: Warning: Goto at line 357 to label lc jumps into a block with initia goto.c:359: Warning: Goto at line 359 to label le jumps into a block with initialization of an object that has automatic storage duration goto.c:360: Warning: Goto at line 360 to label lf jumps into a block with initialization of an object that has automatic storage duration goto.c:361: Warning: Goto at line 361 to label lg jumps into a block with initialization of an object that has automatic storage duration +goto.c:367: Warning: Unreachable code goto.c:373: Warning: Goto at line 373 to label l8 jumps into a block with initialization of an object that has automatic storage duration goto.c:374: Warning: Goto at line 374 to label l9 jumps into a block with initialization of an object that has automatic storage duration goto.c:375: Warning: Goto at line 375 to label la jumps into a block with initialization of an object that has automatic storage duration