From c5fe0eaa17c8f76f792da1cb93ae810e562d768f Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 1 Dec 2020 17:04:45 -0800 Subject: [PATCH] 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. --- tools/binpac/src/pac_expr.cc | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/tools/binpac/src/pac_expr.cc b/tools/binpac/src/pac_expr.cc index 4062525a57..066f279ecd 100644 --- a/tools/binpac/src/pac_expr.cc +++ b/tools/binpac/src/pac_expr.cc @@ -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;