@@ -66,7 +66,7 @@ class is_compile_time_constantt
6666
6767 // / This function determines what expressions are to be propagated as
6868 // / "constants"
69- bool is_constant (const exprt &e) const
69+ virtual bool is_constant (const exprt &e) const
7070 {
7171 // non-standard numeric constant
7272 if (e.id () == ID_infinity)
@@ -138,6 +138,52 @@ class is_compile_time_constantt
138138 }
139139};
140140
141+ // / Clang appears to have a somewhat different idea of what is/isn't to be
142+ // / considered a constant at compile time.
143+ class clang_is_constant_foldedt : public is_compile_time_constantt
144+ {
145+ public:
146+ explicit clang_is_constant_foldedt (const namespacet &ns)
147+ : is_compile_time_constantt(ns)
148+ {
149+ }
150+
151+ protected:
152+ // / This function determines what expressions are constant folded by clang
153+ bool is_constant (const exprt &e) const override
154+ {
155+ // we need to adhere to short-circuit semantics for the following
156+ if (e.id () == ID_if)
157+ {
158+ const if_exprt &if_expr = to_if_expr (e);
159+ if (!is_constant (if_expr.cond ()))
160+ return false ;
161+ exprt const_cond = simplify_expr (if_expr.cond (), ns);
162+ CHECK_RETURN (const_cond.is_constant ());
163+ if (const_cond.is_true ())
164+ return is_constant (if_expr.true_case ());
165+ else
166+ return is_constant (if_expr.false_case ());
167+ }
168+ else if (e.id () == ID_and || e.id () == ID_or)
169+ {
170+ for (const auto &op : e.operands ())
171+ {
172+ if (!is_constant (op))
173+ return false ;
174+ exprt const_cond = simplify_expr (op, ns);
175+ CHECK_RETURN (const_cond.is_constant ());
176+ // stop when we hit false (for an and) or true (for an or)
177+ if (const_cond == make_boolean_expr (e.id () == ID_or))
178+ break ;
179+ }
180+ return true ;
181+ }
182+ else
183+ return is_compile_time_constantt::is_constant (e);
184+ }
185+ };
186+
141187void c_typecheck_baset::typecheck_expr (exprt &expr)
142188{
143189 if (expr.id ()==ID_already_typechecked)
@@ -3684,39 +3730,47 @@ exprt c_typecheck_baset::do_special_functions(
36843730 }
36853731 else if (identifier==" __builtin_constant_p" )
36863732 {
3687- // this is a gcc extension to tell whether the argument
3688- // is known to be a compile-time constant
3733+ // This is a gcc/clang extension to tell whether the argument
3734+ // is known to be a compile-time constant. The behavior of these two
3735+ // compiler families, however, is quite different, which we need to take
3736+ // care of in the below config-dependent branches.
3737+
36893738 if (expr.arguments ().size ()!=1 )
36903739 {
36913740 error ().source_location = f_op.source_location ();
36923741 error () << " __builtin_constant_p expects one argument" << eom;
36933742 throw 0 ;
36943743 }
36953744
3696- // do not typecheck the argument - it is never evaluated, and thus side
3697- // effects must not show up either
3698-
3699- // try to produce constant
3700- exprt tmp1=expr.arguments ().front ();
3701- simplify (tmp1, *this );
3702-
3703- bool is_constant=false ;
3704-
3705- // Need to do some special treatment for string literals,
3706- // which are (void *)&("lit"[0])
3707- if (
3708- tmp1.id () == ID_typecast &&
3709- to_typecast_expr (tmp1).op ().id () == ID_address_of &&
3710- to_address_of_expr (to_typecast_expr (tmp1).op ()).object ().id () ==
3711- ID_index &&
3712- to_index_expr (to_address_of_expr (to_typecast_expr (tmp1).op ()).object ())
3713- .array ()
3714- .id () == ID_string_constant)
3745+ bool is_constant = false ;
3746+ if (config.ansi_c .mode == configt::ansi_ct::flavourt::CLANG)
37153747 {
3716- is_constant= true ;
3748+ is_constant = clang_is_constant_foldedt (* this )(expr. arguments (). front ()) ;
37173749 }
37183750 else
3719- is_constant=tmp1.is_constant ();
3751+ {
3752+ // try to produce constant
3753+ exprt tmp1 = expr.arguments ().front ();
3754+ simplify (tmp1, *this );
3755+
3756+ // Need to do some special treatment for string literals,
3757+ // which are (void *)&("lit"[0])
3758+ if (
3759+ tmp1.id () == ID_typecast &&
3760+ to_typecast_expr (tmp1).op ().id () == ID_address_of &&
3761+ to_address_of_expr (to_typecast_expr (tmp1).op ()).object ().id () ==
3762+ ID_index &&
3763+ to_index_expr (to_address_of_expr (to_typecast_expr (tmp1).op ()).object ())
3764+ .array ()
3765+ .id () == ID_string_constant)
3766+ {
3767+ is_constant = true ;
3768+ }
3769+ else if (tmp1.id () == ID_string_constant)
3770+ is_constant = true ;
3771+ else
3772+ is_constant = tmp1.is_constant ();
3773+ }
37203774
37213775 exprt tmp2=from_integer (is_constant, expr.type ());
37223776 tmp2.add_source_location ()=source_location;
0 commit comments