@@ -1771,24 +1771,32 @@ void c_typecheck_baset::typecheck_expr_trinary(if_exprt &expr)
17711771 operands[1 ].type ().id ()!=ID_pointer)
17721772 implicit_typecast (operands[1 ], operands[2 ].type ());
17731773
1774+ auto compile_time_null_pointer = [](const exprt &e, const namespacet &ns) {
1775+ if (!is_compile_time_constantt (ns)(e))
1776+ return false ;
1777+ auto s = simplify_expr (e, ns);
1778+ CHECK_RETURN (is_compile_time_constantt (ns)(s));
1779+ if (!s.is_constant ())
1780+ return false ;
1781+ return to_constant_expr (s).is_null_pointer ();
1782+ };
1783+
17741784 if (operands[1 ].type ().id ()==ID_pointer &&
17751785 operands[2 ].type ().id ()==ID_pointer &&
17761786 operands[1 ].type ()!=operands[2 ].type ())
17771787 {
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)
1788+ // Is one of them void * AND null? Convert that to the other.
1789+ // (At least that's how GCC, Clang, and Visual Studio behave. Presence of
1790+ // symbols blocks them from simplifying the expression to NULL.)
17831791 if (
17841792 to_pointer_type (operands[1 ].type ()).base_type ().id () == ID_empty &&
1785- tmp1. is_constant () && to_constant_expr (tmp1). is_null_pointer ( ))
1793+ compile_time_null_pointer (operands[ 1 ], * this ))
17861794 {
17871795 implicit_typecast (operands[1 ], operands[2 ].type ());
17881796 }
17891797 else if (
17901798 to_pointer_type (operands[2 ].type ()).base_type ().id () == ID_empty &&
1791- tmp2. is_constant () && to_constant_expr (tmp2). is_null_pointer ( ))
1799+ compile_time_null_pointer (operands[ 2 ], * this ))
17921800 {
17931801 implicit_typecast (operands[2 ], operands[1 ].type ());
17941802 }
0 commit comments