Merge from rustc

This commit is contained in:
The Miri Conjob Bot 2024-01-26 05:09:55 +00:00
commit b07da7103f
254 changed files with 4580 additions and 2955 deletions

View file

@ -367,10 +367,13 @@ fn copy_self_contained_objects(
let srcdir = builder
.wasi_root(target)
.unwrap_or_else(|| {
panic!("Target {:?} does not have a \"wasi-root\" key", target.triple)
panic!(
"Target {:?} does not have a \"wasi-root\" key in Config.toml",
target.triple
)
})
.join("lib")
.join(target.to_string().replace("-preview1", ""));
.join(target.to_string().replace("-preview1", "").replace("-preview2", ""));
for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] {
copy_and_stamp(
builder,

View file

@ -88,7 +88,7 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
(Some(Mode::Std), "no_sync", None),
(Some(Mode::Std), "backtrace_in_libstd", None),
/* Extra values not defined in the built-in targets yet, but used in std */
(Some(Mode::Std), "target_env", Some(&["libnx"])),
(Some(Mode::Std), "target_env", Some(&["libnx", "preview2"])),
// (Some(Mode::Std), "target_os", Some(&[])),
// #[cfg(bootstrap)] zkvm
(Some(Mode::Std), "target_os", Some(&["zkvm"])),

View file

@ -59,6 +59,7 @@
- [*-unknown-openbsd](platform-support/openbsd.md)
- [\*-unknown-uefi](platform-support/unknown-uefi.md)
- [wasm32-wasi-preview1-threads](platform-support/wasm32-wasi-preview1-threads.md)
- [wasm32-wasi-preview2](platform-support/wasm32-wasi-preview2.md)
- [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
- [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md)
- [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)

View file

@ -360,6 +360,7 @@ target | std | host | notes
`thumbv7a-pc-windows-msvc` | ? | |
`thumbv7a-uwp-windows-msvc` | ✓ | |
`thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7-A Linux with NEON, MUSL
[`wasm32-wasi-preview2`](platform-support/wasm32-wasi-preview2.md) | ✓ | | WebAssembly
[`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly
`x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64
[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS

View file

@ -0,0 +1,30 @@
# `wasm32-wasi-preview2`
**Tier: 3**
The `wasm32-wasi-preview2` target is a new and still (as of January 2024) an
experimental target. This target is an extension to `wasm32-wasi-preview1` target,
originally known as `wasm32-wasi`. It is the next evolution in the development of
wasi (the [WebAssembly System Interface](https://wasi.dev)) that uses the WebAssembly
[component model] to allow for a standardized set of syscalls that are intended to empower
WebAssembly binaries with native host capabilities.
[component model]: https://github.com/WebAssembly/component-model
## Target maintainers
- Alex Crichton, https://github.com/alexcrichton
- Ryan Levick, https://github.com/rylev
## Requirements
This target is cross-compiled. The target supports `std` fully.
## Platform requirements
The WebAssembly runtime should support the wasi preview 2 API set.
This target is not a stable target. This means that there are only a few engines
which implement wasi preview 2, for example:
* Wasmtime - `-W component-model`

View file

@ -36,6 +36,10 @@ For a full history of changes in the Rust 2024 style edition, see the git
history of the style guide. Notable changes in the Rust 2024 style edition
include:
- [#114764](https://github.com/rust-lang/rust/pull/114764) As the last member
of a delimited expression, delimited expressions are generally combinable,
regardless of the number of members. Previously only applied with exactly
one member (except for closures with explicit blocks).
- Miscellaneous `rustfmt` bugfixes.
- Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
- Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".

View file

@ -818,11 +818,11 @@ E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not.
## Combinable expressions
Where a function call has a single argument, and that argument is formatted
across multiple-lines, format the outer call as if it were a single-line call,
When the last argument in a function call is formatted across
multiple-lines, format the outer call as if it were a single-line call,
if the result fits. Apply the same combining behaviour to any similar
expressions which have multi-line, block-indented lists of sub-expressions
delimited by parentheses (e.g., macros or tuple struct literals). E.g.,
delimited by parentheses, brackets, or braces. E.g.,
```rust
foo(bar(
@ -848,20 +848,61 @@ let arr = [combinable(
an_expr,
another_expr,
)];
let x = Thing(an_expr, another_expr, match cond {
A => 1,
B => 2,
});
let x = format!("Stuff: {}", [
an_expr,
another_expr,
]);
let x = func(an_expr, another_expr, SomeStruct {
field: this_is_long,
another_field: 123,
});
```
Apply this behavior recursively.
For a function with multiple arguments, if the last argument is a multi-line
closure with an explicit block, there are no other closure arguments, and all
the arguments and the first line of the closure fit on the first line, use the
same combining behavior:
If the last argument is a multi-line closure with an explicit block,
only apply the combining behavior if there are no other closure arguments.
```rust
// Combinable
foo(first_arg, x, |param| {
action();
foo(param)
})
// Not combinable, because the closure is not the last argument
foo(
first_arg,
|param| {
action();
foo(param)
},
whatever,
)
// Not combinable, because the first line of the closure does not fit
foo(
first_arg,
x,
move |very_long_param_causing_line_to_overflow| -> Bar {
action();
foo(param)
},
)
// Not combinable, because there is more than one closure argument
foo(
first_arg,
|x| x.bar(),
|param| {
action();
foo(param)
},
)
```
## Ranges

View file

@ -1,8 +1,8 @@
<pre class="rust item-decl"><code>
{{ self.render_attributes_in_pre() | safe }}
{{ self.render_union() | safe }}
{{ self.render_attributes_in_pre()|safe }}
{{ self.render_union()|safe }}
</code></pre>
{{ self.document() | safe }}
{{ self.document()|safe }}
{% if self.fields_iter().peek().is_some() %}
<h2 id="fields" class="fields section-header"> {# #}
Fields<a href="#fields" class="anchor">§</a> {# #}
@ -12,13 +12,13 @@
<span id="structfield.{{ name }}" {#+ #}
class="{{ ItemType::StructField +}} section-header"> {# #}
<a href="#structfield.{{ name }}" class="anchor field">§</a> {# #}
<code>{{ name }}: {{+ self.print_ty(ty) | safe }}</code> {# #}
<code>{{ name }}: {{+ self.print_ty(ty)|safe }}</code> {# #}
</span>
{% if let Some(stability_class) = self.stability_field(field) %}
<span class="stab {{ stability_class }}"></span>
{% endif %}
{{ self.document_field(field) | safe }}
{{ self.document_field(field)|safe }}
{% endfor %}
{% endif %}
{{ self.render_assoc_items() | safe }}
{{ self.document_type_layout() | safe }}
{{ self.render_assoc_items()|safe }}
{{ self.document_type_layout()|safe }}

View file

@ -11,8 +11,6 @@ fn main() {
// This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071)
match FOO_REF_REF {
FOO_REF_REF => {},
//~^ ERROR: to use a constant of type `Foo` in a pattern, `Foo` must be annotated
//~| NOTE: for more information, see issue #62411 <https://github.com/rust-lang/ru
Foo(_) => {},
}
}

View file

@ -1,15 +0,0 @@
error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
--> $DIR/ice-6254.rs:13:9
|
LL | FOO_REF_REF => {},
| ^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
= note: the traits must be derived, manual `impl`s are not sufficient
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
= note: `-D indirect-structural-match` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(indirect_structural_match)]`
error: aborting due to 1 previous error

View file

@ -33,7 +33,6 @@ fn main() {
INT_MIN % NEG_ONE;
//~^ ERROR: this operation will panic at runtime
//~| ERROR: any number modulo -1 will panic/overflow or result in 0
// ONLY caught by rustc
// Not caught by lint, we don't look into static items, even if entirely immutable.
INT_MIN % STATIC_NEG_ONE;
//~^ ERROR: this operation will panic at runtime
}

View file

@ -12,12 +12,6 @@ error: this operation will panic at runtime
LL | INT_MIN % NEG_ONE;
| ^^^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
error: this operation will panic at runtime
--> $DIR/modulo_one.rs:37:5
|
LL | INT_MIN % STATIC_NEG_ONE;
| ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
error: any number modulo 1 will be 0
--> $DIR/modulo_one.rs:8:5
|
@ -57,5 +51,5 @@ error: any number modulo -1 will panic/overflow or result in 0
LL | INT_MIN % NEG_ONE;
| ^^^^^^^^^^^^^^^^^
error: aborting due to 9 previous errors
error: aborting due to 8 previous errors

View file

@ -1109,9 +1109,6 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
}
fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
if config.system_llvm && line.starts_with("no-system-llvm") {
return IgnoreDecision::Ignore { reason: "ignored when the system LLVM is used".into() };
}
if let Some(needed_components) =
config.parse_name_value_directive(line, "needs-llvm-components")
{

View file

@ -242,15 +242,6 @@ fn aux_build() {
);
}
#[test]
fn no_system_llvm() {
let config: Config = cfg().system_llvm(false).build();
assert!(!check_ignore(&config, "// no-system-llvm"));
let config: Config = cfg().system_llvm(true).build();
assert!(check_ignore(&config, "// no-system-llvm"));
}
#[test]
fn llvm_version() {
let config: Config = cfg().llvm_version("8.1.2").build();
@ -266,6 +257,18 @@ fn llvm_version() {
assert!(!check_ignore(&config, "// min-llvm-version: 9.0"));
}
#[test]
fn system_llvm_version() {
let config: Config = cfg().system_llvm(true).llvm_version("17.0.0").build();
assert!(check_ignore(&config, "// min-system-llvm-version: 18.0"));
let config: Config = cfg().system_llvm(true).llvm_version("18.0.0").build();
assert!(!check_ignore(&config, "// min-system-llvm-version: 18.0"));
let config: Config = cfg().llvm_version("17.0.0").build();
assert!(!check_ignore(&config, "// min-system-llvm-version: 18.0"));
}
#[test]
fn ignore_target() {
let config: Config = cfg().target("x86_64-unknown-linux-gnu").build();

View file

@ -3,6 +3,7 @@
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
use std::collections::hash_map::Entry;
use std::fmt;
use std::path::Path;
use std::process;
@ -10,6 +11,7 @@ use std::process;
use either::Either;
use rand::rngs::StdRng;
use rand::SeedableRng;
use rand::Rng;
use rustc_ast::ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@ -45,6 +47,11 @@ pub const SIGRTMIN: i32 = 34;
/// `SIGRTMAX` - `SIGRTMIN` >= 8 (which is the value of `_POSIX_RTSIG_MAX`)
pub const SIGRTMAX: i32 = 42;
/// Each const has multiple addresses, but only this many. Since const allocations are never
/// deallocated, choosing a new [`AllocId`] and thus base address for each evaluation would
/// produce unbounded memory usage.
const ADDRS_PER_CONST: usize = 16;
/// Extra data stored with each stack frame
pub struct FrameExtra<'tcx> {
/// Extra data for the Borrow Tracker.
@ -65,12 +72,18 @@ pub struct FrameExtra<'tcx> {
/// optimization.
/// This is used by `MiriMachine::current_span` and `MiriMachine::caller_span`
pub is_user_relevant: bool,
/// We have a cache for the mapping from [`mir::Const`] to resulting [`AllocId`].
/// However, we don't want all frames to always get the same result, so we insert
/// an additional bit of "salt" into the cache key. This salt is fixed per-frame
/// so that within a call, a const will have a stable address.
salt: usize,
}
impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Omitting `timing`, it does not support `Debug`.
let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _ } = self;
let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } = self;
f.debug_struct("FrameData")
.field("borrow_tracker", borrow_tracker)
.field("catch_unwind", catch_unwind)
@ -80,7 +93,7 @@ impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
impl VisitProvenance for FrameExtra<'_> {
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _ } = self;
let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } = self;
catch_unwind.visit_provenance(visit);
borrow_tracker.visit_provenance(visit);
@ -552,6 +565,11 @@ pub struct MiriMachine<'mir, 'tcx> {
/// The spans we will use to report where an allocation was created and deallocated in
/// diagnostics.
pub(crate) allocation_spans: RefCell<FxHashMap<AllocId, (Span, Option<Span>)>>,
/// Maps MIR consts to their evaluated result. We combine the const with a "salt" (`usize`)
/// that is fixed per stack frame; this lets us have sometimes different results for the
/// same const while ensuring consistent results within a single call.
const_cache: RefCell<FxHashMap<(mir::Const<'tcx>, usize), OpTy<'tcx, Provenance>>>,
}
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
@ -677,6 +695,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
stack_size,
collect_leak_backtraces: config.collect_leak_backtraces,
allocation_spans: RefCell::new(FxHashMap::default()),
const_cache: RefCell::new(FxHashMap::default()),
}
}
@ -788,6 +807,7 @@ impl VisitProvenance for MiriMachine<'_, '_> {
stack_size: _,
collect_leak_backtraces: _,
allocation_spans: _,
const_cache: _,
} = self;
threads.visit_provenance(visit);
@ -1345,6 +1365,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
catch_unwind: None,
timing,
is_user_relevant: ecx.machine.is_user_relevant(&frame),
salt: ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_CONST,
};
Ok(frame.with_extra(extra))
@ -1450,4 +1471,31 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None));
Ok(())
}
fn eval_mir_constant<F>(
ecx: &InterpCx<'mir, 'tcx, Self>,
val: mir::Const<'tcx>,
span: Option<Span>,
layout: Option<TyAndLayout<'tcx>>,
eval: F,
) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>
where
F: Fn(
&InterpCx<'mir, 'tcx, Self>,
mir::Const<'tcx>,
Option<Span>,
Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>,
{
let frame = ecx.active_thread_stack().last().unwrap();
let mut cache = ecx.machine.const_cache.borrow_mut();
match cache.entry((val, frame.extra.salt)) {
Entry::Vacant(ve) => {
let op = eval(ecx, val, span, layout)?;
ve.insert(op.clone());
Ok(op)
}
Entry::Occupied(oe) => Ok(oe.get().clone()),
}
}
}

