Merge pull request #2819 from kugelfuhr/kugelfuhr/improved-flowanalysis

Improved flowanalysis for cc65
This commit is contained in:
Bob Andrews
2025-07-26 23:37:49 +02:00
committed by GitHub
14 changed files with 564 additions and 90 deletions

View File

@@ -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:

View File

@@ -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);
}
/*****************************************************************************/

View File

@@ -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);
}
}

View File

@@ -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

90
test/misc/flow-for-01.c Normal file
View File

@@ -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();
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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

107
test/misc/flow-switch-02.c Normal file
View File

@@ -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();
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -22,7 +22,7 @@ static int f2(void)
/* Unreachable */
break;
}
/* Unreachable but no warning */
/* Unreachable */
a = 2;
return a;
}

View File

@@ -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

View File

@@ -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