@@ -1689,24 +1689,32 @@ void c_typecheck_baset::typecheck_expr_trinary(if_exprt &expr)
1689
1689
operands[1 ].type ().id ()!=ID_pointer)
1690
1690
implicit_typecast (operands[1 ], operands[2 ].type ());
1691
1691
1692
+ auto compile_time_null_pointer = [](const exprt &e, const namespacet &ns) {
1693
+ if (!is_compile_time_constantt (ns)(e))
1694
+ return false ;
1695
+ auto s = simplify_expr (e, ns);
1696
+ CHECK_RETURN (is_compile_time_constantt (ns)(s));
1697
+ if (!s.is_constant ())
1698
+ return false ;
1699
+ return is_null_pointer (to_constant_expr (s));
1700
+ };
1701
+
1692
1702
if (operands[1 ].type ().id ()==ID_pointer &&
1693
1703
operands[2 ].type ().id ()==ID_pointer &&
1694
1704
operands[1 ].type ()!=operands[2 ].type ())
1695
1705
{
1696
- exprt tmp1=simplify_expr (operands[1 ], *this );
1697
- exprt tmp2=simplify_expr (operands[2 ], *this );
1698
-
1699
- // is one of them void * AND null? Convert that to the other.
1700
- // (at least that's how GCC behaves)
1706
+ // Is one of them void * AND null? Convert that to the other.
1707
+ // (At least that's how GCC, Clang, and Visual Studio behave. Presence of
1708
+ // symbols blocks them from simplifying the expression to NULL.)
1701
1709
if (
1702
1710
to_pointer_type (operands[1 ].type ()).base_type ().id () == ID_empty &&
1703
- tmp1. is_constant () && is_null_pointer ( to_constant_expr (tmp1) ))
1711
+ compile_time_null_pointer (operands[ 1 ], * this ))
1704
1712
{
1705
1713
implicit_typecast (operands[1 ], operands[2 ].type ());
1706
1714
}
1707
1715
else if (
1708
1716
to_pointer_type (operands[2 ].type ()).base_type ().id () == ID_empty &&
1709
- tmp2. is_constant () && is_null_pointer ( to_constant_expr (tmp2) ))
1717
+ compile_time_null_pointer (operands[ 2 ], * this ))
1710
1718
{
1711
1719
implicit_typecast (operands[2 ], operands[1 ].type ());
1712
1720
}
0 commit comments