@@ -1689,24 +1689,31 @@ 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
+ if (!s.is_constant ())
1697
+ return false ;
1698
+ return is_null_pointer (to_constant_expr (s));
1699
+ };
1700
+
1692
1701
if (operands[1 ].type ().id ()==ID_pointer &&
1693
1702
operands[2 ].type ().id ()==ID_pointer &&
1694
1703
operands[1 ].type ()!=operands[2 ].type ())
1695
1704
{
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)
1705
+ // Is one of them void * AND null? Convert that to the other.
1706
+ // (At least that's how GCC, Clang, and Visual Studio behave. Presence of
1707
+ // symbols blocks them from simplifying the expression to NULL.)
1701
1708
if (
1702
1709
to_pointer_type (operands[1 ].type ()).base_type ().id () == ID_empty &&
1703
- tmp1. is_constant () && is_null_pointer ( to_constant_expr (tmp1) ))
1710
+ compile_time_null_pointer (operands[ 1 ], * this ))
1704
1711
{
1705
1712
implicit_typecast (operands[1 ], operands[2 ].type ());
1706
1713
}
1707
1714
else if (
1708
1715
to_pointer_type (operands[2 ].type ()).base_type ().id () == ID_empty &&
1709
- tmp2. is_constant () && is_null_pointer ( to_constant_expr (tmp2) ))
1716
+ compile_time_null_pointer (operands[ 2 ], * this ))
1710
1717
{
1711
1718
implicit_typecast (operands[2 ], operands[1 ].type ());
1712
1719
}
0 commit comments