@@ -1719,24 +1719,32 @@ void c_typecheck_baset::typecheck_expr_trinary(if_exprt &expr)
1719
1719
operands[1 ].type ().id ()!=ID_pointer)
1720
1720
implicit_typecast (operands[1 ], operands[2 ].type ());
1721
1721
1722
+ auto compile_time_null_pointer = [](const exprt &e, const namespacet &ns) {
1723
+ if (!is_compile_time_constantt (ns)(e))
1724
+ return false ;
1725
+ auto s = simplify_expr (e, ns);
1726
+ CHECK_RETURN (is_compile_time_constantt (ns)(s));
1727
+ if (!s.is_constant ())
1728
+ return false ;
1729
+ return is_null_pointer (to_constant_expr (s));
1730
+ };
1731
+
1722
1732
if (operands[1 ].type ().id ()==ID_pointer &&
1723
1733
operands[2 ].type ().id ()==ID_pointer &&
1724
1734
operands[1 ].type ()!=operands[2 ].type ())
1725
1735
{
1726
- exprt tmp1=simplify_expr (operands[1 ], *this );
1727
- exprt tmp2=simplify_expr (operands[2 ], *this );
1728
-
1729
- // is one of them void * AND null? Convert that to the other.
1730
- // (at least that's how GCC behaves)
1736
+ // Is one of them void * AND null? Convert that to the other.
1737
+ // (At least that's how GCC, Clang, and Visual Studio behave. Presence of
1738
+ // symbols blocks them from simplifying the expression to NULL.)
1731
1739
if (
1732
1740
to_pointer_type (operands[1 ].type ()).base_type ().id () == ID_empty &&
1733
- tmp1. is_constant () && is_null_pointer ( to_constant_expr (tmp1) ))
1741
+ compile_time_null_pointer (operands[ 1 ], * this ))
1734
1742
{
1735
1743
implicit_typecast (operands[1 ], operands[2 ].type ());
1736
1744
}
1737
1745
else if (
1738
1746
to_pointer_type (operands[2 ].type ()).base_type ().id () == ID_empty &&
1739
- tmp2. is_constant () && is_null_pointer ( to_constant_expr (tmp2) ))
1747
+ compile_time_null_pointer (operands[ 2 ], * this ))
1740
1748
{
1741
1749
implicit_typecast (operands[2 ], operands[1 ].type ());
1742
1750
}
0 commit comments