Fix type deduction for certain cases

Fix type deduction for certain cases involving C-style casts, or
which are syntactically like a C-style cast applied to an unary
operator, such as: (7)*6

See #2796
This commit is contained in:
Olly Betts 2024-02-13 17:05:55 +13:00
parent a93d1b8b2f
commit 4dc621d804
7 changed files with 92 additions and 4 deletions

View File

@ -7,6 +7,11 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.2.1 (in progress)
===========================
2024-02-13: olly
Fix type deduction for certain cases involving C-style casts, or
which are syntactically like a C-style cast applied to an unary
operator, such as: (7)*6
2024-02-13: olly
#2796 Fix handling of enum initialised by expression including a
cast to a typedef-ed type. Regression introduced in 4.2.0.

View File

@ -58,6 +58,11 @@
decltype(~'x') should_be_int3;
decltype(int(0)) should_be_int4;
decltype((int)0.0) should_be_int5;
decltype((6)-7) should_be_int6;
decltype((6)+7) should_be_int7;
decltype((6)*7) should_be_int8;
decltype((6)&7) should_be_int9;
static constexpr decltype(*"abc") should_be_char = 0;

View File

@ -85,5 +85,9 @@ enum Enum2796
CASE3A = (unknown_to_swig_type)10,
CASE3B = unknown_to_swig_type(10),
CASE3C = static_cast<unknown_to_swig_type>(10),
CASE4A = (5)*2,
CASE4B = (14)&11,
CASE4C = (3)+7,
CASE4D = (42)-32,
};
%}

View File

@ -44,6 +44,11 @@ check::equal(gettype($b->should_be_int), "integer");
check::equal(gettype($b->should_be_int2), "integer");
check::equal(gettype($b->should_be_int3), "integer");
check::equal(gettype($b->should_be_int4), "integer");
check::equal(gettype($b->should_be_int5), "integer");
check::equal(gettype($b->should_be_int6), "integer");
check::equal(gettype($b->should_be_int7), "integer");
check::equal(gettype($b->should_be_int8), "integer");
check::equal(gettype($b->should_be_int9), "integer");
check::equal(gettype($b->should_be_bool), "boolean");

View File

@ -35,5 +35,9 @@ check::equal(CASE2C, 10);
check::equal(CASE3A, 10);
check::equal(CASE3B, 10);
check::equal(CASE3C, 10);
check::equal(CASE4A, 10);
check::equal(CASE4B, 10);
check::equal(CASE4C, 10);
check::equal(CASE4D, 10);
check::done();

View File

