Second question first:
How do I make the code MISRA C:2004 compliant?
You can write this in a MISRA-compliant manner as follows:
typedef unsigned int UNS_32;
UNS_32 test(void);
UNS_32 test(void)
{
UNS_32 original_arg = 3U;
UNS_32 irq_source = 1UL << original_arg;
return irq_source;
}
Back to the first question:
What is really going on here?
First Rule 10.3 says that complex integer expressions shall not be cast to a type wider than the underlying type.
One key to understanding the error message is the concept underlying type, which is a MISRA-C specific concept. In short, the underlying type of a constant is the smallest type that it can fit into. In this case 1U
has the underlying type unsigned char
despite it having the language type unsigned int
.
The rationale behind the 10.3 rule is to avoid cases where the result of an operation is used in a context which is larger than the parts. The standard example of this is multiplication, where alpha
and beta
are 16 bit types:
uint32_t res = alpha * beta;
Here, if int
is 16 bits, the multiplication will be performed in 16 bits, the result will then be converted to 32 bits. On the other hand, if int
is 32 bits or larger, the multiplication will be performed in the larger precision. Concretely, this will make the result different when multiplying, say, 0x4000 and 0x10.
MISRA rule 10.3 solved this by enforcing that the cast result is placed in a temporary, which is later cast to the larger type. That way you are forced to write code one way or the other.
If the intention is to use a 16-bit multiplication:
uint16_t tmp = alpha * beta;
uint32_t res = tmp;
On the other hand, if the intention is a 32-bit multiplication:
UNS_32 res = (UNS_32)alpha * (UNS_32)beta;
So, in this case, the expression 1U << count
is the potential problem. If converted_arg
is larger than 16 bits, this could lead to a problem when using 16-bit int
s. MISRA does allow you, however, to write 1UL << count
or (UNS_32)((UNS_32)1U << original_arg)
. You mentioned that the MISRA checker issued an error in the latter case -- mine does not so please check again.
So, the way I see it, the MISRA C checker you used correctly identified a violation to rule 10.3.
1U
has the MISRA underlying typeunsigned char
. Having said that, I don't see why the compiler should issue a warning here -- I'll look into it when I got to work next week... – Brescia