|
ESBMC
Efficient SMT-based Context-Bounded Model Checker
|
#include <clang_c_adjust_irep2.h>
Classes | |
| struct | arm_info |
| One arm of the dispatch, as much of it as a caller may see: what it is called, and the guard deciding whether it claims a node. More... | |
Public Member Functions | |
| clang_c_adjust_irep2 (contextt &_context, bool sole_adjuster=false, bool writeback_all=false) | |
| virtual | ~clang_c_adjust_irep2 ()=default |
| bool | adjust () |
| Walk every code symbol's IREP2 value. | |
| void | adjust_expr (expr2tc &expr) |
Static Public Member Functions | |
| static std::vector< arm_info > | arm_order () |
| The arms in the order adjust_expr applies them. | |
Protected Types | |
| using | arm = adjust_arm<clang_c_adjust_irep2> |
Protected Member Functions | |
| virtual void | adjust_reference (expr2tc &) |
| Read a reference-typed operand through, where the operand is used as a value: r becomes *r. | |
| void | adjust_increment_reference (expr2tc &expr) |
| clang_c_adjust adjusts references on an increment or decrement, whose operand it updates in place. | |
| void | adjust_index (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_index's rewrite. | |
| void | adjust_member (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_member's rewrite: reach through a pointer base with a dereference, or an array base with a zero index. | |
| void | declare_implicit_callee (const expr2tc &expr) |
| A call to a function with no visible declaration reaches here with no symbol in the context; clang_c_adjust::adjust_side_effect_function_call declares one. | |
| void | adjust_boolean_operands (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_expr_{unary,binary}_boolean's live half. | |
| void | adjust_call_callee (expr2tc &expr) |
| IREP2 form of the "do implicit dereference" step of clang_c_adjust::adjust_side_effect_function_call: goto_convert's do_function_call accepts a symbol or a dereference, so a pointer-typed callee – a function-pointer struct member, say – must be dereferenced first (§82). | |
| void | adjust_call_signature (expr2tc &expr) |
| Rebuild a call's callee from the symbol table when the converter left its type incomplete, then let the frontend align the call's own type. | |
| virtual void | align_call_return_type (expr2tc &, const symbolt &) |
| The call's type follows its callee's return type in C++ but not in C, where clang_c_adjust::align_se_function_call_return_type is empty. | |
| void | adjust_complex_arith (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_expr_binary_arithmetic's complex branch: decompose a op b over a complex operand into per-component arithmetic and rebuild a (real, imag) pair. | |
| void | adjust_complex_unary (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_expr_unary_complex: -z negates both components, GNU ~z conjugates. | |
| void | adjust_if_expr (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_if: a ternary's condition must be boolean before goto_convert lowers it, and its arms must agree with the node's type. | |
| void | adjust_special_functions (expr2tc &expr) |
| IREP2 form of the __builtin_-prefixed half of clang_c_adjust::do_special_functions: fold a recognised builtin call to the node it denotes. | |
| void | adjust_derived_to_base (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_derived_to_base: displace a derived->base conversion onto the base subobject under the flattened layout. | |
| void | adjust_base_to_derived (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_base_to_derived: re-base a downcast off the base subobject onto the start of the derived object. | |
| void | adjust_address_of (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_address_of's array decay (§105). | |
| void | adjust_ptr_mem (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_ptr_mem. | |
| void | declare_polymorphic_builtin (expr2tc &expr) |
| The GCC __sync_* / C11 __c11_atomic_* half of clang_c_adjust::adjust_side_effect_function_call: clang hands these builtins over body-less, so the concrete instance has to be declared and the callee repointed at it. | |
| void | adjust_expression_statement (expr2tc &expr) |
| An expression statement whose value has array type – y->ss; where y points at a struct with an array member – is rewritten to &y->ss[0]. | |
| void | promote_unary_bool_operand (expr2tc &expr) |
| C11 6.5.3.3: the operand of unary - and ~ undergoes integer promotion, so a boolean one – a comparison, || or && – becomes int. | |
| void | adjust_struct (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_struct's insertion loop. | |
| void | adjust_array_subtype (expr2tc &expr) |
| adjust_struct retypes an element to its tag's padded layout, which leaves an enclosing array literal still naming the unpadded element type. | |
| void | adjust_decl_init (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_decl's trailing gen_typecast: a declaration's initialiser converts to the declared type. | |
| void | adjust_dereference (expr2tc &expr) |
| void | lower_complex_compound_assignment (expr2tc &expr) |
| IREP2 form of clang_c_adjust::lower_complex_compound_assignment. | |
| void | adjust_vector_float_arith (expr2tc &expr) |
| clang emits ieee_* for scalar float arithmetic itself, but hands over a plain +/-/*// when the operands are vectors of float and leaves clang_c_adjust::adjust_float_arith to promote it. | |
| void | hoist_for_init (expr2tc &expr) |
| void | pad_type_symbol (symbolt &symbol) |
| Pad a complete struct or union type symbol to its ABI layout (§96). | |
| void | adjust_binary_arith_operands (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_expr_binary_arithmetic's conversion half: the usual arithmetic conversions over the operands, then the node's own type. | |
| void | adjust_shift_operands (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_expr_shifts. | |
| void | adjust_plain_assignment (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_side_effect_assignment's plain "assign" case: the node takes the target's type, and the source converts to it. | |
| void | adjust_compound_assignment (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_side_effect_assignment's tail: the compound operators take the usual arithmetic conversions on both operands (C11 6.5.16.2p3 – b += a is b = b + a, so a narrow target promotes), while the node keeps the target's type. | |
| void | adjust_statement_condition (expr2tc &expr) |
| IREP2 form of the gen_typecast_bool that adjust_ifthenelse, adjust_while and adjust_for apply to a statement's controlling expression (§95). | |
| bool | adjust_float_builtin (expr2tc &expr, const irep_idt &name, const std::vector< expr2tc > &args) |
| The name-matched half of do_special_functions: isnan, abs, sqrt, inf and friends. | |
| void | adjust_relational (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_expr_rel's operand half: the usual arithmetic conversions over a comparison's operands, which is also what decays an array operand compared against a pointer (§96). | |
| void | adjust_call_arguments (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_function_call_arguments' conversion half: convert each argument to its parameter type, which is what decays a function designator to a pointer at a call (§108). | |
| void | adjust_function_designators (expr2tc &expr) |
| IREP2 form of clang_c_adjust::adjust_symbol's function-designator sugar (§100). | |
| virtual void | gen_symbol_code (symbolt &) |
| Per-symbol code the pass synthesises rather than rewrites, run before the value walk so what it emits is adjusted like the rest. | |
| virtual void | adjust_symbol_type (symbolt &) |
| Per-symbol type work, run for every symbol including the value-less ones. | |
| virtual void | adjust_before_operands (expr2tc &) |
| A rewrite whose result must be walked, so it cannot be an arm: the arms run after the operand walk. | |
| virtual void | adjust_sole_arms (expr2tc &expr) |
| Arms that run only when this pass is the sole adjuster, applied in the order arms lists them. | |
| void | adjust_comma_type (expr2tc &expr) |
| A comma expression takes its right operand's type (C11 6.5.17p2). | |
Protected Attributes | |
| contextt & | context |
| const bool | sole_adjuster |
| const bool | writeback_all |
| locationt | enclosing_location |
| Location of the innermost enclosing statement, for the nodes that carry none of their own. | |
| namespacet | ns {context} |
Static Protected Attributes | |
| static const arm | arms [] |
| The chain in application order. | |
|
protected |
|
inlineexplicit |
| sole_adjuster | true under –clang-c-irep2-adjust-only, where this pass replaces clang_c_adjust. Work that substitutes for the legacy pass – declaring an implicitly-declared callee (§70) – must run only then: in shadow mode the legacy pass has already done it, and doing it twice adds conflicting symbols for library functions. |
| writeback_all | diagnostic only (–clang-c-irep2-adjust-writeback-all): refresh every symbol's legacy value, not just the ones this pass changed. adjust() gates the write-back on value != before so an untouched body never pays migrate_expr_back's losses – but that also means --symbol-table-only prints the converter's tree for those bodies, not this pass's, and the two differ wherever migrate_expr normalises (§135). Set this to see what the pass actually produced. |
|
virtualdefault |
| bool clang_c_adjust_irep2::adjust | ( | ) |
Walk every code symbol's IREP2 value.
Returns false; there is no failure mode yet, and the signature matches clang_c_adjust::adjust() so the driver can call either.
|
protected |
IREP2 form of clang_c_adjust::adjust_address_of's array decay (§105).
|
protected |
adjust_struct retypes an element to its tag's padded layout, which leaves an enclosing array literal still naming the unpadded element type.
The operands are walked before the node itself, so the retyped elements are already in place here; value_sett::assign's base_type_eq rejects the pair otherwise.
|
protected |
IREP2 form of clang_c_adjust::adjust_base_to_derived: re-base a downcast off the base subobject onto the start of the derived object.
|
inlineprotectedvirtual |
A rewrite whose result must be walked, so it cannot be an arm: the arms run after the operand walk.
The legacy passes dispatch top-down and get this ordering for free. C has no such rewrite (docs/roadmap/scope-clang-cpp-irep2.md §3.15).
Reimplemented in clang_cpp_adjust_irep2.
|
protected |
IREP2 form of clang_c_adjust::adjust_expr_binary_arithmetic's conversion half: the usual arithmetic conversions over the operands, then the node's own type.
adjust_float_arith's ieee_* promotion is not part of this (§104.2).
|
protected |
IREP2 form of clang_c_adjust::adjust_expr_{unary,binary}_boolean's live half.
Their type write is dead for C (§58.1); the operand conversion is not – goto_convert's short-circuit lowering rejects a non-boolean operand outright. Portable here, unlike §58's dispatch-point shape, because this walk migrates once and does not round-trip per node (§78).
|
protected |
IREP2 form of clang_c_adjust::adjust_function_call_arguments' conversion half: convert each argument to its parameter type, which is what decays a function designator to a pointer at a call (§108).
|
protected |
IREP2 form of the "do implicit dereference" step of clang_c_adjust::adjust_side_effect_function_call: goto_convert's do_function_call accepts a symbol or a dereference, so a pointer-typed callee – a function-pointer struct member, say – must be dereferenced first (§82).
|
protected |
Rebuild a call's callee from the symbol table when the converter left its type incomplete, then let the frontend align the call's own type.
IREP2 form of the callee refresh in clang_c_adjust::adjust_side_effect_function_call: a converter can leave the callee's type incomplete – the Solidity frontend emits a call whose callee has no code type at all – and legacy repairs it by rebuilding the symbol expression from the table.
Aligning the call's own type to the callee's return type is C++'s, not C's (align_se_function_call_return_type is empty in clang_c_adjust), so that half is a hook.
|
protected |
A comma expression takes its right operand's type (C11 6.5.17p2).
Clang hands it the decayed type when the right operand is an array, so leaving it makes (c, a[i])[0] index a pointer rather than the row – which loses the named array-bounds check for the generic dereference one. Same rewrite as adjust_comma_at_dispatch, which the –clang-c-irep2-adjust probe uses.
|
protected |
IREP2 form of clang_c_adjust::adjust_expr_binary_arithmetic's complex branch: decompose a op b over a complex operand into per-component arithmetic and rebuild a (real, imag) pair.
Unported, a complex / reaches goto_check's div_by_zero_check, which asks gen_zero for a complex zero and aborts – the default path never gets there because it lowers to ieee_div, which is exempt from that check (§88).
|
protected |
IREP2 form of clang_c_adjust::adjust_expr_unary_complex: -z negates both components, GNU ~z conjugates.
Unported, either reaches the solver still carrying a complex type and segfaults it (§90).
|
protected |
IREP2 form of clang_c_adjust::adjust_side_effect_assignment's tail: the compound operators take the usual arithmetic conversions on both operands (C11 6.5.16.2p3 – b += a is b = b + a, so a narrow target promotes), while the node keeps the target's type.
|
protected |
IREP2 form of clang_c_adjust::adjust_decl's trailing gen_typecast: a declaration's initialiser converts to the declared type.
Distinct from adjust_plain_assignment, which handles the expression form (sideeffect_assign2t). Without it a narrower declared type keeps the promoted operand type – _ExtInt(10) z = x + y initialises from an int – and the solver is handed mismatching sorts.
|
protected |
|
protected |
IREP2 form of clang_c_adjust::adjust_derived_to_base: displace a derived->base conversion onto the base subobject under the flattened layout.
The offset comes from base_displacement, ESBMC's own layout oracle – recomputing it from clang's record layout is the mistake #3894 records.
| void clang_c_adjust_irep2::adjust_expr | ( | expr2tc & | expr | ) |
|
protected |
An expression statement whose value has array type – y->ss; where y points at a struct with an array member – is rewritten to &y->ss[0].
clang_c_adjust does this because the dereference code does not assume such an object exists; the statement's value is unused, so taking the first element's address is free (clang_c_adjust_code.cpp:57-74).
An assignment operand is exempt there and here: the array is the assignment target, not a value being discarded.
|
protected |
The name-matched half of do_special_functions: isnan, abs, sqrt, inf and friends.
sqrt's legacy arm additionally skips a py:-prefixed callee; this pass is constructed only from clang_c_languaget::typecheck, so no Python symbol can reach it and the guard has nothing to test.
Split from adjust_special_functions because these spellings are not reserved, so they run behind builtin_shadows_user_definition (§94).
|
protected |
IREP2 form of clang_c_adjust::adjust_symbol's function-designator sugar (§100).
A function designator used as a value is sugar for &f (clang_c_adjust::adjust_symbol).
Applied from the parent rather than at the symbol itself: address_of2t asserts its operand is not another address_of, so a user-written &f must not be wrapped again – where the legacy pass builds &(&f) and collapses it in adjust_address_of, this never builds it.
|
protected |
IREP2 form of clang_c_adjust::adjust_if: a ternary's condition must be boolean before goto_convert lowers it, and its arms must agree with the node's type.
if2t is the only value-level kind carrying a location (§49.2), so the rebuild passes the original through (§84).
|
protected |
clang_c_adjust adjusts references on an increment or decrement, whose operand it updates in place.
Without it f()++, where f returns a reference, does arithmetic on the reference instead of on the referent (scope-clang-cpp-irep2.md §3.16).
|
protected |
IREP2 form of clang_c_adjust::adjust_index's rewrite.
The legacy arm keeps the operand recursion and returns before this point when the flag is on (scope-clang-c-irep2.md §19.2).
|
protected |
IREP2 form of clang_c_adjust::adjust_member's rewrite: reach through a pointer base with a dereference, or an array base with a zero index.
|
protected |
IREP2 form of clang_c_adjust::adjust_side_effect_assignment's plain "assign" case: the node takes the target's type, and the source converts to it.
IREP2 form of clang_c_adjust::adjust_side_effect_assignment's "assign" case: the node takes the target's type and the source converts to it.
The compound operators ("assign+", ...) are a larger arm carrying a complex lowering of their own, and are left where this mode already had them.
|
protected |
IREP2 form of clang_c_adjust::adjust_ptr_mem.
*a on an array is a[0] (C11 6.5.3.2p4 through the 6.3.2.1p3 decay), and clang_c_adjust::adjust_dereference rewrites it to that index.
obj->*pmf dereferences its base, and a bound member selection – which carries clang's BoundMember type, empty after the seam – becomes the member function itself, with this prepended to the pointed-to code type's parameters. Left standing, the node reaches goto_convert as a callee it cannot read (docs/roadmap/scope-clang-cpp-irep2.md §7.5).
Left as a dereference the node reaches the encoder as a pointer built from an array rather than a named element, and it aborts there: Unexpected type in int/ptr typecast.
Legacy tests is_array_like, which also admits a vector; clang rejects *v on one ("indirection requires pointer operand"), so no input reaches that half and it is not reproduced here. Incomplete arrays need no arm of their own – migrate_type gives them array_type2t with size_is_infinite. Not every shape aborts: *"abc" returned a wrong verdict instead.
Then: dereferencing a pointer to a function yields a function designator, which converts straight back to a pointer (C11 6.3.2.1p4) – so *f is f, and ******f too. Left bare, the code-typed dereference reaches a consumer that wants a pointer.
Legacy's remaining arm retypes the node to the pointer's subtype; the migration already builds that type, so no corpus input distinguishes it.
|
inlineprotectedvirtual |
Read a reference-typed operand through, where the operand is used as a value: r becomes *r.
Empty for C, which has no references, and overridden by the C++ pass – exactly as clang_c_adjust::adjust_reference is (scope-clang-cpp-irep2.md §3.16).
Reimplemented in clang_cpp_adjust_irep2.
|
protected |
IREP2 form of clang_c_adjust::adjust_expr_rel's operand half: the usual arithmetic conversions over a comparison's operands, which is also what decays an array operand compared against a pointer (§96).
|
protected |
IREP2 form of clang_c_adjust::adjust_expr_shifts.
C11 6.5.7p3 performs the integer promotions on each operand separately – not the usual arithmetic conversions – and 6.5.7p4 gives the result the promoted left operand's type. A _Bool left operand left unpromoted reaches bitwuzla as a one-bit sort where the shift wants a bitvector, and aborts it.
The shr to lshr/ashr selection legacy also does here has no IREP2 counterpart: there is no shr2t, so the migration has already chosen.
|
protectedvirtual |
Arms that run only when this pass is the sole adjuster, applied in the order arms lists them.
Virtual so a derived pass substitutes its own table: one virtual for the whole dispatch, rather than the per-arm virtuals §3 of the C++ scope rejected.
Reimplemented in clang_cpp_adjust_irep2.
|
protected |
IREP2 form of the __builtin_-prefixed half of clang_c_adjust::do_special_functions: fold a recognised builtin call to the node it denotes.
These spellings are reserved, so unlike the name-matched family (is_name_matched_builtin) a program cannot supply its own definition and no shadows_user_definition query is needed (§90).
|
protected |
IREP2 form of the gen_typecast_bool that adjust_ifthenelse, adjust_while and adjust_for apply to a statement's controlling expression (§95).
IREP2 form of the gen_typecast_bool each of adjust_ifthenelse, adjust_while and adjust_for applies to its controlling expression.
goto_convert's branch lowering rejects a non-boolean guard, so this is the statement-level counterpart of adjust_if_expr's operand half.
|
protected |
IREP2 form of clang_c_adjust::adjust_struct's insertion loop.
A struct literal reaches this pass with an operand per declared member, while add_padding has given the type its synthetic ones; unpadded, the value is short a component and a downstream member read resolves by position onto the wrong field. pad_struct_operands is the shared helper the Python adjuster already uses for the same job (irep2/irep2_utils.h).
|
inlineprotectedvirtual |
Per-symbol type work, run for every symbol including the value-less ones.
C has none; C++ resolves a dynamic exception specification here (docs/roadmap/scope-clang-cpp-irep2.md §7.7).
Reimplemented in clang_cpp_adjust_irep2.
|
protected |
clang emits ieee_* for scalar float arithmetic itself, but hands over a plain +/-/*// when the operands are vectors of float and leaves clang_c_adjust::adjust_float_arith to promote it.
Unpromoted, the backend is handed a bitvector operator over a floating-point vector and aborts.
The legacy arm returns before attaching a rounding mode for a vector ("BUG: setting rounding_mode breaks migration"), and migrate_rounding_mode then synthesises the default symbol for the attribute-less node – so the node the default path produces carries that symbol, and this builds the same one.
|
inlineprotectedvirtual |
The call's type follows its callee's return type in C++ but not in C, where clang_c_adjust::align_se_function_call_return_type is empty.
Reimplemented in clang_cpp_adjust_irep2.
|
static |
The arms in the order adjust_expr applies them.
The order is load-bearing – the reasons are stated on the rows in clang_c_adjust_irep2.cpp – and was previously legible only as statement position, which no test could read. unit/clang-c-frontend/adjust_arms.test.cpp reads this.
|
protected |
A call to a function with no visible declaration reaches here with no symbol in the context; clang_c_adjust::adjust_side_effect_function_call declares one.
That is a symbol-table side effect rather than an expression rewrite, so it ports independently of the rest of that arm (§70).
|
protected |
The GCC __sync_* / C11 __c11_atomic_* half of clang_c_adjust::adjust_side_effect_function_call: clang hands these builtins over body-less, so the concrete instance has to be declared and the callee repointed at it.
A symbol-table side effect, so it ports independently of the rest of that arm, exactly as declare_implicit_callee does (§130).
|
inlineprotectedvirtual |
Per-symbol code the pass synthesises rather than rewrites, run before the value walk so what it emits is adjusted like the rest.
Distinct from an arm: an arm rewrites one node, this takes the whole symbol. C generates nothing (docs/roadmap/scope-clang-cpp-irep2.md §3.6).
Reimplemented in clang_cpp_adjust_irep2.
|
protected |
|
protected |
IREP2 form of clang_c_adjust::lower_complex_compound_assignment.
a op= b over a complex operand becomes a = a op b, with the binary node handed to adjust_complex_arith for the component-level decomposition. goto_convert's remove_assignment rebuilds the compound form long after adjustment, so a node left here reaches the SMT layer as a raw complex operator and the backend faults on it (#6713).
|
protected |
Pad a complete struct or union type symbol to its ABI layout (§96).
add_padding on a complete struct or union, which is the half of clang_c_adjust::adjust_type that the corpus shows is load-bearing here.
The function is shared (clang-c-frontend/padding.h) and idempotent – adjust_type asserts that re-padding is a no-op – so this reuses it rather than reimplementing a layout algorithm over type2tc.
|
protected |
C11 6.5.3.3: the operand of unary - and ~ undergoes integer promotion, so a boolean one – a comparison, || or && – becomes int.
Left boolean it reaches the solver where a bitvector is wanted (#4078).
|
staticprotected |
The chain in application order.
The arms that run when this pass is the sole adjuster, in application order.
Defined in clang_c_adjust_irep2.cpp, beside the predicates it names. An unknown-bound declaration completed out of line: every initialiser is an address constant, so the table is constant-initialised rather than built at start-up.
The order is load-bearing wherever a comment below says so; everywhere else the guards are disjoint by expr_id and the row order is free. Each guard is re-evaluated against the current node, so an arm that rewrites a node into another kind hands it to that kind's arm below – which is how adjust_index's p[i] becomes a dereference the dereference arm then sees.
|
protected |
|
protected |
Location of the innermost enclosing statement, for the nodes that carry none of their own.
|
protected |
|
protected |
|
protected |