@ -643,6 +643,7 @@ int yylex(void) {
case NUM_BOOL:
yylval.dtype.type = T_BOOL;
num_common:
yylval.dtype.unary_arg_type = 0;
yylval.dtype.val = NewString(Scanner_text(scan));
yylval.dtype.bitfield = 0;
yylval.dtype.throws = 0;

View File

@ -1608,6 +1608,11 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
String *val;
String *rawval;
int type;
/* The type code for the argument when the top level operator is unary.
* This is useful because our grammar parses cases such as (7)*6 as a
* cast applied to an unary operator.
*/
int unary_arg_type;
String *qualifier;
String *refqualifier;
String *bitfield;
@ -5263,7 +5268,8 @@ def_args : EQUAL definetype {
if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
$$.val = NewString(scanner_ccode);
$$.rawval = 0;
$$.type = T_UNKNOWN;
$$.type = T_UNKNOWN;
$$.unary_arg_type = 0;
$$.bitfield = 0;
$$.throws = 0;
$$.throwf = 0;
@ -5284,6 +5290,7 @@ def_args : EQUAL definetype {
$$.val = 0;
$$.rawval = 0;
$$.type = T_UNKNOWN;
$$.unary_arg_type = 0;
$$.bitfield = 0;
$$.throws = 0;
$$.throwf = 0;
@ -6370,6 +6377,7 @@ deleted_definition : DELETE_KW {
$$.val = NewString("delete");
$$.rawval = 0;
$$.type = T_STRING;
$$.unary_arg_type = 0;
$$.qualifier = 0;
$$.refqualifier = 0;
$$.bitfield = 0;
@ -6385,6 +6393,7 @@ explicit_default : DEFAULT {
$$.val = NewString("default");
$$.rawval = 0;
$$.type = T_STRING;
$$.unary_arg_type = 0;
$$.qualifier = 0;
$$.refqualifier = 0;
$$.bitfield = 0;
@ -6524,6 +6533,7 @@ expr : valexpr
Node *n;
$$.val = $1;
$$.type = T_UNKNOWN;
$$.unary_arg_type = 0;
/* Check if value is in scope */
n = Swig_symbol_clookup($1,0);
if (n) {
@ -6585,16 +6595,19 @@ exprsimple : exprnum
| string {
$$.val = $1;
$$.type = T_STRING;
$$.unary_arg_type = 0;
}
| SIZEOF LPAREN type parameter_declarator RPAREN {
SwigType_push($3,$4.type);
$$.val = NewStringf("sizeof(%s)",SwigType_str($3,0));
$$.type = T_ULONG;
$$.unary_arg_type = 0;
}
| SIZEOF ELLIPSIS LPAREN type parameter_declarator RPAREN {
SwigType_push($4,$5.type);
$$.val = NewStringf("sizeof...(%s)",SwigType_str($4,0));
$$.type = T_ULONG;
$$.unary_arg_type = 0;
}
/* We don't support all valid expressions here currently - e.g.
* sizeof(<unaryop> x) doesn't work - but those are unlikely to
@ -6605,7 +6618,8 @@ exprsimple : exprnum
*/
| SIZEOF LPAREN exprsimple RPAREN {
$$.val = NewStringf("sizeof(%s)", $3.val);
$$.type = T_ULONG;
$$.type = T_ULONG;
$$.unary_arg_type = 0;
}
/* `sizeof expr` without parentheses is valid for an expression,
* but not for a type. This doesn't support `sizeof x` in
@ -6614,11 +6628,13 @@ exprsimple : exprnum
| SIZEOF exprsimple {
$$.val = NewStringf("sizeof(%s)", $2.val);
$$.type = T_ULONG;
$$.unary_arg_type = 0;
}
| wstring {
$$.val = $1;
$$.rawval = NewStringf("L\"%s\"", $$.val);
$$.type = T_WSTRING;
$$.unary_arg_type = 0;
}
| CHARCONST {
$$.val = NewString($1);
@ -6628,6 +6644,7 @@ exprsimple : exprnum
$$.rawval = NewString("'\\0'");
}
$$.type = T_CHAR;
$$.unary_arg_type = 0;
$$.bitfield = 0;
$$.throws = 0;
$$.throwf = 0;
@ -6642,6 +6659,7 @@ exprsimple : exprnum
$$.rawval = NewString("L'\\0'");
}
$$.type = T_WCHAR;
$$.unary_arg_type = 0;
$$.bitfield = 0;
$$.throws = 0;
$$.throwf = 0;
@ -6666,7 +6684,9 @@ valexpr : exprsimple
/* A few common casting operations */
| LPAREN expr RPAREN expr %prec CAST {
$$ = $4;
int cast_type_code = SwigType_type($2.val);
$$ = $4;
$$.unary_arg_type = 0;
if ($4.type != T_STRING) {
switch ($2.type) {
case T_FLOAT:
@ -6681,10 +6701,28 @@ valexpr : exprsimple
break;
}
}
$$.type = promote($2.type, $4.type);
/* As well as C-style casts, this grammar rule currently also
* matches a binary operator with a LHS in parentheses for
* binary operators which also have an unary form, e.g.:
*
* (6)*7
* (6)&7
* (6)+7
* (6)-7
*/
if (cast_type_code != T_USER && cast_type_code != T_UNKNOWN) {
/* $2 is definitely a type so we know this is a cast. */
$$.type = cast_type_code;
} else if ($4.type == 0 || $4.unary_arg_type == 0) {
/* Not one of the cases above, so we know this is a cast. */
$$.type = cast_type_code;
} else {
$$.type = promote($2.type, $4.unary_arg_type);
}
}
| LPAREN expr pointer RPAREN expr %prec CAST {
$$ = $5;
$$.unary_arg_type = 0;
if ($5.type != T_STRING) {
SwigType_push($2.val,$3);
$$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $5.val);
@ -6692,6 +6730,7 @@ valexpr : exprsimple
}
| LPAREN expr AND RPAREN expr %prec CAST {
$$ = $5;
$$.unary_arg_type = 0;
if ($5.type != T_STRING) {
SwigType_add_reference($2.val);
$$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $5.val);
@ -6699,6 +6738,7 @@ valexpr : exprsimple
}
| LPAREN expr LAND RPAREN expr %prec CAST {
$$ = $5;
$$.unary_arg_type = 0;
if ($5.type != T_STRING) {
SwigType_add_rvalue_reference($2.val);
$$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $5.val);
@ -6706,6 +6746,7 @@ valexpr : exprsimple
}
| LPAREN expr pointer AND RPAREN expr %prec CAST {
$$ = $6;
$$.unary_arg_type = 0;
if ($6.type != T_STRING) {
SwigType_push($2.val,$3);
SwigType_add_reference($2.val);
@ -6714,6 +6755,7 @@ valexpr : exprsimple
}
| LPAREN expr pointer LAND RPAREN expr %prec CAST {
$$ = $6;
$$.unary_arg_type = 0;
if ($6.type != T_STRING) {
SwigType_push($2.val,$3);
SwigType_add_rvalue_reference($2.val);
@ -6724,6 +6766,11 @@ valexpr : exprsimple
$$ = $2;
$$.val = NewStringf("&%s", $2.val);
$$.rawval = 0;
/* Record the type code for expr so we can properly handle
* cases such as (6)&7 which get parsed using this rule then
* the rule for a C-style cast.
*/
$$.unary_arg_type = $2.type;
switch ($$.type) {
case T_CHAR:
$$.type = T_STRING;
@ -6739,6 +6786,11 @@ valexpr : exprsimple
$$ = $2;
$$.val = NewStringf("*%s", $2.val);
$$.rawval = 0;
/* Record the type code for expr so we can properly handle
* cases such as (6)*7 which get parsed using this rule then
* the rule for a C-style cast.
*/
$$.unary_arg_type = $2.type;
switch ($$.type) {
case T_STRING:
$$.type = T_CHAR;
@ -6858,6 +6910,7 @@ exprcompound : expr PLUS expr {
* better than it deducing the wrong type).
*/
$$.type = T_USER;
$$.unary_arg_type = 0;
}
| expr QUESTIONMARK expr COLON expr %prec QUESTIONMARK {
$$.val = NewStringf("%s?%s:%s", COMPOUND_EXPR_VAL($1), COMPOUND_EXPR_VAL($3), COMPOUND_EXPR_VAL($5));
@ -6868,10 +6921,20 @@ exprcompound : expr PLUS expr {
| MINUS expr %prec UMINUS {
$$.val = NewStringf("-%s",$2.val);
$$.type = promote_type($2.type);
/* Record the type code for expr so we can properly handle
* cases such as (6)-7 which get parsed using this rule then
* the rule for a C-style cast.
*/
$$.unary_arg_type = $2.type;
}
| PLUS expr %prec UMINUS {
$$.val = NewStringf("+%s",$2.val);
$$.type = promote_type($2.type);
/* Record the type code for expr so we can properly handle
* cases such as (6)+7 which get parsed using this rule then
* the rule for a C-style cast.
*/
$$.unary_arg_type = $2.type;
}
| NOT expr {
$$.val = NewStringf("~%s",$2.val);
@ -6901,6 +6964,7 @@ exprcompound : expr PLUS expr {
// overloaded forms).
$$.type = SwigType_type(qty);
if ($$.type == T_USER) $$.type = T_UNKNOWN;
$$.unary_arg_type = 0;
Delete(qty);
}
;