diff --git a/CHANGES.current b/CHANGES.current index 59257dc09..028adcf74 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,15 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-01-25: olly + #80 #635 https://sourceforge.net/p/swig/bugs/1139/ + Add support for parsing common cases of `<` and `>` comparisons + in constant expressions. Adding full support for these seems hard + to do without introducing conflicts into the parser grammar, but in + fact all reported cases have had parentheses around the comparison + and we can support that with a few restrictions on the left side of + `<`. + 2022-01-25: wsfulton New warning 327 for extern templates, eg: diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 5a44980cc..6574c4549 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -141,6 +141,7 @@ CPP_TEST_CASES += \ compactdefaultargs \ const_const_2 \ constant_directive \ + constant_expr \ constant_pointers \ constover \ constructor_copy \ @@ -689,7 +690,7 @@ C_TEST_CASES += \ c_delete_function \ char_constant \ const_const \ - constant_expr \ + constant_expr_c \ default_args_c \ empty_c \ enums \ diff --git a/Examples/test-suite/constant_expr.i b/Examples/test-suite/constant_expr.i index 8e5c8aee6..7cb529f8a 100644 --- a/Examples/test-suite/constant_expr.i +++ b/Examples/test-suite/constant_expr.i @@ -1,11 +1,17 @@ %module constant_expr; -/* Tests of constant expressions. */ +/* Tests of constant expressions (C++ version). */ + +%include "constant_expr_c.i" %inline %{ -/* % didn't work in SWIG 1.3.40 and earlier. */ -const int X = 123%7; -#define FOO 12 % 9 -double d_array[12 % 9]; +// Testcase from https://sourceforge.net/p/swig/bugs/1139/ +template +struct SizeInfo { +enum { +isLarge = (sizeof(Tp)>sizeof(void*)), +isPointer = false +}; +}; %} diff --git a/Examples/test-suite/constant_expr_c.i b/Examples/test-suite/constant_expr_c.i new file mode 100644 index 000000000..b7431c1f1 --- /dev/null +++ b/Examples/test-suite/constant_expr_c.i @@ -0,0 +1,35 @@ +%module constant_expr_c; +/* Tests of constant expressions (C version). */ + +%inline %{ + +/* % didn't work in SWIG 1.3.40 and earlier. */ +const int X = 123%7; +#define FOO 12 % 9 +double d_array[12 % 9]; + +/* `<` and `>` in constant expressions caused parse errors before SWIG 4.1.0. + * They're now supported if inside parentheses (and with some restrictions + * on the LHS of `<`. + */ + +// Testcase from https://github.com/swig/swig/issues/635 +#define TEST_A 1 +#define TEST_B 2 +#define TEST_C (TEST_A < TEST_B) +#define TEST_D (TEST_A > TEST_B) +// These have been supported since 1.3.41. +#define TEST_E (TEST_A <= TEST_B) +#define TEST_F (TEST_A >= TEST_B) +// For completeness +#define TEST_G (TEST_A == TEST_B) +#define TEST_H (TEST_A != TEST_B) + +// No warning +#if (TEST_A < TEST_B) +#define TEST_I 1 +#else +#define TEST_I 0 +#endif + +%} diff --git a/Examples/test-suite/csharp/preproc_constants_c_runme.cs b/Examples/test-suite/csharp/preproc_constants_c_runme.cs index 5966d5266..8cdb705c9 100644 --- a/Examples/test-suite/csharp/preproc_constants_c_runme.cs +++ b/Examples/test-suite/csharp/preproc_constants_c_runme.cs @@ -51,6 +51,8 @@ public class runme { assert( typeof(int) == preproc_constants_c.EXPR_MINUS.GetType() ); assert( typeof(int) == preproc_constants_c.EXPR_LSHIFT.GetType() ); assert( typeof(int) == preproc_constants_c.EXPR_RSHIFT.GetType() ); + assert( typeof(int) == preproc_constants_c.EXPR_LT.GetType() ); + assert( typeof(int) == preproc_constants_c.EXPR_GT.GetType() ); assert( typeof(int) == preproc_constants_c.EXPR_LTE.GetType() ); assert( typeof(int) == preproc_constants_c.EXPR_GTE.GetType() ); assert( typeof(int) == preproc_constants_c.EXPR_INEQUALITY.GetType() ); diff --git a/Examples/test-suite/csharp/preproc_constants_runme.cs b/Examples/test-suite/csharp/preproc_constants_runme.cs index 6af8f20a4..d79e2c302 100644 --- a/Examples/test-suite/csharp/preproc_constants_runme.cs +++ b/Examples/test-suite/csharp/preproc_constants_runme.cs @@ -50,6 +50,8 @@ public class runme { assert( typeof(int) == preproc_constants.EXPR_MINUS.GetType() ); assert( typeof(int) == preproc_constants.EXPR_LSHIFT.GetType() ); assert( typeof(int) == preproc_constants.EXPR_RSHIFT.GetType() ); + assert( typeof(bool) == preproc_constants.EXPR_LT.GetType() ); + assert( typeof(bool) == preproc_constants.EXPR_GT.GetType() ); assert( typeof(bool) == preproc_constants.EXPR_LTE.GetType() ); assert( typeof(bool) == preproc_constants.EXPR_GTE.GetType() ); assert( typeof(bool) == preproc_constants.EXPR_INEQUALITY.GetType() ); diff --git a/Examples/test-suite/d/preproc_constants_c_runme.1.d b/Examples/test-suite/d/preproc_constants_c_runme.1.d index a6c2f3d10..f98f37b5f 100644 --- a/Examples/test-suite/d/preproc_constants_c_runme.1.d +++ b/Examples/test-suite/d/preproc_constants_c_runme.1.d @@ -51,6 +51,8 @@ void main() { static assert(is(int == typeof(EXPR_MINUS()))); static assert(is(int == typeof(EXPR_LSHIFT()))); static assert(is(int == typeof(EXPR_RSHIFT()))); + static assert(is(int == typeof(EXPR_LT()))); + static assert(is(int == typeof(EXPR_GT()))); static assert(is(int == typeof(EXPR_LTE()))); static assert(is(int == typeof(EXPR_GTE()))); static assert(is(int == typeof(EXPR_INEQUALITY()))); diff --git a/Examples/test-suite/d/preproc_constants_c_runme.2.d b/Examples/test-suite/d/preproc_constants_c_runme.2.d index 786cb48cc..caf3029b2 100644 --- a/Examples/test-suite/d/preproc_constants_c_runme.2.d +++ b/Examples/test-suite/d/preproc_constants_c_runme.2.d @@ -51,6 +51,8 @@ void main() { static assert(is(int == typeof(EXPR_MINUS()))); static assert(is(int == typeof(EXPR_LSHIFT()))); static assert(is(int == typeof(EXPR_RSHIFT()))); + static assert(is(int == typeof(EXPR_LT()))); + static assert(is(int == typeof(EXPR_GT()))); static assert(is(int == typeof(EXPR_LTE()))); static assert(is(int == typeof(EXPR_GTE()))); static assert(is(int == typeof(EXPR_INEQUALITY()))); diff --git a/Examples/test-suite/d/preproc_constants_runme.1.d b/Examples/test-suite/d/preproc_constants_runme.1.d index 85fa918e4..95f3c4757 100644 --- a/Examples/test-suite/d/preproc_constants_runme.1.d +++ b/Examples/test-suite/d/preproc_constants_runme.1.d @@ -50,6 +50,8 @@ void main() { static assert(is(int == typeof(EXPR_MINUS()))); static assert(is(int == typeof(EXPR_LSHIFT()))); static assert(is(int == typeof(EXPR_RSHIFT()))); + static assert(is(int == typeof(EXPR_LT()))); + static assert(is(int == typeof(EXPR_GT()))); static assert(is(bool == typeof(EXPR_LTE()))); static assert(is(bool == typeof(EXPR_GTE()))); static assert(is(bool == typeof(EXPR_INEQUALITY()))); diff --git a/Examples/test-suite/d/preproc_constants_runme.2.d b/Examples/test-suite/d/preproc_constants_runme.2.d index c81e53160..416384a11 100644 --- a/Examples/test-suite/d/preproc_constants_runme.2.d +++ b/Examples/test-suite/d/preproc_constants_runme.2.d @@ -50,6 +50,8 @@ void main() { static assert(is(int == typeof(EXPR_MINUS()))); static assert(is(int == typeof(EXPR_LSHIFT()))); static assert(is(int == typeof(EXPR_RSHIFT()))); + static assert(is(bool == typeof(EXPR_LT()))); + static assert(is(bool == typeof(EXPR_GT()))); static assert(is(bool == typeof(EXPR_LTE()))); static assert(is(bool == typeof(EXPR_GTE()))); static assert(is(bool == typeof(EXPR_INEQUALITY()))); diff --git a/Examples/test-suite/php/preproc_constants_c_runme.php b/Examples/test-suite/php/preproc_constants_c_runme.php index 411f7d766..688da52f6 100644 --- a/Examples/test-suite/php/preproc_constants_c_runme.php +++ b/Examples/test-suite/php/preproc_constants_c_runme.php @@ -51,6 +51,8 @@ check::equal(gettype(preproc_constants_c::EXPR_PLUS), "integer", "preproc_consta check::equal(gettype(preproc_constants_c::EXPR_MINUS), "integer", "preproc_constants.EXPR_MINUS has unexpected type"); check::equal(gettype(preproc_constants_c::EXPR_LSHIFT), "integer", "preproc_constants.EXPR_LSHIFT has unexpected type"); check::equal(gettype(preproc_constants_c::EXPR_RSHIFT), "integer", "preproc_constants.EXPR_RSHIFT has unexpected type"); +check::equal(gettype(preproc_constants_c::EXPR_LT), "integer", "preproc_constants.EXPR_LTE has unexpected type"); +check::equal(gettype(preproc_constants_c::EXPR_GT), "integer", "preproc_constants.EXPR_GTE has unexpected type"); check::equal(gettype(preproc_constants_c::EXPR_LTE), "integer", "preproc_constants.EXPR_LTE has unexpected type"); check::equal(gettype(preproc_constants_c::EXPR_GTE), "integer", "preproc_constants.EXPR_GTE has unexpected type"); check::equal(gettype(preproc_constants_c::EXPR_INEQUALITY), "integer", "preproc_constants.EXPR_INEQUALITY has unexpected type"); diff --git a/Examples/test-suite/preproc_constants.i b/Examples/test-suite/preproc_constants.i index 3050baa06..f0c5e9361 100644 --- a/Examples/test-suite/preproc_constants.i +++ b/Examples/test-suite/preproc_constants.i @@ -72,10 +72,8 @@ #define EXPR_LSHIFT 0xFF << 2 #define EXPR_RSHIFT 0xFF >> 2 -/* FIXME -#define EXPR_LT 0xFF < 255 -#define EXPR_GT 0xFF > 255 -*/ +#define EXPR_LT (0xFF < 255) +#define EXPR_GT (0xFF > 255) #define EXPR_LTE 0xFF <= 255 #define EXPR_GTE 0xFF >= 255 #define EXPR_INEQUALITY 0xFF != 255 diff --git a/RELEASENOTES b/RELEASENOTES index 3a596dd46..1fedffc8a 100644 --- a/RELEASENOTES +++ b/RELEASENOTES @@ -11,6 +11,8 @@ SWIG-4.1.0 summary: - Add PHP 8 support. - PHP wrapping is now done entirely via PHP's C API - no more .php wrapper. - Perl 5.8.0 is now the oldest version SWIG supports. +- Common cases of `<` and `>` comparisons in constant expressions are now + supported. - GitHub Actions is now used instead of Travis CI for continuous integration. SWIG-4.0.2 summary: diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index 0796362bc..562c51269 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -1675,7 +1675,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier) %type type rawtype type_right anon_bitfield_type decltype ; %type base_list inherit raw_inherit; %type definetype def_args etype default_delete deleted_definition explicit_default; -%type expr exprnum exprcompound valexpr exprmem; +%type expr exprnum exprsimple exprcompound valexpr exprmem; %type ename ; %type less_valparms_greater; %type type_qualifier; @@ -6533,7 +6533,8 @@ exprmem : ID ARROW ID { } ; -valexpr : exprnum { +/* Non-compound expression */ +exprsimple : exprnum { $$ = $1; } | exprmem { @@ -6553,7 +6554,6 @@ valexpr : exprnum { $$.val = NewStringf("sizeof...(%s)",SwigType_str($6,0)); $$.type = T_ULONG; } - | exprcompound { $$ = $1; } | wstring { $$.val = $1; $$.rawval = NewStringf("L\"%s\"", $$.val); @@ -6588,6 +6588,11 @@ valexpr : exprnum { $$.final = 0; } + ; + +valexpr : exprsimple { $$ = $1; } + | exprcompound { $$ = $1; } + /* grouping */ | LPAREN expr RPAREN %prec CAST { $$.val = NewStringf("(%s)",$2.val); @@ -6666,7 +6671,7 @@ valexpr : exprnum { $$ = $2; $$.val = NewStringf("*%s",$2.val); } - ; + ; exprnum : NUM_INT { $$ = $1; } | NUM_FLOAT { $$ = $1; } @@ -6734,16 +6739,24 @@ exprcompound : expr PLUS expr { $$.val = NewStringf("%s!=%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); $$.type = cparse_cplusplus ? T_BOOL : T_INT; } -/* Sadly this causes 2 reduce-reduce conflicts with templates. FIXME resolve these. - | expr GREATERTHAN expr { - $$.val = NewStringf("%s > %s", COMPOUND_EXPR_VAL($1), COMPOUND_EXPR_VAL($3)); + /* Trying to parse `>` in the general case results in conflicts + * in the parser, but all user-reported cases are actually inside + * parentheses and we can handle that case. + */ + | LPAREN expr GREATERTHAN expr RPAREN { + $$.val = NewStringf("%s > %s", COMPOUND_EXPR_VAL($2), COMPOUND_EXPR_VAL($4)); $$.type = cparse_cplusplus ? T_BOOL : T_INT; } - | expr LESSTHAN expr { - $$.val = NewStringf("%s < %s", COMPOUND_EXPR_VAL($1), COMPOUND_EXPR_VAL($3)); + + /* Similarly for `<` except trying to handle exprcompound on the + * left side gives a shift/reduce conflict, so also restrict + * handling to non-compound subexpressions there. Again this + * covers all user-reported cases. + */ + | LPAREN exprsimple LESSTHAN expr RPAREN { + $$.val = NewStringf("%s < %s", COMPOUND_EXPR_VAL($2), COMPOUND_EXPR_VAL($4)); $$.type = cparse_cplusplus ? T_BOOL : T_INT; } -*/ | expr GREATERTHANOREQUALTO expr { $$.val = NewStringf("%s >= %s", COMPOUND_EXPR_VAL($1), COMPOUND_EXPR_VAL($3)); $$.type = cparse_cplusplus ? T_BOOL : T_INT;