binpac: GH-14: Use larger temporary storage for evaluating case-expressions

For example:

    inum: uint32 = case (ed & 0x0f) of {
        0x00    -> n_8;  # n_8 is a uint8
        0x01    -> n_16; # n_16 is a uint16
        0x02    -> n_32; # n_32 is a uint32
        default -> 0;
    };

Previously, the temporary storage used for evaluating the
case-expression was based on whatever type the first case yields, which
is a uint8 in the above example.  That behavior can lead to a narrowing
conversion whenever the 0x01 or 0x02 cases occur.

The new behavior is to base the temporary storage's type on the largest
numeric type that the case-expression can yield, which is uint32 in the
above example.
This commit is contained in:
Jon Siwek 2020-12-01 17:04:45 -08:00 committed by Tim Wojtulewicz
parent 11b6feb18b
commit c5fe0eaa17

View file

@ -528,6 +528,8 @@ Type *Expr::DataType(Env *env) const
{
Type *type1 =
cases_->front()->value()->DataType(env);
Type* numeric_with_largest_width = 0;
foreach(i, CaseExprList, cases_)
{
Type *type2 =
@ -541,8 +543,34 @@ Type *Expr::DataType(Env *env) const
}
if ( type1 == extern_type_nullptr )
type1 = type2;
if ( type2 && type2->IsNumericType() )
{
if ( numeric_with_largest_width )
{
int largest;
int contender;
// External C++ types like "int", "bool", "enum" use "int"
// storage internally.
if ( numeric_with_largest_width->tot() == Type::EXTERN )
largest = sizeof(int);
else
largest = numeric_with_largest_width->StaticSize(env);
if ( type2->tot() == Type::EXTERN )
contender = sizeof(int);
else
contender = type2->StaticSize(env);
if ( contender > largest )
numeric_with_largest_width = type2;
}
else
numeric_with_largest_width = type2;
}
}
data_type = type1;
data_type = numeric_with_largest_width ? numeric_with_largest_width : type1;
}
else
data_type = 0;