Merge from rustc
This commit is contained in:
commit
b07da7103f
254 changed files with 4580 additions and 2955 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"])),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
30
src/doc/rustc/src/platform-support/wasm32-wasi-preview2.md
Normal file
30
src/doc/rustc/src/platform-support/wasm32-wasi-preview2.md
Normal 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`
|
||||
|
|
@ -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".
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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(_) => {},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
|
|
|||
38
src/tools/miri/tests/pass/const-addrs.rs
Normal file
38
src/tools/miri/tests/pass/const-addrs.rs
Normal 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()
|
||||
}
|
||||
|
|
@ -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(()));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue