Skip to main content

Module interprocedural

Module interprocedural 

Source
Expand description

Interprocedural call summaries derived from MIR for local wrapper functions.

When no hand-crafted summary exists, this module inspects a calleeโ€™s own MIR to approximate its effects: pointer-arithmetic wrappers, from_raw_parts wrappers, argument-to-return dataflow, and index-disjointness validators.

Enumsยง

TupleFieldLen ๐Ÿ”’
Length kind of a decoderโ€™s returned tuple length field.
WrapperEffectMemo ๐Ÿ”’
Memo state for the transitive wrapper-effect walk: Computing marks a callee currently being resolved (a re-entry is a self/mutual-recursive cycle), Done caches the finished result.

Functionsยง

block_dominates ๐Ÿ”’
Whether block a dominates block b (every path from the entry to b passes through a). Simple BFS: a dominates b iff b is not reachable from the entry when a is skipped.
body_reads_slice_len ๐Ÿ”’
Whether body contains a len call whose receiver traces back to argument 0.
call_result_reaches_return ๐Ÿ”’
Return true when call_destโ€™s value flows (via Copy/Move/Cast) to the functionโ€™s return place _0.
callee_calls_other_local ๐Ÿ”’
Return true if the callee body contains any Call terminator, meaning the callee is not self-contained (a nested call may have side effects that a shallow summary cannot capture).
callee_contains_pointer_arithmetic ๐Ÿ”’
Check whether a callee body contains pointer arithmetic calls.
context_key ๐Ÿ”’
Canonical, sortable representation of a CallContextโ€™s concrete arguments, used as part of the memo key (FxHashMap is not Hash).
copy_root ๐Ÿ”’
Trace a local back through x = copy y / x = move y assignments to its copy root (the original loop variable before MIR temporaries).
detect_index_disjoint_validator ๐Ÿ”’
Detect an โ€œindex disjoint validatorโ€: a function whose body loads elements from an array argument, and returns early (Err) both when an element is out of range against a scalar argument (>= len) and when two elements are equal (a duplicate). Returns (indices_arg, len_arg).
detect_pre_dec_end_offset ๐Ÿ”’
Detect a pre_dec_end(offset) call on the receiver (arg 0) and return its constant offset. next_back_unchecked calls self.pre_dec_end(1) before returning the end_or_len field, so the returned pointer must be adjusted by offset elements.
iter_ctor_reads_slice_len ๐Ÿ”’
Whether the callee (following at most depth single-call wrappers) reads the length of its slice argument โ€” a necessary condition for a slice iterator, whose end field is start + len.
local_must_write_args ๐Ÿ”’
Return callee argument indices that are definitely written on every reachable return path, pruning paths infeasible under context. Works for any callee with available MIR, and follows wrapper calls (Vec::push โ†’ push_mut) with bounded depth.
local_return_dependencies ๐Ÿ”’
Use the existing dataflow graph to approximate callee return deps. Works for any callee with available MIR (local or cross-crate #[inline]).
must_write_args_rec ๐Ÿ”’
named_index_disjoint_validator ๐Ÿ”’
Recognize the standard-library get_disjoint_check_valid helper as a trusted index-disjoint validator by name.
nested_call_context ๐Ÿ”’
Build the CallContext a nested call sees, keyed by the nested calleeโ€™s own argument indices. Each nested argument is concrete either because it is a literal at this call site, or because it passes an outer concrete value straight through (Copy/Move of an argument). This keeps a callerโ€™s literal at position i from being read as the nested calleeโ€™s position-i argument.
operand_is_ptr_metadata ๐Ÿ”’
Whether operand (through copy/move temps) is PtrMetadata(slice), including a slice.len() call (which is semantically PtrMetadata).
path_ends_in_return ๐Ÿ”’
path_infeasible_under_context ๐Ÿ”’
Return true if path is provably infeasible under context, by folding a SwitchInt whose discriminant is a direct copy of a concrete argument. Only prunes when the taken target is uniquely determined, so a feasible path is never removed.
pointer_arith_wrapper_probe ๐Ÿ”’
Single-effect recognizer for resolve_wrapper_effect: does callee directly wrap a pointer add/sub, or delegate to a nested callee that itself resolves to one?
resolve_wrapper_effect ๐Ÿ”’
Resolve calleeโ€™s wrapper effect by walking nested wrapper calls, with cycle detection and memoization. probe inspects calleeโ€™s body and, for a nested call it follows, invokes recurse, which routes back through this resolver so the memo applies uniformly. A callee re-entered while still being resolved is a cycle and resolves to None (no finite wrapper chain).
single_call_wrapper_target ๐Ÿ”’
The callee delegated to by a thin wrapper whose body is a single call returning directly into _0 (e.g. slice::iter โ†’ Iter::new).
switch_discriminant_concrete ๐Ÿ”’
Trace a SwitchInt discriminant back to a concrete argument value, following only direct Copy/Move assignments (no casts or pointer arithmetic) so the recovered value is identical to the argumentโ€™s.
trace_to_callee_arg ๐Ÿ”’
Trace backward from an operand (inner call arg) through Copy/Move/Cast/ Ref/RawPtr assignments to the outer calleeโ€™s argument local, returning its index. Ref/RawPtr are treated as data-flow too, which is an approximation (taking a reference is not a pure copy) but is adequate for wrapper recognition.
try_branch_effect ๐Ÿ”’
Detect <Option<T> as Try>::branch: Option<T> -> ControlFlow<Option<!>, T>. The Continue payload (field 0) equals the Some payload (field 0), so a ?-operator if let Some(..) = expr? unwrap keeps the payloadโ€™s provenance.
try_decode_length_return_effect ๐Ÿ”’
Detect a UTF-8-decoder shape: the function returns Option<(.., usize, ..)> whose length field is a constant on each Some return, and each Some((.., len)) return is guarded by a slice.get(len - 1)? (so len <= slice.len()). Summarizes the tupleโ€™s length field as field <= arg.len() so a caller can re-prove finger <= finger_back after finger += len.
try_field_load_effect ๐Ÿ”’
Detect a field-getter callee from its MIR: a function whose body is (essentially) (*self).field โ€” a single Deref + Field load returned as the functionโ€™s result. Produces a ReturnFieldOfArg effect so the materialized field is returned, without any name- or length-specific knowledge.
try_from_raw_parts_wrapper_effect ๐Ÿ”’
Detect when a local callee wraps from_raw_parts(ptr, len) and produce a ReturnFreshAllocation effect with the correct element size.
try_iter_constructor_effect ๐Ÿ”’
Detect a slice-iterator constructor structurally: a callee whose argument is a &[T]/&mut [T] and whose return type is a struct whose first two fields are pointers into T (field 0 = start NonNull<T>, field 1 = end *const T/*mut T). This matches slice::Iter/IterMut and same-shaped local re-implementations by structure rather than by the typeโ€™s name.
try_pointer_arith_wrapper_effect ๐Ÿ”’
Probe whether callee is a pointer-arithmetic (add/sub) wrapper, following nested wrapper calls transitively. effect_summary runs this on every local callee; it returns None for anything that is not โ€” transitively โ€” a pointer add/sub wrapper.
try_ptr_field_return_effect ๐Ÿ”’
Detect a function that returns a raw-pointer field of its receiver ((*self).end_or_len-shaped), even when the body also contains a ZST/non-ZST branch and a preceding mutation call (e.g. an iteratorโ€™s next_back_unchecked). Produces a ReturnFieldOfArg effect so the returned pointer keeps the fieldโ€™s provenance across the interprocedural boundary.
try_slice_bounded_return_effect ๐Ÿ”’
Detect a memchr-style search function: it returns Option<usize> whose Some(i) payload is an index guarded by a loop condition i < arg.len() (where arg is a slice argument). The summary lets a caller re-prove a numeric invariant like finger <= finger_back after finger += i + 1.
tuple_field_len_kind ๐Ÿ”’
Classify the length field of a (.., len, ..) tuple, tracing through copy/move temps and a _tmp = (..) tuple aggregate assignment.
write_args_on_path ๐Ÿ”’

Type Aliasesยง

MustWriteMemo ๐Ÿ”’
Cached must-write summaries, keyed by (callee, depth, context). Depth is part of the key because the depth > 4 cutoff makes a summary computed deeper in the wrapper chain less complete than one computed higher up, and the DFS reaches the deep ones first. The context is part of the key because one query can reach the same callee with different concrete arguments, which prune different paths.