#[contracts::requires(...)] + #[contracts::ensures(...)]
cc https://github.com/rust-lang/rust/issues/128044
Updated contract support: attribute syntax for preconditions and postconditions, implemented via a series of desugarings that culminates in:
1. a compile-time flag (`-Z contract-checks`) that, similar to `-Z ub-checks`, attempts to ensure that the decision of enabling/disabling contract checks is delayed until the end user program is compiled,
2. invocations of lang-items that handle invoking the precondition, building a checker for the post-condition, and invoking that post-condition checker at the return sites for the function, and
3. intrinsics for the actual evaluation of pre- and post-condition predicates that third-party verification tools can intercept and reinterpret for their own purposes (e.g. creating shims of behavior that abstract away the function body and replace it solely with the pre- and post-conditions).
Known issues:
* My original intent, as described in the MCP (https://github.com/rust-lang/compiler-team/issues/759) was to have a rustc-prefixed attribute namespace (like rustc_contracts::requires). But I could not get things working when I tried to do rewriting via a rustc-prefixed builtin attribute-macro. So for now it is called `contracts::requires`.
* Our attribute macro machinery does not provide direct support for attribute arguments that are parsed like rust expressions. I spent some time trying to add that (e.g. something that would parse the attribute arguments as an AST while treating the remainder of the items as a token-tree), but its too big a lift for me to undertake. So instead I hacked in something approximating that goal, by semi-trivially desugaring the token-tree attribute contents into internal AST constucts. This may be too fragile for the long-term.
* (In particular, it *definitely* breaks when you try to add a contract to a function like this: `fn foo1(x: i32) -> S<{ 23 }> { ... }`, because its token-tree based search for where to inject the internal AST constructs cannot immediately see that the `{ 23 }` is within a generics list. I think we can live for this for the short-term, i.e. land the work, and continue working on it while in parallel adding a new attribute variant that takes a token-tree attribute alongside an AST annotation, which would completely resolve the issue here.)
* the *intent* of `-Z contract-checks` is that it behaves like `-Z ub-checks`, in that we do not prematurely commit to including or excluding the contract evaluation in upstream crates (most notably, `core` and `std`). But the current test suite does not actually *check* that this is the case. Ideally the test suite would be extended with a multi-crate test that explores the matrix of enabling/disabling contracts on both the upstream lib and final ("leaf") bin crates.
Use the type-level constant value `ty::Value` where needed
**Follow-up to #136180**
### Summary
This PR refactors functions to accept a single type-level constant value `ty::Value` instead of separate `ty::ValTree` and `ty::Ty` parameters:
- `valtree_to_const_value`: now takes `ty::Value`
- `pretty_print_const_valtree`: now takes `ty::Value`
- Uses `pretty_print_const_valtree` for formatting valtrees when `visit_const_operand`
- Moves `try_to_raw_bytes` from `ty::Valtree` to `ty::Value`
---
r? ``@lukas-code`` ``@oli-obk``
Remove hook calling via `TyCtxtAt`.
All hooks receive a `TyCtxtAt` argument.
Currently hooks can be called through `TyCtxtAt` or `TyCtxt`. In the latter case, a `TyCtxtAt` is constructed with a dummy span and passed to the hook.
However, in practice hooks are never called through `TyCtxtAt`, and always receive a dummy span. (I confirmed this via code inspection, and double-checked it by temporarily making the `TyCtxtAt` code path panic and running all the tests.)
This commit removes all the `TyCtxtAt` machinery for hooks. All hooks now receive `TyCtxt` instead of `TyCtxtAt`. There are two existing hooks that use `TyCtxtAt::span`: `const_caller_location_provider` and `try_destructure_mir_constant_for_user_output`. For both hooks the span is always a dummy span, probably unintentionally. This dummy span use is now explicit. If a non-dummy span is needed for these two hooks it would be easy to add it as an extra argument because hooks are less constrained than queries.
r? `@oli-obk`
All hooks receive a `TyCtxtAt` argument.
Currently hooks can be called through `TyCtxtAt` or `TyCtxt`. In the
latter case, a `TyCtxtAt` is constructed with a dummy span and passed to
the hook.
However, in practice hooks are never called through `TyCtxtAt`, and
always receive a dummy span. (I confirmed this via code inspection, and
double-checked it by temporarily making the `TyCtxtAt` code path panic
and running all the tests.)
This commit removes all the `TyCtxtAt` machinery for hooks. All hooks
now receive `TyCtxt` instead of `TyCtxtAt`. There are two existing hooks
that use `TyCtxtAt::span`: `const_caller_location_provider` and
`try_destructure_mir_constant_for_user_output`. For both hooks the span
is always a dummy span, probably unintentionally. This dummy span use is
now explicit. If a non-dummy span is needed for these two hooks it would
be easy to add it as an extra argument because hooks are less
constrained than queries.
Implement MIR lowering for unsafe binders
This is the final bit of the unsafe binders puzzle. It implements MIR, CTFE, and codegen for unsafe binders, and enforces that (for now) they are `Copy`. Later on, I'll introduce a new trait that relaxes this requirement to being "is `Copy` or `ManuallyDrop<T>`" which more closely models how we treat union fields.
Namely, wrapping unsafe binders is now `Rvalue::WrapUnsafeBinder`, which acts much like an `Rvalue::Aggregate`. Unwrapping unsafe binders are implemented as a MIR projection `ProjectionElem::UnwrapUnsafeBinder`, which acts much like `ProjectionElem::Field`.
Tracking:
- https://github.com/rust-lang/rust/issues/130516
Insert null checks for pointer dereferences when debug assertions are enabled
Similar to how the alignment is already checked, this adds a check
for null pointer dereferences in debug mode. It is implemented similarly
to the alignment check as a `MirPass`.
This inserts checks in the same places as the `CheckAlignment` pass and additionally
also inserts checks for `Borrows`, so code like
```rust
let ptr: *const u32 = std::ptr::null();
let val: &u32 = unsafe { &*ptr };
```
will have a check inserted on dereference. This is done because null references
are UB. The alignment check doesn't cover these places, because in `&(*ptr).field`,
the exact requirement is that the final reference must be aligned. This is something to
consider further enhancements of the alignment check.
For now this is implemented as a separate `MirPass`, to make it easy to disable
this check if necessary.
This is related to a 2025H1 project goal for better UB checks in debug
mode: https://github.com/rust-lang/rust-project-goals/pull/177.
r? `@saethlin`
Similar to how the alignment is already checked, this adds a check
for null pointer dereferences in debug mode. It is implemented similarly
to the alignment check as a MirPass.
This is related to a 2025H1 project goal for better UB checks in debug
mode: https://github.com/rust-lang/rust-project-goals/pull/177.
Fix deduplication mismatches in vtables leading to upcasting unsoundness
We currently have two cases where subtleties in supertraits can trigger disagreements in the vtable layout, e.g. leading to a different vtable layout being accessed at a callsite compared to what was prepared during unsizing. Namely:
### #135315
In this example, we were not normalizing supertraits when preparing vtables. In the example,
```
trait Supertrait<T> {
fn _print_numbers(&self, mem: &[usize; 100]) {
println!("{mem:?}");
}
}
impl<T> Supertrait<T> for () {}
trait Identity {
type Selff;
}
impl<Selff> Identity for Selff {
type Selff = Selff;
}
trait Middle<T>: Supertrait<()> + Supertrait<T> {
fn say_hello(&self, _: &usize) {
println!("Hello!");
}
}
impl<T> Middle<T> for () {}
trait Trait: Middle<<() as Identity>::Selff> {}
impl Trait for () {}
fn main() {
(&() as &dyn Trait as &dyn Middle<()>).say_hello(&0);
}
```
When we prepare `dyn Trait`, we see a supertrait of `Middle<<() as Identity>::Selff>`, which itself has two supertraits `Supertrait<()>` and `Supertrait<<() as Identity>::Selff>`. These two supertraits are identical, but they are not duplicated because we were using structural equality and *not* considering normalization. This leads to a vtable layout with two trait pointers.
When we upcast to `dyn Middle<()>`, those two supertraits are now the same, leading to a vtable layout with only one trait pointer. This leads to an offset error, and we call the wrong method.
### #135316
This one is a bit more interesting, and is the bulk of the changes in this PR. It's a bit similar, except it uses binder equality instead of normalization to make the compiler get confused about two vtable layouts. In the example,
```
trait Supertrait<T> {
fn _print_numbers(&self, mem: &[usize; 100]) {
println!("{mem:?}");
}
}
impl<T> Supertrait<T> for () {}
trait Trait<T, U>: Supertrait<T> + Supertrait<U> {
fn say_hello(&self, _: &usize) {
println!("Hello!");
}
}
impl<T, U> Trait<T, U> for () {}
fn main() {
(&() as &'static dyn for<'a> Trait<&'static (), &'a ()>
as &'static dyn Trait<&'static (), &'static ()>)
.say_hello(&0);
}
```
When we prepare the vtable for `dyn for<'a> Trait<&'static (), &'a ()>`, we currently consider the PolyTraitRef of the vtable as the key for a supertrait. This leads two two supertraits -- `Supertrait<&'static ()>` and `for<'a> Supertrait<&'a ()>`.
However, we can upcast[^up] without offsetting the vtable from `dyn for<'a> Trait<&'static (), &'a ()>` to `dyn Trait<&'static (), &'static ()>`. This is just instantiating the principal trait ref for a specific `'a = 'static`. However, when considering those supertraits, we now have only one distinct supertrait -- `Supertrait<&'static ()>` (which is deduplicated since there are two supertraits with the same substitutions). This leads to similar offsetting issues, leading to the wrong method being called.
[^up]: I say upcast but this is a cast that is allowed on stable, since it's not changing the vtable at all, just instantiating the binder of the principal trait ref for some lifetime.
The solution here is to recognize that a vtable isn't really meaningfully higher ranked, and to just treat a vtable as corresponding to a `TraitRef` so we can do this deduplication more faithfully. That is to say, the vtable for `dyn for<'a> Tr<'a>` and `dyn Tr<'x>` are always identical, since they both would correspond to a set of free regions on an impl... Do note that `Tr<for<'a> fn(&'a ())>` and `Tr<fn(&'static ())>` are still distinct.
----
There's a bit more that can be cleaned up. In codegen, we can stop using `PolyExistentialTraitRef` basically everywhere. We can also fix SMIR to stop storing `PolyExistentialTraitRef` in its vtable allocations.
As for testing, it's difficult to actually turn this into something that can be tested with `rustc_dump_vtable`, since having multiple supertraits that are identical is a recipe for ambiguity errors. Maybe someone else is more creative with getting that attr to work, since the tests I added being run-pass tests is a bit unsatisfying. Miri also doesn't help here, since it doesn't really generate vtables that are offset by an index in the same way as codegen.
r? `@lcnr` for the vibe check? Or reassign, idk. Maybe let's talk about whether this makes sense.
<sup>(I guess an alternative would also be to not do any deduplication of vtable supertraits (or only a really conservative subset) rather than trying to normalize and deduplicate more faithfully here. Not sure if that works and is sufficient tho.)</sup>
cc `@steffahn` -- ty for the minimizations
cc `@WaffleLapkin` -- since you're overseeing the feature stabilization :3
Fixes#135315Fixes#135316
miri: optimize zeroed alloc
When allocating zero-initialized memory in MIR interpretation, rustc allocates zeroed memory, marks it as initialized and then re-zeroes it. Remove the last step.
I don't expect this to have much of an effect on performance normally, but in my case in which I'm creating a large allocation via mmap it gets in the way.
- `check-pass` test for a MRE of #135020
- fail test for #135138
- switch to `TooGeneric` for checking CMSE fn signatures
- switch to `TooGeneric` for compute `SizeSkeleton` (for transmute)
- fix broken tests
```
error: `size_of_val` is not yet stable as a const intrinsic
--> $DIR/const-unstable-intrinsic.rs:17:9
|
LL | unstable_intrinsic::size_of_val(&x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(unstable)]` to the crate attributes to enable
help: add `#![feature(unstable)]` to the crate attributes to enable
|
LL + #![feature("unstable")]
|
```
When encountering a call corresponding to an item marked as unstable behind a feature flag, provide a structured suggestion pointing at where in the crate the `#![feature(..)]` needs to be written.
```
error: `foobar` is not yet stable as a const fn
--> $DIR/const-stability-attribute-implies-no-feature.rs:12:5
|
LL | foobar();
| ^^^^^^^^
|
help: add `#![feature(const_foobar)]` to the crate attributes to enable
|
LL + #![feature(const_foobar)]
|
```
Fix#81370.
This renames variables named `str` to other names, to make sure `str`
always refers to a type.
It's confusing to read code where `str` (or another standard type name)
is used as an identifier. It also produces misleading syntax
highlighting.
stabilize const_swap
libs-api FCP passed in https://github.com/rust-lang/rust/issues/83163.
However, I only just realized that this actually involves an intrinsic. The intrinsic could be implemented entirely with existing stable const functionality, but we choose to make it a primitive to be able to detect more UB. So nominating for `@rust-lang/lang` to make sure they are aware; I leave it up to them whether they want to FCP this.
While at it I also renamed the intrinsic to make the "nonoverlapping" constraint more clear.
Fixes#83163
Spruce up the docs of several queries related to the type/trait system and const eval
- Editorial
- Proper rustdoc summary/synopsis line by making use of extra paragraphs: Leads to better rendered output on module pages, in search result lists and overall, too
- Use rustdoc warning blocks for admonitions of the form "do not call / avoid calling this query directly"
- Use intra-doc links of the form ``[`Self::$query`]`` to cross-link queries. Indeed, such links are generally a bit brittle due to the existence of `TyCtxtFeed` which only contains a subset of queries. Therefore the docs of `feedable` queries cannot cross-link to non-`feedable` ones. I'd say it's fine to use intra-doc links despite the potential/unlikely occasional future breakage (if a query with the aforementioned characteristics becomes `feedable`). `Self::` is nicer than `TyCtxt::` (which would be more stable) since it accounts for other contexts like `TyCtxt{Feed,At,Ensure{,WithValue}}`
- Informative
- Generally add, flesh out and correct some doc comments
- Add *Panic* sections (to a few selected queries only). The lists of panics aren't necessarily exhaustive and focus on the more "obvious" or "important" panics.
- Where applicable add a paragraph calling attention to the relevant [`#[rustc_*]` TEST attribute](https://rustc-dev-guide.rust-lang.org/compiler-debugging.html#rustc_-test-attributes)
The one non-doc change (it's internal and not observable):
Be even more defensive in `query constness`'s impl (spiritual follow-up to #134122) (see self review comment).
Fixes#133494.
r\? **any**(compiler-errors, oli-obk)
ptr::copy: fix docs for the overlapping case
Fixes https://github.com/rust-lang/unsafe-code-guidelines/issues/549
As discussed in that issue, it doesn't make any sense for `copy` to read a byte via `src` after it was already written via `dst`. The entire point of this method is that is copies correctly even if they overlap, and that requires always reading any given location before writing it.
Cc `@rust-lang/opsem`
Begin to implement type system layer of unsafe binders
Mostly TODOs, but there's a lot of match arms that are basically just noops so I wanted to split these out before I put up the MIR lowering/projection part of this logic.
r? oli-obk
Tracking:
- https://github.com/rust-lang/rust/issues/130516
Use `MixedBitSet`s in const qualif
These analyses' domains should be very homogeneous, having compressed bitmaps on huge cfgs should make a difference (and doesn’t have an impact on the smaller / regular cfgs in our benchmarks).
This is a >40% walltime reduction on [this stress test](https://github.com/Manishearth/icu4x_compile_sample) extracted from a real world ICU case, and a 10x or so max-rss reduction.
cc `@oli-obk` `@RalfJung`
Should help with (or fix) issue #134404.
Variants::Single: do not use invalid VariantIdx for uninhabited enums
~~Stacked on top of https://github.com/rust-lang/rust/pull/133681, only the last commit is new.~~
Currently, `Variants::Single` for an empty enum contains a `VariantIdx` of 0; looking that up in the enum variant list will ICE. That's quite confusing. So let's fix that by adding a new `Variants::Empty` case for types that have 0 variants.
try-job: i686-msvc
Use field init shorthand where possible
Field init shorthand allows writing initializers like `tcx: tcx` as
`tcx`. The compiler already uses it extensively. Fix the last few places
where it isn't yet used.
EDIT: this PR also updates `rustfmt.toml` to set
`use_field_init_shorthand = true`.
`rustc_span::symbol` defines some things that are re-exported from
`rustc_span`, such as `Symbol` and `sym`. But it doesn't re-export some
closely related things such as `Ident` and `kw`. So you can do `use
rustc_span::{Symbol, sym}` but you have to do `use
rustc_span::symbol::{Ident, kw}`, which is inconsistent for no good
reason.
This commit re-exports `Ident`, `kw`, and `MacroRulesNormalizedIdent`,
and changes many `rustc_span::symbol::` qualifiers in `compiler/` to
`rustc_span::`. This is a 200+ net line of code reduction, mostly
because many files with two `use rustc_span` items can be reduced to
one.
Field init shorthand allows writing initializers like `tcx: tcx` as
`tcx`. The compiler already uses it extensively. Fix the last few places
where it isn't yet used.
Add some convenience helper methods on `hir::Safety`
Makes a lot of call sites simpler and should make any refactorings needed for https://github.com/rust-lang/rust/pull/134090#issuecomment-2541332415 simpler, as fewer sites have to be touched in case we end up storing some information in the variants of `hir::Safety`
Bounds-check with PtrMetadata instead of Len in MIR
Rather than emitting `Len(*_n)` in array index bounds checks, emit `PtrMetadata(copy _n)` instead -- with some asterisks for arrays and `&mut` that need it to be done slightly differently.
We're getting pretty close to removing `Len` entirely, actually. I think just one more PR after this (for slice drop shims).
r? mir
Make some types and methods related to Polonius + Miri public
We have a tool, [Aquascope](https://github.com/cognitive-engineering-lab/aquascope/), which uses Polonius and Miri to visualize the compile-time and run-time semantics of a Rust program. Changes in the last few months to both APIs have hidden away details we depend upon. This PR re-exposes some of those details, specifically:
**Polonius:**
- `BorrowSet` and `BorrowData` are added to `rustc_borrowck::consumers`, and their fields are made `pub` instead of `pub(crate)`. We need this to interpret the `BorrowIndex`es generated by Polonius.
- `BorrowSet::build` is now `pub`. We need this because the borrowck API doesn't provide access to the `BorrowSet` constructed during checking.
- `PoloniusRegionVid` is added to `rustc_borrowck::consumers`. We need this because it's also contained in the Polonius facts.
**Miri:**
- `InterpCx::local_to_op` is now a special case of `local_at_frame_to_op`, which allows querying locals in any frame. We need this because we walk the whole stack at each step to collect the state of memory.
- `InterpCx::layout_of_local` is now `pub`. We need this because we need to know the layout of every local at each step.
If these changes go against some design goal for keeping certain types private, please let me know so we can hash out a better solution. Additionally, if there's a better way to document that it's important that certain types stay public, also let me know. For example, `BorrowSet` was previously public but was hidden in 6676cec, breaking our build.
cc ```@RalfJung``` ```@nnethercote``` ```@gavinleroy```
Rollup of 7 pull requests
Successful merges:
- #133900 (Advent of `tests/ui` (misc cleanups and improvements) [1/N])
- #133937 (Keep track of parse errors in `mod`s and don't emit resolve errors for paths involving them)
- #133938 (`rustc_mir_dataflow` cleanups, including some renamings)
- #134058 (interpret: reduce usage of TypingEnv::fully_monomorphized)
- #134130 (Stop using driver queries in the public API)
- #134140 (Add AST support for unsafe binders)
- #134229 (Fix typos in docs on provenance)
r? `@ghost`
`@rustbot` modify labels: rollup
fix ICE on type error in promoted
Fixes https://github.com/rust-lang/rust/issues/133968
Ensure that when we turn a type error into a "this promoted failed to evaluate" error, we do record this as something that may happen even in "infallible" promoteds.
The words "before" and "after" have an obvious temporal meaning, e.g.
`seek_before_primary_effect`,
`visit_statement_{before,after}_primary_effect`. But "before" is also
used to name the effect that occurs before the primary effect of a
statement/terminator; this is `Effect::Before`. This leads to the
confusing possibility of talking about things happening "before/after
the before event".
This commit removes this awkward overloading of "before" by renaming
`Effect::Before` as `Effect::Early`. It also renames some of the
`Analysis` and `ResultsVisitor` methods to be more consistent.
Here are the before and after names:
- `Effect::{Before,Primary}` -> `Effect::{Early,Primary}`
- `apply_before_statement_effect` -> `apply_early_statement_effect`
- `apply_statement_effect` -> `apply_primary_statement_effect`
- `visit_statement_before_primary_effect` -> `visit_after_early_statement_effect`
- `visit_statement_after_primary_effect` -> `visit_after_primary_statement_effect`
(And s/statement/terminator/ for all the terminator events.)