View file

@ -5,6 +5,7 @@ use std::iter;
use log::trace;
use rand::Rng;
use rustc_apfloat::{Float, Round};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::{
@ -141,6 +142,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_pointer(Pointer::new(ptr.provenance, masked_addr), dest)?;
}
// We want to return either `true` or `false` at random, or else something like
// ```
// if !is_val_statically_known(0) { unreachable_unchecked(); }
// ```
// Would not be considered UB, or the other way around (`is_val_statically_known(0)`).
"is_val_statically_known" => {
let [_] = check_arg_count(args)?;
let branch: bool = this.machine.rng.get_mut().gen();
this.write_scalar(Scalar::from_bool(branch), dest)?;
}
// Floating-point operations
"fabsf32" => {
let [f] = check_arg_count(args)?;

View file

@ -0,0 +1,38 @@
// The const fn interpreter creates a new AllocId every time it evaluates any const.
// If we do that in Miri, repeatedly evaluating a const causes unbounded memory use
// we need to keep track of the base address for that AllocId, and the allocation is never
// deallocated.
// In Miri we explicitly store previously-assigned AllocIds for each const and ensure
// that we only hand out a finite number of AllocIds per const.
// MIR inlining will put every evaluation of the const we're repeatedly evaluting into the same
// stack frame, breaking this test.
//@compile-flags: -Zinline-mir=no
#![feature(strict_provenance)]
const EVALS: usize = 256;
use std::collections::HashSet;
fn main() {
let mut addrs = HashSet::new();
for _ in 0..EVALS {
addrs.insert(const_addr());
}
// Check that the const allocation has multiple base addresses
assert!(addrs.len() > 1);
// But also that we get a limited number of unique base addresses
assert!(addrs.len() < EVALS);
// Check that within a call we always produce the same address
let mut prev = 0;
for iter in 0..EVALS {
let addr = "test".as_bytes().as_ptr().addr();
if iter > 0 {
assert_eq!(prev, addr);
}
prev = addr;
}
}
fn const_addr() -> usize {
"test".as_bytes().as_ptr().addr()
}

View file

@ -33,6 +33,21 @@ fn main() {
assert_eq!(intrinsics::likely(false), false);
assert_eq!(intrinsics::unlikely(true), true);
let mut saw_true = false;
let mut saw_false = false;
for _ in 0..50 {
if unsafe { intrinsics::is_val_statically_known(0) } {
saw_true = true;
} else {
saw_false = true;
}
}
assert!(
saw_true && saw_false,
"`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!"
);
intrinsics::forget(Bomb);
let _v = intrinsics::discriminant_value(&Some(()));