crosses Says No as Well as YesStatus: Accepted
Date: September 16, 2026
Related: ADR-312 (the crossing verdict, and its three
answers), ADR-281 D29 (locks, three-valued for the same
reason), ADR-290 (a described crate, whose describer fills the
column), ADR-005 §1 Group B, Part III 13.5
Whether a value may cross a thread has three answers — may, may not,
undecided — and two refusals fire on may not. With a crosses column of
two values, true for may and absent for undecided, no described type
could answer may not, and at the destination the refusals guard they could
never fire.
examples/foreign-runtime/ describes a crate whose handle holds an
Rc<String>, a value that provably does not cross a thread, and a two-valued
column cannot say so. locks met the same shape and became three-valued, because
reading nothing said as no refuses correct programs and reading it as
yes is a promise that fails open.
crosses has three values: true, false, and absent.crosses = true is the claim a value of this type may cross a thread, as
it was. crosses = false is the claim it may not, and is what produces
may not at the destination a task goes to. Absent stays nothing recorded,
which is not permission. Every ledger already written keeps its meaning.
nikaia describe writes crosses = false for a type whose fields hold a
thing the language below marks as not sendable — an Rc, a raw pointer —
which a field reader can see and a reviewer can check; true where every
field is a scalar, a String, or one of those inside a container that changes
nothing; nothing where it cannot tell, which is the common answer. A Cell or
RefCell is not on the list: it is !Sync but may be moved to another thread
exactly when its T may, so false for it would be a claim that is untrue.
An Arc<T>, a field of another crate’s type and a tuple struct fall to
silence, because nobody looked is not it holds nothing. That is
ADR-290’s second step with one more column in it.
NK2501 and NK2502 fire on a described foreign type that does not cross,
on the .nika line, with no word of rustc’s in the message.false says what it
said.crosses for a Nikaia struct, which walks its fields and needs
no column.crosses that depends on a type parameter (Box[T] crosses where T
does); a single value per type is enough for every entry the corpus has.NK2502 asks its question only of a call nothing describes
(ADR-303 D7), so a value with crosses = false handed to a
described foreign call is still refused by rustc’s Send bound, not here.
That is a column of its own.false is read whatever the type’s arguments; true is not read on a type
with arguments. The claim is about the type, and the polarity decides
(ADR-010 D1): a promise is withheld where the line might not
have spoken about the T, and a restriction is kept, because nothing a value
is wrapped in makes it crossable.