@@ -1771,24 +1771,33 @@ void c_typecheck_baset::typecheck_expr_trinary(if_exprt &expr)
1771
1771
operands[1 ].type ().id ()!=ID_pointer)
1772
1772
implicit_typecast (operands[1 ], operands[2 ].type ());
1773
1773
1774
+ auto compile_time_null_pointer = [](const exprt &e, const namespacet &ns)
1775
+ {
1776
+ if (!is_compile_time_constantt (ns)(e))
1777
+ return false ;
1778
+ auto s = simplify_expr (e, ns);
1779
+ CHECK_RETURN (is_compile_time_constantt (ns)(s));
1780
+ if (!s.is_constant ())
1781
+ return false ;
1782
+ return to_constant_expr (s).is_null_pointer ();
1783
+ };
1784
+
1774
1785
if (operands[1 ].type ().id ()==ID_pointer &&
1775
1786
operands[2 ].type ().id ()==ID_pointer &&
1776
1787
operands[1 ].type ()!=operands[2 ].type ())
1777
1788
{
1778
- exprt tmp1=simplify_expr (operands[1 ], *this );
1779
- exprt tmp2=simplify_expr (operands[2 ], *this );
1780
-
1781
- // is one of them void * AND null? Convert that to the other.
1782
- // (at least that's how GCC behaves)
1789
+ // Is one of them void * AND null? Convert that to the other.
1790
+ // (At least that's how GCC, Clang, and Visual Studio behave. Presence of
1791
+ // symbols blocks them from simplifying the expression to NULL.)
1783
1792
if (
1784
1793
to_pointer_type (operands[1 ].type ()).base_type ().id () == ID_empty &&
1785
- tmp1. is_constant () && to_constant_expr (tmp1). is_null_pointer ( ))
1794
+ compile_time_null_pointer (operands[ 1 ], * this ))
1786
1795
{
1787
1796
implicit_typecast (operands[1 ], operands[2 ].type ());
1788
1797
}
1789
1798
else if (
1790
1799
to_pointer_type (operands[2 ].type ()).base_type ().id () == ID_empty &&
1791
- tmp2. is_constant () && to_constant_expr (tmp2). is_null_pointer ( ))
1800
+ compile_time_null_pointer (operands[ 2 ], * this ))
1792
1801
{
1793
1802
implicit_typecast (operands[2 ], operands[1 ].type ());
1794
1803
}
0 commit comments