Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

rustc_const_uneval

rustc_const_uneval is a subcrate of Charon which handles evaluating constants with rustc and reading their values back into structured constants (“unevaluating” them). Like rustc_trait_elaboration, this is meant to be a sort of extension of rustc.

The entry point is ConstReader::read, which evaluates a ConstSource (a const item, a promoted, a global, a type-level constant, a valtree or an already-evaluated value) and reads the result either as a structured Const or as raw bytes, depending on the ReadMode. This avoid duplicating a lot of tricky code around handling these similar entities.

rustc represents evaluated constants in two ways:

  • valtrees, which are trees of integers used for type-level constants.
  • allocations, which occur in MIR bodies and consts. We read them by loading them in a const-eval interpreter and walking the value according to its type.

Pointers are the tricky part of this. A pointer into a global (anything with provenance: a static, an allocation without an item such as the bytes of b"foo", or a function, whose place has type ()) is kept as a pointer to that global, expressed as a sequence of projections from the global to the pointee (fields, indices, subslices, and byte offsets when no typed path exists). A pointer whose type doesn’t match the place it reaches becomes a cast of a pointer to that place. Whether allocations without an item become globals or get inlined at each use is controlled by Config::anon_allocs_as_globals, except that a pointer outside of its allocation always points to it as a global. Note that inlining allocations means aliasing information is lost. Finally, wide pointers are read as a thin pointer to the sized value they were unsized from (e.g. [T; N] for a &[T]), with an Unsize that tells how to recover the wide pointer.

Allocations without an item are untyped. When we name them (Config.anon_allocs_as_globals) and are in values mode, we try reading them using the type of the first pointer to it, if that read doesn’t lose information. In all other cases, we view them as MaybeUninit<[u8; N]>.

In raw bytes mode, a value is a list of bytes, each of which is uninitialized, a concrete u8 byte, or part of a pointer to a given target. This mimics how MiniRust represents allocations, except that we do not give a value to provenance-having bytes, since that value is non-deterministic. Instead, provenance is an enum, pointing to one of: a function, a global, a vtable or a TypeId (this mimics rustc).

Values we can’t represent (e.g. constants of a generic type) are read as ConstKind::Unsupported.