This rule is part of MISRA C++:2023.
Usage of this content is governed by Sonar’s terms and conditions. Redistribution is
prohibited.
Rule 9.4.2 - The structure of a switch statement shall be appropriate
[stmt.switch]
[dcl.attr.fallthrough]
Category: Required
Analysis: Decidable,Single Translation Unit
Amplification
The substatement of a switch statement is called the switch body. It shall be a compound statement.
A labeled statement, along with the complete chain of its substatements that are also labeled statements, is called a label
group. A label group that is directly enclosed by a switch body is called a switch label group.
The statements directly enclosed by a switch body are partitioned into switch branches, with each switch label group
starting a new branch.
A switch statement is structured appropriately when it conforms to the following restrictions:
- The condition shall only be preceded by an optional simple-declaration;
-
case or default labeled statements shall only appear as part of a switch label group;
- Switch label groups shall only contain
case or default labeled statements;
- The first statement in a switch body shall be a switch label group;
- Every switch branch shall be unconditionally terminated by either:
- A
break statement; or
- A
continue statement; or
- A
return statement; or
- A
goto statement; or
- A
throw expression; or
- A call to a
[[noreturn]] function; or
- A
[[fallthrough]] attribute applied to a null statement.
- Every
switch statement shall have at least two switch branches;
- Every
switch statement shall have a default label, appearing as either the first label of the first switch label
group or as the last label of the last switch label group.
Rationale
The syntax for the switch statement can be used to create complex, unstructured code. This rule places restrictions on the use of the
switch statement in order to impose a simple and consistent structure:
- A simple-declaration is permitted before the condition as it allows the declaration of a variable with restricted scope
within a
switch statement. An expression-statement is not permitted as the init-statement, as it introduces
complexity without any extra benefit.
- The C++ Standard permits a
case label or default label to be placed before any statement contained within the body of
a switch statement, potentially leading to unstructured code. To prevent this, a case label or default label
is only permitted to appear at the outermost level of the compound statement forming the body of a switch statement.
- Including labels other than
case or default in a switch label group potentially allows unstructured control
flow to be introduced.
- A statement placed before a switch label group would either be an uninitialized variable or unreachable code.
- If a developer fails to terminate a switch branch, then control flow "falls" into the following switch branch or, if there is
no such branch, off the end and into the statement following the
switch statement. The requirement for unconditional termination
ensures that unintentional fall-throughs can be detected, with the [[fallthrough]] attribute being used to explicitly indicate when
fall-through is intentional. Note: fall-through that occurs between two consecutive case or default
labels having no intervening statements is not ambiguous, and is permitted by this rule.
- A
switch statement with a single switch branch is not permitted as it may be indicative of a programming error.
- The requirement for a
default label is defensive programming, complementing the requirement for if ... else if
constructs to be terminated with an else (see M23_112: MISRA C++ 2023 Rule 9.4.1). The addition of a
default, even when empty, indicates that consideration has been given regarding the behaviour when all other cases are not selected.
Placing the default as the first or last label makes it easier to locate during code review.
Note: even when the condition of a switch has enum type, listing all enumerators values in
case labels does not make the use of default redundant as the value could still lie outside of the set of enumerators.
Exception
If the condition of a switch statement is an unscoped enumeration type that does not have a fixed underlying
type, and all the enumerators are listed in case labels, then a default label is not required. Note:
compliance with M23_061: MISRA C++ 2023 Rule 10.2.3 ensures that an object of such a type cannot be assigned values outside of its set
of enumerators.
Example
The following switch statement has four switch branches:
switch ( int8_t x = f(); x ) // Compliant - declaration of x is simple
{
case 1:
{
break; // Compliant - branch unconditionally terminated
}
case 2:
case 3:
throw; // Compliant - branch unconditionally terminated
case 4:
a++;
[[fallthrough]]; // Compliant - branch has explicit fall-through
default: // Compliant - default is last label
b++;
return; // Compliant - branches unconditionally terminated
}
The following switch statement has four switch branches:
switch ( x = f(); x ) // Non-compliant - x = f() is not a simple-declaration
{
int32_t i; // Non-compliant - not a switch label group
case 5:
if ( ... )
{
break;
}
else
{
break;
}
// Non-compliant - termination is not unconditional
case 6:
a = b; // Non-compliant - non-empty, implicit fall-through
case 7:
{
case 8: // Non-compliant - case not in a switch label group
DoIt();
}
break;
} // Non-compliant - default is required
switch ( x ) // Non-compliant - only one switch branch
{
default:
; // Non-compliant - default must also be terminated
}
enum Colours { RED, GREEN, BLUE } colour;
switch ( colour )
{
case RED:
break;
case GREEN:
break;
} // Non-compliant - default is required
switch ( colour )
{
case RED:
case GREEN:
break;
case BLUE:
break;
} // Compliant by exception - all enumerators listed
switch ( colour ) // Non-compliant - only one switch branch
{
case RED:
default: // Non-compliant - default must be first or last label
case BLUE:
break;
}
Copyright The MISRA Consortium Limited © 2023