Auto merge of #136085 - jhpratt:rollup-dxmb2h2, r=jhpratt
Rollup of 7 pull requests Successful merges: - #133951 (Make the wasm_c_abi future compat warning a hard error) - #134283 (fix(libtest): Deprecate '--logfile') - #135785 (use `PassMode::Direct` for vector types on `s390x`) - #135948 (Update emscripten std tests) - #135951 (Use `fmt::from_fn` in more places in the compiler) - #136031 (Expand polonius MIR dump) - #136032 (Account for mutable borrow in argument suggestion) Failed merges: - #135635 (Move `std::io::pipe` code into its own file) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c2270becb6
55 changed files with 743 additions and 409 deletions
|
@ -1,7 +1,9 @@
|
|||
use std::io;
|
||||
|
||||
use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options};
|
||||
use rustc_middle::mir::{Body, ClosureRegionRequirements, PassWhere};
|
||||
use rustc_middle::mir::pretty::{
|
||||
PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
|
||||
};
|
||||
use rustc_middle::mir::{Body, ClosureRegionRequirements};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::MirIncludeSpans;
|
||||
|
||||
|
@ -10,9 +12,6 @@ use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSe
|
|||
use crate::{BorrowckInferCtxt, RegionInferenceContext};
|
||||
|
||||
/// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information.
|
||||
// Note: this currently duplicates most of NLL MIR, with some additions for the localized outlives
|
||||
// constraints. This is ok for now as this dump will change in the near future to an HTML file to
|
||||
// become more useful.
|
||||
pub(crate) fn dump_polonius_mir<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
|
@ -26,12 +25,100 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
return;
|
||||
}
|
||||
|
||||
if !dump_enabled(tcx, "polonius", body.source.def_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let localized_outlives_constraints = localized_outlives_constraints
|
||||
.expect("missing localized constraints with `-Zpolonius=next`");
|
||||
|
||||
// We want the NLL extra comments printed by default in NLL MIR dumps (they were removed in
|
||||
// #112346). Specifying `-Z mir-include-spans` on the CLI still has priority: for example,
|
||||
// they're always disabled in mir-opt tests to make working with blessed dumps easier.
|
||||
let _: io::Result<()> = try {
|
||||
let mut file = create_dump_file(tcx, "html", false, "polonius", &0, body)?;
|
||||
emit_polonius_dump(
|
||||
tcx,
|
||||
body,
|
||||
regioncx,
|
||||
borrow_set,
|
||||
localized_outlives_constraints,
|
||||
closure_region_requirements,
|
||||
&mut file,
|
||||
)?;
|
||||
};
|
||||
}
|
||||
|
||||
/// The polonius dump consists of:
|
||||
/// - the NLL MIR
|
||||
/// - the list of polonius localized constraints
|
||||
/// - a mermaid graph of the CFG
|
||||
fn emit_polonius_dump<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
localized_outlives_constraints: LocalizedOutlivesConstraintSet,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
// Prepare the HTML dump file prologue.
|
||||
writeln!(out, "<!DOCTYPE html>")?;
|
||||
writeln!(out, "<html>")?;
|
||||
writeln!(out, "<head><title>Polonius MIR dump</title></head>")?;
|
||||
writeln!(out, "<body>")?;
|
||||
|
||||
// Section 1: the NLL + Polonius MIR.
|
||||
writeln!(out, "<div>")?;
|
||||
writeln!(out, "Raw MIR dump")?;
|
||||
writeln!(out, "<code><pre>")?;
|
||||
emit_html_mir(
|
||||
tcx,
|
||||
body,
|
||||
regioncx,
|
||||
borrow_set,
|
||||
localized_outlives_constraints,
|
||||
closure_region_requirements,
|
||||
out,
|
||||
)?;
|
||||
writeln!(out, "</pre></code>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
// Section 2: mermaid visualization of the CFG.
|
||||
writeln!(out, "<div>")?;
|
||||
writeln!(out, "Control-flow graph")?;
|
||||
writeln!(out, "<code><pre class='mermaid'>")?;
|
||||
emit_mermaid_cfg(body, out)?;
|
||||
writeln!(out, "</pre></code>")?;
|
||||
writeln!(out, "</div>")?;
|
||||
|
||||
// Finalize the dump with the HTML epilogue.
|
||||
writeln!(
|
||||
out,
|
||||
"<script src='https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'></script>"
|
||||
)?;
|
||||
writeln!(out, "<script>")?;
|
||||
writeln!(out, "mermaid.initialize({{ startOnLoad: false, maxEdges: 100 }});")?;
|
||||
writeln!(out, "mermaid.run({{ querySelector: '.mermaid' }})")?;
|
||||
writeln!(out, "</script>")?;
|
||||
writeln!(out, "</body>")?;
|
||||
writeln!(out, "</html>")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits the polonius MIR, as escaped HTML.
|
||||
fn emit_html_mir<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
localized_outlives_constraints: LocalizedOutlivesConstraintSet,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
// Buffer the regular MIR dump to be able to escape it.
|
||||
let mut buffer = Vec::new();
|
||||
|
||||
// We want the NLL extra comments printed by default in NLL MIR dumps. Specifying `-Z
|
||||
// mir-include-spans` on the CLI still has priority.
|
||||
let options = PrettyPrintMirOptions {
|
||||
include_extra_comments: matches!(
|
||||
tcx.sess.opts.unstable_opts.mir_include_spans,
|
||||
|
@ -39,12 +126,12 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
),
|
||||
};
|
||||
|
||||
dump_mir_with_options(
|
||||
dump_mir_to_writer(
|
||||
tcx,
|
||||
false,
|
||||
"polonius",
|
||||
&0,
|
||||
body,
|
||||
&mut buffer,
|
||||
|pass_where, out| {
|
||||
emit_polonius_mir(
|
||||
tcx,
|
||||
|
@ -57,7 +144,27 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
)
|
||||
},
|
||||
options,
|
||||
);
|
||||
)?;
|
||||
|
||||
// Escape the handful of characters that need it. We don't need to be particularly efficient:
|
||||
// we're actually writing into a buffered writer already. Note that MIR dumps are valid UTF-8.
|
||||
let buffer = String::from_utf8_lossy(&buffer);
|
||||
for ch in buffer.chars() {
|
||||
let escaped = match ch {
|
||||
'>' => ">",
|
||||
'<' => "<",
|
||||
'&' => "&",
|
||||
'\'' => "'",
|
||||
'"' => """,
|
||||
_ => {
|
||||
// The common case, no escaping needed.
|
||||
write!(out, "{}", ch)?;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
write!(out, "{}", escaped)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Produces the actual NLL + Polonius MIR sections to emit during the dumping process.
|
||||
|
@ -102,3 +209,55 @@ fn emit_polonius_mir<'tcx>(
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits a mermaid flowchart of the CFG blocks and edges, similar to the graphviz version.
|
||||
fn emit_mermaid_cfg(body: &Body<'_>, out: &mut dyn io::Write) -> io::Result<()> {
|
||||
use rustc_middle::mir::{TerminatorEdges, TerminatorKind};
|
||||
|
||||
// The mermaid chart type: a top-down flowchart.
|
||||
writeln!(out, "flowchart TD")?;
|
||||
|
||||
// Emit the block nodes.
|
||||
for (block_idx, block) in body.basic_blocks.iter_enumerated() {
|
||||
let block_idx = block_idx.as_usize();
|
||||
let cleanup = if block.is_cleanup { " (cleanup)" } else { "" };
|
||||
writeln!(out, "{block_idx}[\"bb{block_idx}{cleanup}\"]")?;
|
||||
}
|
||||
|
||||
// Emit the edges between blocks, from the terminator edges.
|
||||
for (block_idx, block) in body.basic_blocks.iter_enumerated() {
|
||||
let block_idx = block_idx.as_usize();
|
||||
let terminator = block.terminator();
|
||||
match terminator.edges() {
|
||||
TerminatorEdges::None => {}
|
||||
TerminatorEdges::Single(bb) => {
|
||||
writeln!(out, "{block_idx} --> {}", bb.as_usize())?;
|
||||
}
|
||||
TerminatorEdges::Double(bb1, bb2) => {
|
||||
if matches!(terminator.kind, TerminatorKind::FalseEdge { .. }) {
|
||||
writeln!(out, "{block_idx} --> {}", bb1.as_usize())?;
|
||||
writeln!(out, "{block_idx} -- imaginary --> {}", bb2.as_usize())?;
|
||||
} else {
|
||||
writeln!(out, "{block_idx} --> {}", bb1.as_usize())?;
|
||||
writeln!(out, "{block_idx} -- unwind --> {}", bb2.as_usize())?;
|
||||
}
|
||||
}
|
||||
TerminatorEdges::AssignOnReturn { return_, cleanup, .. } => {
|
||||
for to_idx in return_ {
|
||||
writeln!(out, "{block_idx} --> {}", to_idx.as_usize())?;
|
||||
}
|
||||
|
||||
if let Some(to_idx) = cleanup {
|
||||
writeln!(out, "{block_idx} -- unwind --> {}", to_idx.as_usize())?;
|
||||
}
|
||||
}
|
||||
TerminatorEdges::SwitchInt { targets, .. } => {
|
||||
for to_idx in targets.all_targets() {
|
||||
writeln!(out, "{block_idx} --> {}", to_idx.as_usize())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1285,13 +1285,13 @@ impl fmt::Debug for OwnerNodes<'_> {
|
|||
.field("node", &self.nodes[ItemLocalId::ZERO])
|
||||
.field(
|
||||
"parents",
|
||||
&self
|
||||
.nodes
|
||||
.iter_enumerated()
|
||||
.map(|(id, parented_node)| {
|
||||
debug_fn(move |f| write!(f, "({id:?}, {:?})", parented_node.parent))
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
&fmt::from_fn(|f| {
|
||||
f.debug_list()
|
||||
.entries(self.nodes.iter_enumerated().map(|(id, parented_node)| {
|
||||
fmt::from_fn(move |f| write!(f, "({id:?}, {:?})", parented_node.parent))
|
||||
}))
|
||||
.finish()
|
||||
}),
|
||||
)
|
||||
.field("bodies", &self.bodies)
|
||||
.field("opt_hash_including_bodies", &self.opt_hash_including_bodies)
|
||||
|
@ -4638,15 +4638,5 @@ mod size_asserts {
|
|||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
|
||||
struct DebugFn<F>(F);
|
||||
impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(self.0)(fmt)
|
||||
}
|
||||
}
|
||||
DebugFn(f)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(closure_track_caller)]
|
||||
#![feature(debug_closure_helpers)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(never_type)]
|
||||
|
|
|
@ -184,6 +184,50 @@ enum Scope<'a> {
|
|||
},
|
||||
}
|
||||
|
||||
impl<'a> Scope<'a> {
|
||||
// A helper for debugging scopes without printing parent scopes
|
||||
fn debug_truncated(&'a self) -> impl fmt::Debug + 'a {
|
||||
fmt::from_fn(move |f| match self {
|
||||
Self::Binder { bound_vars, scope_type, hir_id, where_bound_origin, s: _ } => f
|
||||
.debug_struct("Binder")
|
||||
.field("bound_vars", bound_vars)
|
||||
.field("scope_type", scope_type)
|
||||
.field("hir_id", hir_id)
|
||||
.field("where_bound_origin", where_bound_origin)
|
||||
.field("s", &"..")
|
||||
.finish(),
|
||||
Self::Opaque { captures, def_id, s: _ } => f
|
||||
.debug_struct("Opaque")
|
||||
.field("def_id", def_id)
|
||||
.field("captures", &captures.borrow())
|
||||
.field("s", &"..")
|
||||
.finish(),
|
||||
Self::Body { id, s: _ } => {
|
||||
f.debug_struct("Body").field("id", id).field("s", &"..").finish()
|
||||
}
|
||||
Self::ObjectLifetimeDefault { lifetime, s: _ } => f
|
||||
.debug_struct("ObjectLifetimeDefault")
|
||||
.field("lifetime", lifetime)
|
||||
.field("s", &"..")
|
||||
.finish(),
|
||||
Self::Supertrait { bound_vars, s: _ } => f
|
||||
.debug_struct("Supertrait")
|
||||
.field("bound_vars", bound_vars)
|
||||
.field("s", &"..")
|
||||
.finish(),
|
||||
Self::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
|
||||
Self::LateBoundary { s: _, what, deny_late_regions } => f
|
||||
.debug_struct("LateBoundary")
|
||||
.field("what", what)
|
||||
.field("deny_late_regions", deny_late_regions)
|
||||
.finish(),
|
||||
Self::Root { opt_parent_item } => {
|
||||
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum BinderScopeType {
|
||||
/// Any non-concatenating binder scopes.
|
||||
|
@ -200,52 +244,6 @@ enum BinderScopeType {
|
|||
Concatenating,
|
||||
}
|
||||
|
||||
// A helper struct for debugging scopes without printing parent scopes
|
||||
struct TruncatedScopeDebug<'a>(&'a Scope<'a>);
|
||||
|
||||
impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.0 {
|
||||
Scope::Binder { bound_vars, scope_type, hir_id, where_bound_origin, s: _ } => f
|
||||
.debug_struct("Binder")
|
||||
.field("bound_vars", bound_vars)
|
||||
.field("scope_type", scope_type)
|
||||
.field("hir_id", hir_id)
|
||||
.field("where_bound_origin", where_bound_origin)
|
||||
.field("s", &"..")
|
||||
.finish(),
|
||||
Scope::Opaque { captures, def_id, s: _ } => f
|
||||
.debug_struct("Opaque")
|
||||
.field("def_id", def_id)
|
||||
.field("captures", &captures.borrow())
|
||||
.field("s", &"..")
|
||||
.finish(),
|
||||
Scope::Body { id, s: _ } => {
|
||||
f.debug_struct("Body").field("id", id).field("s", &"..").finish()
|
||||
}
|
||||
Scope::ObjectLifetimeDefault { lifetime, s: _ } => f
|
||||
.debug_struct("ObjectLifetimeDefault")
|
||||
.field("lifetime", lifetime)
|
||||
.field("s", &"..")
|
||||
.finish(),
|
||||
Scope::Supertrait { bound_vars, s: _ } => f
|
||||
.debug_struct("Supertrait")
|
||||
.field("bound_vars", bound_vars)
|
||||
.field("s", &"..")
|
||||
.finish(),
|
||||
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
|
||||
Scope::LateBoundary { s: _, what, deny_late_regions } => f
|
||||
.debug_struct("LateBoundary")
|
||||
.field("what", what)
|
||||
.field("deny_late_regions", deny_late_regions)
|
||||
.finish(),
|
||||
Scope::Root { opt_parent_item } => {
|
||||
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ScopeRef<'a> = &'a Scope<'a>;
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
|
@ -1144,7 +1142,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
{
|
||||
let BoundVarContext { tcx, map, .. } = self;
|
||||
let mut this = BoundVarContext { tcx: *tcx, map, scope: &wrap_scope };
|
||||
let span = debug_span!("scope", scope = ?TruncatedScopeDebug(this.scope));
|
||||
let span = debug_span!("scope", scope = ?this.scope.debug_truncated());
|
||||
{
|
||||
let _enter = span.enter();
|
||||
f(&mut this);
|
||||
|
|
|
@ -63,6 +63,7 @@ This API is completely unstable and subject to change.
|
|||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(coroutines)]
|
||||
#![feature(debug_closure_helpers)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_from_coroutine)]
|
||||
#![feature(iter_intersperse)]
|
||||
|
|
|
@ -851,32 +851,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&& let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
|
||||
|
||||
// Look for the type corresponding to the argument pattern we have in the argument list.
|
||||
&& let Some(ty_sugg) = fn_decl
|
||||
&& let Some(ty_ref) = fn_decl
|
||||
.inputs
|
||||
.iter()
|
||||
.filter_map(|ty| {
|
||||
if ty.span == *ty_span
|
||||
&& let hir::TyKind::Ref(lt, x) = ty.kind
|
||||
{
|
||||
// `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
|
||||
Some((
|
||||
x.ty.span.shrink_to_lo(),
|
||||
format!(
|
||||
"{}mut ",
|
||||
if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " }
|
||||
),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
.filter_map(|ty| match ty.kind {
|
||||
hir::TyKind::Ref(lt, mut_ty) if ty.span == *ty_span => Some((lt, mut_ty)),
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
{
|
||||
let sugg = vec![
|
||||
ty_sugg,
|
||||
let mut sugg = if ty_ref.1.mutbl.is_mut() {
|
||||
// Leave `&'name mut Ty` and `&mut Ty` as they are (#136028).
|
||||
vec![]
|
||||
} else {
|
||||
// `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
|
||||
vec![(
|
||||
ty_ref.1.ty.span.shrink_to_lo(),
|
||||
format!(
|
||||
"{}mut ",
|
||||
if ty_ref.0.ident.span.lo() == ty_ref.0.ident.span.hi() { "" } else { " " },
|
||||
),
|
||||
)]
|
||||
};
|
||||
sugg.extend([
|
||||
(pat.span.until(ident.span), String::new()),
|
||||
(lhs.span.shrink_to_lo(), "*".to_string()),
|
||||
];
|
||||
]);
|
||||
// We suggest changing the argument from `mut ident: &Ty` to `ident: &'_ mut Ty` and the
|
||||
// assignment from `ident = val;` to `*ident = val;`.
|
||||
err.multipart_suggestion_verbose(
|
||||
|
|
|
@ -974,6 +974,3 @@ lint_uses_power_alignment = repr(C) does not follow the power alignment rule. Th
|
|||
|
||||
lint_variant_size_differences =
|
||||
enum variant is more than three times larger ({$largest} bytes) than the next largest
|
||||
|
||||
lint_wasm_c_abi =
|
||||
older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88
|
||||
|
|
|
@ -430,7 +430,6 @@ pub(super) fn decorate_lint(
|
|||
BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
|
||||
lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
|
||||
}
|
||||
BuiltinLintDiag::WasmCAbi => lints::WasmCAbi.decorate_lint(diag),
|
||||
BuiltinLintDiag::IllFormedAttributeInput { suggestions } => {
|
||||
lints::IllFormedAttributeInput {
|
||||
num_suggestions: suggestions.len(),
|
||||
|
|
|
@ -2553,10 +2553,6 @@ pub(crate) struct UnusedCrateDependency {
|
|||
pub local_crate: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_wasm_c_abi)]
|
||||
pub(crate) struct WasmCAbi;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_ill_formed_attribute_input)]
|
||||
pub(crate) struct IllFormedAttributeInput {
|
||||
|
|
|
@ -144,7 +144,6 @@ declare_lint_pass! {
|
|||
UNUSED_VARIABLES,
|
||||
USELESS_DEPRECATED,
|
||||
WARNINGS,
|
||||
WASM_C_ABI,
|
||||
// tidy-alphabetical-end
|
||||
]
|
||||
}
|
||||
|
@ -4681,44 +4680,6 @@ declare_lint! {
|
|||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `wasm_c_abi` lint detects crate dependencies that are incompatible
|
||||
/// with future versions of Rust that will emit spec-compliant C ABI.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,ignore (needs extern crate)
|
||||
/// #![deny(wasm_c_abi)]
|
||||
/// ```
|
||||
///
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// error: the following packages contain code that will be rejected by a future version of Rust: wasm-bindgen v0.2.87
|
||||
/// |
|
||||
/// note: the lint level is defined here
|
||||
/// --> src/lib.rs:1:9
|
||||
/// |
|
||||
/// 1 | #![deny(wasm_c_abi)]
|
||||
/// | ^^^^^^^^^^
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Rust has historically emitted non-spec-compliant C ABI. This has caused
|
||||
/// incompatibilities between other compilers and Wasm targets. In a future
|
||||
/// version of Rust this will be fixed and therefore dependencies relying
|
||||
/// on the non-spec-compliant C ABI will stop functioning.
|
||||
pub WASM_C_ABI,
|
||||
Deny,
|
||||
"detects dependencies that are incompatible with the Wasm C ABI",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
|
||||
reference: "issue #71871 <https://github.com/rust-lang/rust/issues/71871>",
|
||||
};
|
||||
crate_level_only
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `uncovered_param_in_projection` lint detects a violation of one of Rust's orphan rules for
|
||||
/// foreign trait implementations that concerns the use of type parameters inside trait associated
|
||||
|
|
|
@ -795,7 +795,6 @@ pub enum BuiltinLintDiag {
|
|||
extern_crate: Symbol,
|
||||
local_crate: Symbol,
|
||||
},
|
||||
WasmCAbi,
|
||||
IllFormedAttributeInput {
|
||||
suggestions: Vec<String>,
|
||||
},
|
||||
|
|
|
@ -290,6 +290,9 @@ metadata_unsupported_abi =
|
|||
metadata_unsupported_abi_i686 =
|
||||
ABI not supported by `#[link(kind = "raw-dylib")]` on i686
|
||||
|
||||
metadata_wasm_c_abi =
|
||||
older versions of the `wasm-bindgen` crate are incompatible with current versions of Rust; please update to `wasm-bindgen` v0.2.88
|
||||
|
||||
metadata_wasm_import_form =
|
||||
wasm import module must be of the form `wasm_import_module = "string"`
|
||||
|
||||
|
|
|
@ -1076,12 +1076,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
|||
// Make a point span rather than covering the whole file
|
||||
let span = krate.spans.inner_span.shrink_to_lo();
|
||||
|
||||
self.sess.psess.buffer_lint(
|
||||
lint::builtin::WASM_C_ABI,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::WasmCAbi,
|
||||
);
|
||||
self.sess.dcx().emit_err(errors::WasmCAbi { span });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -732,3 +732,10 @@ pub struct ImportNameTypeRaw {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(metadata_wasm_c_abi)]
|
||||
pub(crate) struct WasmCAbi {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#![feature(const_type_name)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(coroutines)]
|
||||
#![feature(debug_closure_helpers)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(discriminant_kind)]
|
||||
#![feature(extern_types)]
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use std::collections::BTreeSet;
|
||||
use std::fmt::{Display, Write as _};
|
||||
use std::fs;
|
||||
use std::io::{self, Write as _};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{fs, io};
|
||||
|
||||
use rustc_abi::Size;
|
||||
use rustc_ast::InlineAsmTemplatePiece;
|
||||
|
@ -149,37 +148,59 @@ pub fn dump_enabled(tcx: TyCtxt<'_>, pass_name: &str, def_id: DefId) -> bool {
|
|||
// `def_path_str()` would otherwise trigger `type_of`, and this can
|
||||
// run while we are already attempting to evaluate `type_of`.
|
||||
|
||||
/// Most use-cases of dumping MIR should use the [dump_mir] entrypoint instead, which will also
|
||||
/// check if dumping MIR is enabled, and if this body matches the filters passed on the CLI.
|
||||
///
|
||||
/// That being said, if the above requirements have been validated already, this function is where
|
||||
/// most of the MIR dumping occurs, if one needs to export it to a file they have created with
|
||||
/// [create_dump_file], rather than to a new file created as part of [dump_mir], or to stdout/stderr
|
||||
/// for debugging purposes.
|
||||
pub fn dump_mir_to_writer<'tcx, F>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
pass_name: &str,
|
||||
disambiguator: &dyn Display,
|
||||
body: &Body<'tcx>,
|
||||
w: &mut dyn io::Write,
|
||||
mut extra_data: F,
|
||||
options: PrettyPrintMirOptions,
|
||||
) -> io::Result<()>
|
||||
where
|
||||
F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>,
|
||||
{
|
||||
// see notes on #41697 above
|
||||
let def_path =
|
||||
ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id()));
|
||||
// ignore-tidy-odd-backticks the literal below is fine
|
||||
write!(w, "// MIR for `{def_path}")?;
|
||||
match body.source.promoted {
|
||||
None => write!(w, "`")?,
|
||||
Some(promoted) => write!(w, "::{promoted:?}`")?,
|
||||
}
|
||||
writeln!(w, " {disambiguator} {pass_name}")?;
|
||||
if let Some(ref layout) = body.coroutine_layout_raw() {
|
||||
writeln!(w, "/* coroutine_layout = {layout:#?} */")?;
|
||||
}
|
||||
writeln!(w)?;
|
||||
extra_data(PassWhere::BeforeCFG, w)?;
|
||||
write_user_type_annotations(tcx, body, w)?;
|
||||
write_mir_fn(tcx, body, &mut extra_data, w, options)?;
|
||||
extra_data(PassWhere::AfterCFG, w)
|
||||
}
|
||||
|
||||
fn dump_matched_mir_node<'tcx, F>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
pass_num: bool,
|
||||
pass_name: &str,
|
||||
disambiguator: &dyn Display,
|
||||
body: &Body<'tcx>,
|
||||
mut extra_data: F,
|
||||
extra_data: F,
|
||||
options: PrettyPrintMirOptions,
|
||||
) where
|
||||
F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>,
|
||||
{
|
||||
let _: io::Result<()> = try {
|
||||
let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?;
|
||||
// see notes on #41697 above
|
||||
let def_path =
|
||||
ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id()));
|
||||
// ignore-tidy-odd-backticks the literal below is fine
|
||||
write!(file, "// MIR for `{def_path}")?;
|
||||
match body.source.promoted {
|
||||
None => write!(file, "`")?,
|
||||
Some(promoted) => write!(file, "::{promoted:?}`")?,
|
||||
}
|
||||
writeln!(file, " {disambiguator} {pass_name}")?;
|
||||
if let Some(ref layout) = body.coroutine_layout_raw() {
|
||||
writeln!(file, "/* coroutine_layout = {layout:#?} */")?;
|
||||
}
|
||||
writeln!(file)?;
|
||||
extra_data(PassWhere::BeforeCFG, &mut file)?;
|
||||
write_user_type_annotations(tcx, body, &mut file)?;
|
||||
write_mir_fn(tcx, body, &mut extra_data, &mut file, options)?;
|
||||
extra_data(PassWhere::AfterCFG, &mut file)?;
|
||||
dump_mir_to_writer(tcx, pass_name, disambiguator, body, &mut file, extra_data, options)?;
|
||||
};
|
||||
|
||||
if tcx.sess.opts.unstable_opts.dump_mir_graphviz {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//! Values computed by queries that use MIR.
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
|
@ -62,55 +61,26 @@ pub struct CoroutineLayout<'tcx> {
|
|||
|
||||
impl Debug for CoroutineLayout<'_> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// Prints an iterator of (key, value) tuples as a map.
|
||||
struct MapPrinter<'a, K, V>(Cell<Option<Box<dyn Iterator<Item = (K, V)> + 'a>>>);
|
||||
impl<'a, K, V> MapPrinter<'a, K, V> {
|
||||
fn new(iter: impl Iterator<Item = (K, V)> + 'a) -> Self {
|
||||
Self(Cell::new(Some(Box::new(iter))))
|
||||
}
|
||||
}
|
||||
impl<'a, K: Debug, V: Debug> Debug for MapPrinter<'a, K, V> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt.debug_map().entries(self.0.take().unwrap()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the coroutine variant name.
|
||||
struct GenVariantPrinter(VariantIdx);
|
||||
impl From<VariantIdx> for GenVariantPrinter {
|
||||
fn from(idx: VariantIdx) -> Self {
|
||||
GenVariantPrinter(idx)
|
||||
}
|
||||
}
|
||||
impl Debug for GenVariantPrinter {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let variant_name = ty::CoroutineArgs::variant_name(self.0);
|
||||
if fmt.alternate() {
|
||||
write!(fmt, "{:9}({:?})", variant_name, self.0)
|
||||
} else {
|
||||
write!(fmt, "{variant_name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Forces its contents to print in regular mode instead of alternate mode.
|
||||
struct OneLinePrinter<T>(T);
|
||||
impl<T: Debug> Debug for OneLinePrinter<T> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.debug_struct("CoroutineLayout")
|
||||
.field("field_tys", &MapPrinter::new(self.field_tys.iter_enumerated()))
|
||||
.field(
|
||||
"variant_fields",
|
||||
&MapPrinter::new(
|
||||
self.variant_fields
|
||||
.iter_enumerated()
|
||||
.map(|(k, v)| (GenVariantPrinter(k), OneLinePrinter(v))),
|
||||
),
|
||||
)
|
||||
.field_with("field_tys", |fmt| {
|
||||
fmt.debug_map().entries(self.field_tys.iter_enumerated()).finish()
|
||||
})
|
||||
.field_with("variant_fields", |fmt| {
|
||||
let mut map = fmt.debug_map();
|
||||
for (idx, fields) in self.variant_fields.iter_enumerated() {
|
||||
map.key_with(|fmt| {
|
||||
let variant_name = ty::CoroutineArgs::variant_name(idx);
|
||||
if fmt.alternate() {
|
||||
write!(fmt, "{variant_name:9}({idx:?})")
|
||||
} else {
|
||||
write!(fmt, "{variant_name}")
|
||||
}
|
||||
});
|
||||
// Force variant fields to print in regular mode instead of alternate mode.
|
||||
map.value_with(|fmt| write!(fmt, "{fields:?}"));
|
||||
}
|
||||
map.finish()
|
||||
})
|
||||
.field("storage_conflicts", &self.storage_conflicts)
|
||||
.finish()
|
||||
}
|
||||
|
|
|
@ -581,9 +581,11 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
pub enum TerminatorEdges<'mir, 'tcx> {
|
||||
/// For terminators that have no successor, like `return`.
|
||||
None,
|
||||
/// For terminators that a single successor, like `goto`, and `assert` without cleanup block.
|
||||
/// For terminators that have a single successor, like `goto`, and `assert` without a cleanup
|
||||
/// block.
|
||||
Single(BasicBlock),
|
||||
/// For terminators that two successors, `assert` with cleanup block and `falseEdge`.
|
||||
/// For terminators that have two successors, like `assert` with a cleanup block, and
|
||||
/// `falseEdge`.
|
||||
Double(BasicBlock, BasicBlock),
|
||||
/// Special action for `Yield`, `Call` and `InlineAsm` terminators.
|
||||
AssignOnReturn {
|
||||
|
|
|
@ -2325,51 +2325,41 @@ macro_rules! sty_debug_print {
|
|||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
pub fn debug_stats(self) -> impl std::fmt::Debug + 'tcx {
|
||||
struct DebugStats<'tcx>(TyCtxt<'tcx>);
|
||||
pub fn debug_stats(self) -> impl fmt::Debug + 'tcx {
|
||||
fmt::from_fn(move |fmt| {
|
||||
sty_debug_print!(
|
||||
fmt,
|
||||
self,
|
||||
Adt,
|
||||
Array,
|
||||
Slice,
|
||||
RawPtr,
|
||||
Ref,
|
||||
FnDef,
|
||||
FnPtr,
|
||||
UnsafeBinder,
|
||||
Placeholder,
|
||||
Coroutine,
|
||||
CoroutineWitness,
|
||||
Dynamic,
|
||||
Closure,
|
||||
CoroutineClosure,
|
||||
Tuple,
|
||||
Bound,
|
||||
Param,
|
||||
Infer,
|
||||
Alias,
|
||||
Pat,
|
||||
Foreign
|
||||
)?;
|
||||
|
||||
impl<'tcx> std::fmt::Debug for DebugStats<'tcx> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
sty_debug_print!(
|
||||
fmt,
|
||||
self.0,
|
||||
Adt,
|
||||
Array,
|
||||
Slice,
|
||||
RawPtr,
|
||||
Ref,
|
||||
FnDef,
|
||||
FnPtr,
|
||||
UnsafeBinder,
|
||||
Placeholder,
|
||||
Coroutine,
|
||||
CoroutineWitness,
|
||||
Dynamic,
|
||||
Closure,
|
||||
CoroutineClosure,
|
||||
Tuple,
|
||||
Bound,
|
||||
Param,
|
||||
Infer,
|
||||
Alias,
|
||||
Pat,
|
||||
Foreign
|
||||
)?;
|
||||
writeln!(fmt, "GenericArgs interner: #{}", self.interners.args.len())?;
|
||||
writeln!(fmt, "Region interner: #{}", self.interners.region.len())?;
|
||||
writeln!(fmt, "Const Allocation interner: #{}", self.interners.const_allocation.len())?;
|
||||
writeln!(fmt, "Layout interner: #{}", self.interners.layout.len())?;
|
||||
|
||||
writeln!(fmt, "GenericArgs interner: #{}", self.0.interners.args.len())?;
|
||||
writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?;
|
||||
writeln!(
|
||||
fmt,
|
||||
"Const Allocation interner: #{}",
|
||||
self.0.interners.const_allocation.len()
|
||||
)?;
|
||||
writeln!(fmt, "Layout interner: #{}", self.0.interners.layout.len())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
DebugStats(self)
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1598,45 +1598,35 @@ impl<'a> Parser<'a> {
|
|||
// Only used when debugging.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ {
|
||||
struct DebugParser<'dbg> {
|
||||
parser: &'dbg Parser<'dbg>,
|
||||
lookahead: usize,
|
||||
}
|
||||
fmt::from_fn(move |f| {
|
||||
let mut dbg_fmt = f.debug_struct("Parser"); // or at least, one view of
|
||||
|
||||
impl fmt::Debug for DebugParser<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { parser, lookahead } = self;
|
||||
let mut dbg_fmt = f.debug_struct("Parser"); // or at least, one view of
|
||||
|
||||
// we don't need N spans, but we want at least one, so print all of prev_token
|
||||
dbg_fmt.field("prev_token", &parser.prev_token);
|
||||
let mut tokens = vec![];
|
||||
for i in 0..*lookahead {
|
||||
let tok = parser.look_ahead(i, |tok| tok.kind.clone());
|
||||
let is_eof = tok == TokenKind::Eof;
|
||||
tokens.push(tok);
|
||||
if is_eof {
|
||||
// Don't look ahead past EOF.
|
||||
break;
|
||||
}
|
||||
// we don't need N spans, but we want at least one, so print all of prev_token
|
||||
dbg_fmt.field("prev_token", &self.prev_token);
|
||||
let mut tokens = vec![];
|
||||
for i in 0..lookahead {
|
||||
let tok = self.look_ahead(i, |tok| tok.kind.clone());
|
||||
let is_eof = tok == TokenKind::Eof;
|
||||
tokens.push(tok);
|
||||
if is_eof {
|
||||
// Don't look ahead past EOF.
|
||||
break;
|
||||
}
|
||||
dbg_fmt.field_with("tokens", |field| field.debug_list().entries(tokens).finish());
|
||||
dbg_fmt.field("approx_token_stream_pos", &parser.num_bump_calls);
|
||||
|
||||
// some fields are interesting for certain values, as they relate to macro parsing
|
||||
if let Some(subparser) = parser.subparser_name {
|
||||
dbg_fmt.field("subparser_name", &subparser);
|
||||
}
|
||||
if let Recovery::Forbidden = parser.recovery {
|
||||
dbg_fmt.field("recovery", &parser.recovery);
|
||||
}
|
||||
|
||||
// imply there's "more to know" than this view
|
||||
dbg_fmt.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
dbg_fmt.field_with("tokens", |field| field.debug_list().entries(tokens).finish());
|
||||
dbg_fmt.field("approx_token_stream_pos", &self.num_bump_calls);
|
||||
|
||||
DebugParser { parser: self, lookahead }
|
||||
// some fields are interesting for certain values, as they relate to macro parsing
|
||||
if let Some(subparser) = self.subparser_name {
|
||||
dbg_fmt.field("subparser_name", &subparser);
|
||||
}
|
||||
if let Recovery::Forbidden = self.recovery {
|
||||
dbg_fmt.field("recovery", &self.recovery);
|
||||
}
|
||||
|
||||
// imply there's "more to know" than this view
|
||||
dbg_fmt.finish_non_exhaustive()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn clear_expected_token_types(&mut self) {
|
||||
|
|
|
@ -1791,7 +1791,7 @@ pub(crate) struct UnusedAssign {
|
|||
pub(crate) struct UnusedAssignSuggestion {
|
||||
pub pre: &'static str,
|
||||
#[suggestion_part(code = "{pre}mut ")]
|
||||
pub ty_span: Span,
|
||||
pub ty_span: Option<Span>,
|
||||
#[suggestion_part(code = "")]
|
||||
pub ty_ref_span: Span,
|
||||
#[suggestion_part(code = "*")]
|
||||
|
|
|
@ -1620,24 +1620,28 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
|||
&& let item = self.ir.tcx.hir_owner_node(item_id)
|
||||
&& let Some(fn_decl) = item.fn_decl()
|
||||
&& let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
|
||||
&& let Some((ty_span, pre)) = fn_decl
|
||||
&& let Some((lt, mut_ty)) = fn_decl
|
||||
.inputs
|
||||
.iter()
|
||||
.filter_map(|ty| {
|
||||
if ty.span == *ty_span
|
||||
&& let hir::TyKind::Ref(lt, mut_ty) = ty.kind
|
||||
{
|
||||
// `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
|
||||
Some((
|
||||
mut_ty.ty.span.shrink_to_lo(),
|
||||
if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " },
|
||||
))
|
||||
Some((lt, mut_ty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.next()
|
||||
{
|
||||
let ty_span = if mut_ty.mutbl.is_mut() {
|
||||
// Leave `&'name mut Ty` and `&mut Ty` as they are (#136028).
|
||||
None
|
||||
} else {
|
||||
// `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
|
||||
Some(mut_ty.ty.span.shrink_to_lo())
|
||||
};
|
||||
let pre = if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " };
|
||||
Some(errors::UnusedAssignSuggestion {
|
||||
ty_span,
|
||||
pre,
|
||||
|
|
|
@ -38,9 +38,17 @@ where
|
|||
}
|
||||
|
||||
let size = arg.layout.size;
|
||||
if size.bits() <= 128 && arg.layout.is_single_vector_element(cx, size) {
|
||||
arg.cast_to(Reg { kind: RegKind::Vector, size });
|
||||
return;
|
||||
if size.bits() <= 128 {
|
||||
if let BackendRepr::Vector { .. } = arg.layout.backend_repr {
|
||||
// pass non-wrapped vector types using `PassMode::Direct`
|
||||
return;
|
||||
}
|
||||
|
||||
if arg.layout.is_single_vector_element(cx, size) {
|
||||
// pass non-transparant wrappers around a vector as `PassMode::Cast`
|
||||
arg.cast_to(Reg { kind: RegKind::Vector, size });
|
||||
return;
|
||||
}
|
||||
}
|
||||
if !arg.layout.is_aggregate() && size.bits() <= 64 {
|
||||
arg.extend_integer_width_to(64);
|
||||
|
|
|
@ -353,6 +353,7 @@ pub fn iter_10k(b: &mut Bencher) {
|
|||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)] // hits an OOM
|
||||
pub fn iter_1m(b: &mut Bencher) {
|
||||
bench_iter(b, 1_000, 1_000_000);
|
||||
}
|
||||
|
|
|
@ -366,14 +366,25 @@ rotate!(rotate_medium_half, gen_random, 9158, 9158 / 2);
|
|||
rotate!(rotate_medium_half_plus_one, gen_random, 9158, 9158 / 2 + 1);
|
||||
|
||||
// Intended to use more RAM than the machine has cache
|
||||
#[cfg(not(target_os = "emscripten"))] // hits an OOM
|
||||
rotate!(rotate_huge_by1, gen_random, 5 * 1024 * 1024, 1);
|
||||
#[cfg(not(target_os = "emscripten"))] // hits an OOM
|
||||
rotate!(rotate_huge_by9199_u64, gen_random, 5 * 1024 * 1024, 9199);
|
||||
#[cfg(not(target_os = "emscripten"))] // hits an OOM
|
||||
rotate!(rotate_huge_by9199_bytes, gen_random_bytes, 5 * 1024 * 1024, 9199);
|
||||
#[cfg(not(target_os = "emscripten"))] // hits an OOM
|
||||
rotate!(rotate_huge_by9199_strings, gen_strings, 5 * 1024 * 1024, 9199);
|
||||
#[cfg(not(target_os = "emscripten"))] // hits an OOM
|
||||
rotate!(rotate_huge_by9199_big, gen_big_random, 5 * 1024 * 1024, 9199);
|
||||
#[cfg(not(target_os = "emscripten"))] // hits an OOM
|
||||
rotate!(rotate_huge_by1234577_u64, gen_random, 5 * 1024 * 1024, 1234577);
|
||||
#[cfg(not(target_os = "emscripten"))] // hits an OOM
|
||||
rotate!(rotate_huge_by1234577_bytes, gen_random_bytes, 5 * 1024 * 1024, 1234577);
|
||||
#[cfg(not(target_os = "emscripten"))] // hits an OOM
|
||||
rotate!(rotate_huge_by1234577_strings, gen_strings, 5 * 1024 * 1024, 1234577);
|
||||
#[cfg(not(target_os = "emscripten"))] // hits an OOM
|
||||
rotate!(rotate_huge_by1234577_big, gen_big_random, 5 * 1024 * 1024, 1234577);
|
||||
#[cfg(not(target_os = "emscripten"))] // hits an OOM
|
||||
rotate!(rotate_huge_half, gen_random, 5 * 1024 * 1024, 5 * 1024 * 1024 / 2);
|
||||
#[cfg(not(target_os = "emscripten"))] // hits an OOM
|
||||
rotate!(rotate_huge_half_plus_one, gen_random, 5 * 1024 * 1024, 5 * 1024 * 1024 / 2 + 1);
|
||||
|
|
|
@ -547,6 +547,11 @@ fn bench_in_place_collect_droppable(b: &mut Bencher) {
|
|||
})
|
||||
}
|
||||
|
||||
// node.js gives out of memory error to use with length 1_100_000
|
||||
#[cfg(target_os = "emscripten")]
|
||||
const LEN: usize = 4096;
|
||||
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
const LEN: usize = 16384;
|
||||
|
||||
#[bench]
|
||||
|
|
|
@ -502,9 +502,7 @@ fn test_retain_catch_unwind() {
|
|||
// even if the order might not be correct.
|
||||
//
|
||||
// Destructors must be called exactly once per element.
|
||||
// FIXME: re-enable emscripten once it can unwind again
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||
fn panic_safe() {
|
||||
use std::cmp;
|
||||
|
|
|
@ -94,9 +94,6 @@ fn test_rng() -> rand_xorshift::XorShiftRng {
|
|||
rand::SeedableRng::from_seed(seed)
|
||||
}
|
||||
|
||||
// FIXME: Instantiated functions with i128 in the signature is not supported in Emscripten.
|
||||
// See https://github.com/kripken/emscripten-fastcomp/issues/169
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
#[test]
|
||||
fn test_boxed_hasher() {
|
||||
let ordinary_hash = hash(&5u32);
|
||||
|
|
|
@ -1414,7 +1414,6 @@ fn test_box_slice_clone() {
|
|||
|
||||
#[test]
|
||||
#[allow(unused_must_use)] // here, we care about the side effects of `.clone()`
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||
fn test_box_slice_clone_panics() {
|
||||
use std::sync::Arc;
|
||||
|
|
|
@ -11,7 +11,14 @@ use crate::sort::{Sort, known_good_stable_sort, patterns};
|
|||
#[cfg(miri)]
|
||||
const TEST_LENGTHS: &[usize] = &[2, 3, 4, 7, 10, 15, 20, 24, 33, 50, 100, 171, 300];
|
||||
|
||||
#[cfg(not(miri))]
|
||||
// node.js gives out of memory error to use with length 1_100_000
|
||||
#[cfg(all(not(miri), target_os = "emscripten"))]
|
||||
const TEST_LENGTHS: &[usize] = &[
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 20, 24, 30, 32, 33, 35, 50, 100, 200, 500, 1_000,
|
||||
2_048, 5_000, 10_000, 100_000,
|
||||
];
|
||||
|
||||
#[cfg(all(not(miri), not(target_os = "emscripten")))]
|
||||
const TEST_LENGTHS: &[usize] = &[
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 20, 24, 30, 32, 33, 35, 50, 100, 200, 500, 1_000,
|
||||
2_048, 5_000, 10_000, 100_000, 1_100_000,
|
||||
|
|
|
@ -128,6 +128,7 @@ fn try_unwrap() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
|
||||
fn into_inner() {
|
||||
for _ in 0..100
|
||||
// ^ Increase chances of hitting potential race conditions
|
||||
|
|
|
@ -1587,9 +1587,7 @@ fn extract_if_complex() {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: re-enable emscripten once it can unwind again
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||
fn extract_if_consumed_panic() {
|
||||
use std::rc::Rc;
|
||||
|
@ -1640,9 +1638,7 @@ fn extract_if_consumed_panic() {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Re-enable emscripten once it can catch panics
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||
fn extract_if_unconsumed_panic() {
|
||||
use std::rc::Rc;
|
||||
|
|
|
@ -141,9 +141,6 @@ fn test_custom_state() {
|
|||
// const { assert!(hash(&Custom { hash: 6 }) == 6) };
|
||||
}
|
||||
|
||||
// FIXME: Instantiated functions with i128 in the signature is not supported in Emscripten.
|
||||
// See https://github.com/kripken/emscripten-fastcomp/issues/169
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
#[test]
|
||||
fn test_indirect_hasher() {
|
||||
let mut hasher = MyHasher { hash: 0 };
|
||||
|
|
|
@ -84,9 +84,6 @@ where
|
|||
F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
|
||||
G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
|
||||
{
|
||||
if cfg!(target_os = "emscripten") {
|
||||
return; // using rng pulls in i128 support, which doesn't work
|
||||
}
|
||||
let mut rng = crate::test_rng();
|
||||
let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000);
|
||||
iterate("f32_random_equivalence_test", k, n, f, g, |_| {
|
||||
|
@ -100,9 +97,6 @@ where
|
|||
F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
|
||||
G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
|
||||
{
|
||||
if cfg!(target_os = "emscripten") {
|
||||
return; // using rng pulls in i128 support, which doesn't work
|
||||
}
|
||||
let mut rng = crate::test_rng();
|
||||
let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
|
||||
iterate("f64_random_equivalence_test", k, n, f, g, |_| {
|
||||
|
|
|
@ -51,9 +51,7 @@ macro_rules! test_op {
|
|||
};
|
||||
}
|
||||
|
||||
test_op!(test_neg_defined, Neg::neg(0), 0, i8, i16, i32, i64, f32, f64);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
test_op!(test_neg_defined_128, Neg::neg(0), 0, i128);
|
||||
test_op!(test_neg_defined, Neg::neg(0), 0, i8, i16, i32, i64, i128, f32, f64);
|
||||
|
||||
test_op!(test_not_defined_bool, Not::not(true), false, bool);
|
||||
|
||||
|
@ -69,17 +67,17 @@ macro_rules! test_arith_op {
|
|||
i16,
|
||||
i32,
|
||||
i64,
|
||||
i128,
|
||||
isize,
|
||||
u8,
|
||||
u16,
|
||||
u32,
|
||||
u64,
|
||||
u128,
|
||||
usize,
|
||||
f32,
|
||||
f64
|
||||
);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
impls_defined!($op, $method($lhs, $rhs), 0, i128, u128);
|
||||
}
|
||||
};
|
||||
($fn_name:ident, $op:ident::$method:ident(&mut $lhs:literal, $rhs:literal)) => {
|
||||
|
@ -93,17 +91,17 @@ macro_rules! test_arith_op {
|
|||
i16,
|
||||
i32,
|
||||
i64,
|
||||
i128,
|
||||
isize,
|
||||
u8,
|
||||
u16,
|
||||
u32,
|
||||
u64,
|
||||
u128,
|
||||
usize,
|
||||
f32,
|
||||
f64
|
||||
);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
impls_defined!($op, $method(&mut $lhs, $rhs), 0, i128, u128);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -131,15 +129,15 @@ macro_rules! test_bitop {
|
|||
i16,
|
||||
i32,
|
||||
i64,
|
||||
i128,
|
||||
isize,
|
||||
u8,
|
||||
u16,
|
||||
u32,
|
||||
u64,
|
||||
u128,
|
||||
usize
|
||||
);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
impls_defined!($op, $method(0, 0), 0, i128, u128);
|
||||
impls_defined!($op, $method(false, false), false, bool);
|
||||
}
|
||||
};
|
||||
|
@ -156,15 +154,15 @@ macro_rules! test_bitop_assign {
|
|||
i16,
|
||||
i32,
|
||||
i64,
|
||||
i128,
|
||||
isize,
|
||||
u8,
|
||||
u16,
|
||||
u32,
|
||||
u64,
|
||||
u128,
|
||||
usize
|
||||
);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
impls_defined!($op, $method(&mut 0, 0), 0, i128, u128);
|
||||
impls_defined!($op, $method(&mut false, false), false, bool);
|
||||
}
|
||||
};
|
||||
|
@ -182,9 +180,11 @@ macro_rules! test_shift_inner {
|
|||
$(impl_defined!($op, $method(0,0), 0, $lt, $rt);)+
|
||||
};
|
||||
($op:ident::$method:ident, $lt:ty) => {
|
||||
test_shift_inner!($op::$method, $lt, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
test_shift_inner!($op::$method, $lt, i128, u128);
|
||||
test_shift_inner!(
|
||||
$op::$method, $lt,
|
||||
i8, i16, i32, i64, i128, isize,
|
||||
u8, u16, u32, u64, u128, usize
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -195,9 +195,11 @@ macro_rules! test_shift {
|
|||
($test_name:ident, $op:ident::$method:ident) => {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
test_shift!($op::$method, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
test_shift!($op::$method, i128, u128);
|
||||
test_shift!(
|
||||
$op::$method,
|
||||
i8, i16, i32, i64, i128, isize,
|
||||
u8, u16, u32, u64, u128, usize
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -207,9 +209,11 @@ macro_rules! test_shift_assign_inner {
|
|||
$(impl_defined!($op, $method(&mut 0,0), 0, $lt, $rt);)+
|
||||
};
|
||||
($op:ident::$method:ident, $lt:ty) => {
|
||||
test_shift_assign_inner!($op::$method, $lt, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
test_shift_assign_inner!($op::$method, $lt, i128, u128);
|
||||
test_shift_assign_inner!(
|
||||
$op::$method, $lt,
|
||||
i8, i16, i32, i64, i128, isize,
|
||||
u8, u16, u32, u64, u128, usize
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -220,9 +224,11 @@ macro_rules! test_shift_assign {
|
|||
($test_name:ident, $op:ident::$method:ident) => {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
test_shift_assign!($op::$method, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
test_shift_assign!($op::$method, i128, u128);
|
||||
test_shift_assign!(
|
||||
$op::$method,
|
||||
i8, i16, i32, i64, i128, isize,
|
||||
u8, u16, u32, u64, u128, usize
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -64,14 +64,12 @@ wrapping_test!(test_wrapping_i8, i8, i8::MIN, i8::MAX);
|
|||
wrapping_test!(test_wrapping_i16, i16, i16::MIN, i16::MAX);
|
||||
wrapping_test!(test_wrapping_i32, i32, i32::MIN, i32::MAX);
|
||||
wrapping_test!(test_wrapping_i64, i64, i64::MIN, i64::MAX);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
wrapping_test!(test_wrapping_i128, i128, i128::MIN, i128::MAX);
|
||||
wrapping_test!(test_wrapping_isize, isize, isize::MIN, isize::MAX);
|
||||
wrapping_test!(test_wrapping_u8, u8, u8::MIN, u8::MAX);
|
||||
wrapping_test!(test_wrapping_u16, u16, u16::MIN, u16::MAX);
|
||||
wrapping_test!(test_wrapping_u32, u32, u32::MIN, u32::MAX);
|
||||
wrapping_test!(test_wrapping_u64, u64, u64::MIN, u64::MAX);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
wrapping_test!(test_wrapping_u128, u128, u128::MIN, u128::MAX);
|
||||
wrapping_test!(test_wrapping_usize, usize, usize::MIN, usize::MAX);
|
||||
|
||||
|
|
|
@ -112,7 +112,6 @@ fn test_neg_zero() {
|
|||
assert_eq!(Fp::Zero, neg_zero.classify());
|
||||
}
|
||||
|
||||
#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
|
||||
#[test]
|
||||
fn test_one() {
|
||||
let one: f64 = 1.0f64;
|
||||
|
@ -165,7 +164,6 @@ fn test_is_finite() {
|
|||
assert!((-109.2f64).is_finite());
|
||||
}
|
||||
|
||||
#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
|
||||
#[test]
|
||||
fn test_is_normal() {
|
||||
let nan: f64 = f64::NAN;
|
||||
|
@ -183,7 +181,6 @@ fn test_is_normal() {
|
|||
assert!(!1e-308f64.is_normal());
|
||||
}
|
||||
|
||||
#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
|
||||
#[test]
|
||||
fn test_classify() {
|
||||
let nan: f64 = f64::NAN;
|
||||
|
|
|
@ -126,6 +126,7 @@ mod io_benches {
|
|||
use crate::io::prelude::*;
|
||||
|
||||
#[bench]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)] // no /dev
|
||||
fn bench_copy_buf_reader(b: &mut Bencher) {
|
||||
let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed");
|
||||
// use dyn to avoid specializations unrelated to readbuf
|
||||
|
|
|
@ -7,7 +7,6 @@ use crate::mem::MaybeUninit;
|
|||
use crate::ops::Deref;
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
fn read_until() {
|
||||
let mut buf = Cursor::new(&b"12"[..]);
|
||||
let mut v = Vec::new();
|
||||
|
@ -359,7 +358,6 @@ fn chain_zero_length_read_is_not_eof() {
|
|||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
#[cfg_attr(miri, ignore)] // Miri isn't fast...
|
||||
fn bench_read_to_end(b: &mut test::Bencher) {
|
||||
b.iter(|| {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! This is an implementation of a global allocator on wasm targets when
|
||||
//! emscripten is not in use. In that situation there's no actual runtime for us
|
||||
//! to lean on for allocation, so instead we provide our own!
|
||||
//! emscripten or wasi is not in use. In that situation there's no actual runtime
|
||||
//! for us to lean on for allocation, so instead we provide our own!
|
||||
//!
|
||||
//! The wasm instruction set has two instructions for getting the current
|
||||
//! amount of memory and growing the amount of memory. These instructions are the
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
//! System bindings for the wasm/web platform
|
||||
//!
|
||||
//! This module contains the facade (aka platform-specific) implementations of
|
||||
//! OS level functionality for wasm. Note that this wasm is *not* the emscripten
|
||||
//! wasm, so we have no runtime here.
|
||||
//! OS level functionality for wasm.
|
||||
//!
|
||||
//! This is all super highly experimental and not actually intended for
|
||||
//! wide/production use yet, it's still all in the experimental category. This
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//!
|
||||
//! This module contains the facade (aka platform-specific) implementations of
|
||||
//! OS level functionality for wasm. Note that this wasm is *not* the emscripten
|
||||
//! wasm, so we have no runtime here.
|
||||
//! or wasi wasm, so we have no runtime here.
|
||||
//!
|
||||
//! This is all super highly experimental and not actually intended for
|
||||
//! wide/production use yet, it's still all in the experimental category. This
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![feature(anonymous_pipe)]
|
||||
|
||||
fn main() {
|
||||
#[cfg(all(not(miri), any(unix, windows)))]
|
||||
#[cfg(all(not(miri), any(unix, windows), not(target_os = "emscripten")))]
|
||||
{
|
||||
use std::io::{Read, pipe};
|
||||
use std::{env, process};
|
||||
|
|
|
@ -5,7 +5,8 @@ use std::{env, fs, process, str};
|
|||
mod common;
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(any(miri, target_os = "wasi"), ignore)] // Process spawning not supported by Miri and wasi
|
||||
// Process spawning not supported by Miri, Emscripten and wasi
|
||||
#[cfg_attr(any(miri, target_os = "emscripten", target_os = "wasi"), ignore)]
|
||||
fn issue_15149() {
|
||||
// If we're the parent, copy our own binary to a new directory.
|
||||
let my_path = env::current_exe().unwrap();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Module converting command-line arguments into test configuration.
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, IsTerminal};
|
||||
use std::io::{self, IsTerminal, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::options::{ColorConfig, Options, OutputFormat, RunIgnored};
|
||||
|
@ -58,7 +58,7 @@ fn optgroups() -> getopts::Options {
|
|||
.optflag("", "bench", "Run benchmarks instead of tests")
|
||||
.optflag("", "list", "List all tests and benchmarks")
|
||||
.optflag("h", "help", "Display this message")
|
||||
.optopt("", "logfile", "Write logs to the specified file", "PATH")
|
||||
.optopt("", "logfile", "Write logs to the specified file (deprecated)", "PATH")
|
||||
.optflag(
|
||||
"",
|
||||
"nocapture",
|
||||
|
@ -281,6 +281,10 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes {
|
|||
|
||||
let options = Options::new().display_output(matches.opt_present("show-output"));
|
||||
|
||||
if logfile.is_some() {
|
||||
let _ = write!(io::stderr(), "warning: `--logfile` is deprecated");
|
||||
}
|
||||
|
||||
let test_opts = TestOpts {
|
||||
list,
|
||||
filters,
|
||||
|
|
|
@ -133,9 +133,7 @@ fn ignored_tests_result_in_ignored() {
|
|||
assert_eq!(result, TrIgnored);
|
||||
}
|
||||
|
||||
// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||
fn test_should_panic() {
|
||||
fn f() -> Result<(), String> {
|
||||
|
@ -164,9 +162,7 @@ fn test_should_panic() {
|
|||
assert_eq!(result, TrOk);
|
||||
}
|
||||
|
||||
// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||
fn test_should_panic_good_message() {
|
||||
fn f() -> Result<(), String> {
|
||||
|
@ -195,9 +191,7 @@ fn test_should_panic_good_message() {
|
|||
assert_eq!(result, TrOk);
|
||||
}
|
||||
|
||||
// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||
fn test_should_panic_bad_message() {
|
||||
use crate::tests::TrFailedMsg;
|
||||
|
@ -231,9 +225,7 @@ fn test_should_panic_bad_message() {
|
|||
assert_eq!(result, TrFailedMsg(failed_msg.to_string()));
|
||||
}
|
||||
|
||||
// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||
fn test_should_panic_non_string_message_type() {
|
||||
use std::any::TypeId;
|
||||
|
@ -272,9 +264,7 @@ fn test_should_panic_non_string_message_type() {
|
|||
assert_eq!(result, TrFailedMsg(failed_msg));
|
||||
}
|
||||
|
||||
// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||
fn test_should_panic_but_succeeds() {
|
||||
let should_panic_variants = [ShouldPanic::Yes, ShouldPanic::YesWithMessage("error message")];
|
||||
|
|
|
@ -118,7 +118,7 @@ This target is not extensively tested in CI for the rust-lang/rust repository. I
|
|||
can be tested locally, for example, with:
|
||||
|
||||
```sh
|
||||
./x.py test --target wasm32-unknown-emscripten --skip src/tools/linkchecker
|
||||
EMCC_CFLAGS="-s MAXIMUM_MEMORY=2GB" ./x.py test --target wasm32-unknown-emscripten --skip src/tools/linkchecker
|
||||
```
|
||||
|
||||
To run these tests, both `emcc` and `node` need to be in your `$PATH`. You can
|
||||
|
|
|
@ -268,6 +268,8 @@ Controls the format of the output. Valid options:
|
|||
|
||||
Writes the results of the tests to the given file.
|
||||
|
||||
This option is deprecated.
|
||||
|
||||
#### `--report-time`
|
||||
|
||||
⚠️ 🚧 This option is [unstable](#unstable-options), and requires the `-Z
|
||||
|
|
143
tests/codegen/s390x-simd.rs
Normal file
143
tests/codegen/s390x-simd.rs
Normal file
|
@ -0,0 +1,143 @@
|
|||
//! test that s390x vector types are passed using `PassMode::Direct`
|
||||
//! see also https://github.com/rust-lang/rust/issues/135744
|
||||
//@ add-core-stubs
|
||||
//@ compile-flags: --target s390x-unknown-linux-gnu -O
|
||||
//@ needs-llvm-components: systemz
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![feature(s390x_target_feature, simd_ffi, link_llvm_intrinsics, repr_simd)]
|
||||
#![no_core]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[repr(simd)]
|
||||
struct i8x16([i8; 16]);
|
||||
|
||||
#[repr(simd)]
|
||||
struct i16x8([i16; 8]);
|
||||
|
||||
#[repr(simd)]
|
||||
struct i32x4([i32; 4]);
|
||||
|
||||
#[repr(simd)]
|
||||
struct i64x2([i64; 2]);
|
||||
|
||||
#[repr(simd)]
|
||||
struct f32x4([f32; 4]);
|
||||
|
||||
#[repr(simd)]
|
||||
struct f64x2([f64; 2]);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
extern "C" {
|
||||
#[link_name = "llvm.smax.v16i8"]
|
||||
fn vmxb(a: i8x16, b: i8x16) -> i8x16;
|
||||
#[link_name = "llvm.smax.v8i16"]
|
||||
fn vmxh(a: i16x8, b: i16x8) -> i16x8;
|
||||
#[link_name = "llvm.smax.v4i32"]
|
||||
fn vmxf(a: i32x4, b: i32x4) -> i32x4;
|
||||
#[link_name = "llvm.smax.v2i64"]
|
||||
fn vmxg(a: i64x2, b: i64x2) -> i64x2;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define <16 x i8> @max_i8x16
|
||||
// CHECK-SAME: <16 x i8> %a, <16 x i8> %b
|
||||
// CHECK: call <16 x i8> @llvm.smax.v16i8(<16 x i8> %a, <16 x i8> %b)
|
||||
#[no_mangle]
|
||||
#[target_feature(enable = "vector")]
|
||||
pub unsafe extern "C" fn max_i8x16(a: i8x16, b: i8x16) -> i8x16 {
|
||||
vmxb(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define <8 x i16> @max_i16x8
|
||||
// CHECK-SAME: <8 x i16> %a, <8 x i16> %b
|
||||
// CHECK: call <8 x i16> @llvm.smax.v8i16(<8 x i16> %a, <8 x i16> %b)
|
||||
#[no_mangle]
|
||||
#[target_feature(enable = "vector")]
|
||||
pub unsafe extern "C" fn max_i16x8(a: i16x8, b: i16x8) -> i16x8 {
|
||||
vmxh(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define <4 x i32> @max_i32x4
|
||||
// CHECK-SAME: <4 x i32> %a, <4 x i32> %b
|
||||
// CHECK: call <4 x i32> @llvm.smax.v4i32(<4 x i32> %a, <4 x i32> %b)
|
||||
#[no_mangle]
|
||||
#[target_feature(enable = "vector")]
|
||||
pub unsafe extern "C" fn max_i32x4(a: i32x4, b: i32x4) -> i32x4 {
|
||||
vmxf(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define <2 x i64> @max_i64x2
|
||||
// CHECK-SAME: <2 x i64> %a, <2 x i64> %b
|
||||
// CHECK: call <2 x i64> @llvm.smax.v2i64(<2 x i64> %a, <2 x i64> %b)
|
||||
#[no_mangle]
|
||||
#[target_feature(enable = "vector")]
|
||||
pub unsafe extern "C" fn max_i64x2(a: i64x2, b: i64x2) -> i64x2 {
|
||||
vmxg(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define <4 x float> @choose_f32x4
|
||||
// CHECK-SAME: <4 x float> %a, <4 x float> %b
|
||||
#[no_mangle]
|
||||
#[target_feature(enable = "vector")]
|
||||
pub unsafe extern "C" fn choose_f32x4(a: f32x4, b: f32x4, c: bool) -> f32x4 {
|
||||
if c { a } else { b }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define <2 x double> @choose_f64x2
|
||||
// CHECK-SAME: <2 x double> %a, <2 x double> %b
|
||||
#[no_mangle]
|
||||
#[target_feature(enable = "vector")]
|
||||
pub unsafe extern "C" fn choose_f64x2(a: f64x2, b: f64x2, c: bool) -> f64x2 {
|
||||
if c { a } else { b }
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Wrapper<T>(T);
|
||||
|
||||
#[no_mangle]
|
||||
#[inline(never)]
|
||||
#[target_feature(enable = "vector")]
|
||||
pub unsafe extern "C" fn max_wrapper_i8x16(a: Wrapper<i8x16>, b: Wrapper<i8x16>) -> Wrapper<i8x16> {
|
||||
// CHECK-LABEL: max_wrapper_i8x16
|
||||
// CHECK-SAME: sret([16 x i8])
|
||||
// CHECK-SAME: <16 x i8>
|
||||
// CHECK-SAME: <16 x i8>
|
||||
// CHECK: call <16 x i8> @llvm.smax.v16i8
|
||||
// CHECK-SAME: <16 x i8>
|
||||
// CHECK-SAME: <16 x i8>
|
||||
Wrapper(vmxb(a.0, b.0))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[inline(never)]
|
||||
#[target_feature(enable = "vector")]
|
||||
pub unsafe extern "C" fn max_wrapper_i64x2(a: Wrapper<i64x2>, b: Wrapper<i64x2>) -> Wrapper<i64x2> {
|
||||
// CHECK-LABEL: max_wrapper_i64x2
|
||||
// CHECK-SAME: sret([16 x i8])
|
||||
// CHECK-SAME: <16 x i8>
|
||||
// CHECK-SAME: <16 x i8>
|
||||
// CHECK: call <2 x i64> @llvm.smax.v2i64
|
||||
// CHECK-SAME: <2 x i64>
|
||||
// CHECK-SAME: <2 x i64>
|
||||
Wrapper(vmxg(a.0, b.0))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[inline(never)]
|
||||
#[target_feature(enable = "vector")]
|
||||
pub unsafe extern "C" fn choose_wrapper_f64x2(
|
||||
a: Wrapper<f64x2>,
|
||||
b: Wrapper<f64x2>,
|
||||
c: bool,
|
||||
) -> Wrapper<f64x2> {
|
||||
// CHECK-LABEL: choose_wrapper_f64x2
|
||||
// CHECK-SAME: sret([16 x i8])
|
||||
// CHECK-SAME: <16 x i8>
|
||||
// CHECK-SAME: <16 x i8>
|
||||
Wrapper(choose_f64x2(a.0, b.0, c))
|
||||
}
|
||||
|
||||
// CHECK: declare <2 x i64> @llvm.smax.v2i64(<2 x i64>, <2 x i64>)
|
|
@ -1,17 +1,26 @@
|
|||
//@ run-rustfix
|
||||
#![deny(unused_assignments, unused_variables)]
|
||||
#![allow(unused_mut)]
|
||||
struct Object;
|
||||
|
||||
fn change_object(object: &mut Object) { //~ HELP you might have meant to mutate
|
||||
let object2 = Object;
|
||||
*object = object2; //~ ERROR mismatched types
|
||||
let object2 = Object;
|
||||
*object = object2; //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn change_object2(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
|
||||
//~^ HELP you might have meant to mutate
|
||||
let object2 = Object;
|
||||
*object = object2;
|
||||
//~^ ERROR `object2` does not live long enough
|
||||
//~| ERROR value assigned to `object` is never read
|
||||
}
|
||||
|
||||
fn change_object3(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
|
||||
//~^ HELP you might have meant to mutate
|
||||
let object2 = Object;
|
||||
let mut object2 = Object; //~ HELP consider changing this to be mutable
|
||||
*object = object2;
|
||||
//~^ ERROR `object2` does not live long enough
|
||||
//~^ ERROR cannot borrow `object2` as mutable
|
||||
//~| ERROR value assigned to `object` is never read
|
||||
}
|
||||
|
||||
|
@ -19,4 +28,5 @@ fn main() {
|
|||
let mut object = Object;
|
||||
change_object(&mut object);
|
||||
change_object2(&mut object);
|
||||
change_object3(&mut object);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,26 @@
|
|||
//@ run-rustfix
|
||||
#![deny(unused_assignments, unused_variables)]
|
||||
#![allow(unused_mut)]
|
||||
struct Object;
|
||||
|
||||
fn change_object(mut object: &Object) { //~ HELP you might have meant to mutate
|
||||
let object2 = Object;
|
||||
object = object2; //~ ERROR mismatched types
|
||||
let object2 = Object;
|
||||
object = object2; //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn change_object2(mut object: &Object) { //~ ERROR variable `object` is assigned to, but never used
|
||||
//~^ HELP you might have meant to mutate
|
||||
let object2 = Object;
|
||||
object = &object2;
|
||||
//~^ ERROR `object2` does not live long enough
|
||||
//~| ERROR value assigned to `object` is never read
|
||||
}
|
||||
|
||||
fn change_object3(mut object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
|
||||
//~^ HELP you might have meant to mutate
|
||||
let object2 = Object;
|
||||
object = &object2;
|
||||
//~^ ERROR `object2` does not live long enough
|
||||
let object2 = Object; //~ HELP consider changing this to be mutable
|
||||
object = &mut object2;
|
||||
//~^ ERROR cannot borrow `object2` as mutable
|
||||
//~| ERROR value assigned to `object` is never read
|
||||
}
|
||||
|
||||
|
@ -19,4 +28,5 @@ fn main() {
|
|||
let mut object = Object;
|
||||
change_object(&mut object);
|
||||
change_object2(&mut object);
|
||||
change_object3(&mut object);
|
||||
}
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:7:14
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:8:13
|
||||
|
|
||||
LL | fn change_object(mut object: &Object) {
|
||||
| ------- expected due to this parameter type
|
||||
LL | let object2 = Object;
|
||||
LL | object = object2;
|
||||
| ^^^^^^^ expected `&Object`, found `Object`
|
||||
LL | let object2 = Object;
|
||||
LL | object = object2;
|
||||
| ^^^^^^^ expected `&Object`, found `Object`
|
||||
|
|
||||
help: you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
|
||||
|
|
||||
LL ~ fn change_object(object: &mut Object) {
|
||||
LL | let object2 = Object;
|
||||
LL ~ *object = object2;
|
||||
LL | let object2 = Object;
|
||||
LL ~ *object = object2;
|
||||
|
|
||||
|
||||
error: value assigned to `object` is never read
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:13:5
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:14:4
|
||||
|
|
||||
LL | object = &object2;
|
||||
| ^^^^^^
|
||||
LL | object = &object2;
|
||||
| ^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:9
|
||||
|
@ -29,12 +29,12 @@ help: you might have meant to mutate the pointed at value being passed in, inste
|
|||
|
|
||||
LL ~ fn change_object2(object: &mut Object) {
|
||||
LL |
|
||||
LL | let object2 = Object;
|
||||
LL ~ *object = object2;
|
||||
LL | let object2 = Object;
|
||||
LL ~ *object = object2;
|
||||
|
|
||||
|
||||
error: variable `object` is assigned to, but never used
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:10:23
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:11:23
|
||||
|
|
||||
LL | fn change_object2(mut object: &Object) {
|
||||
| ^^^^^^
|
||||
|
@ -47,23 +47,56 @@ LL | #![deny(unused_assignments, unused_variables)]
|
|||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0597]: `object2` does not live long enough
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:13:14
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:14:13
|
||||
|
|
||||
LL | fn change_object2(mut object: &Object) {
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
LL |
|
||||
LL | let object2 = Object;
|
||||
| ------- binding `object2` declared here
|
||||
LL | object = &object2;
|
||||
| ---------^^^^^^^^
|
||||
| | |
|
||||
| | borrowed value does not live long enough
|
||||
| assignment requires that `object2` is borrowed for `'1`
|
||||
LL | let object2 = Object;
|
||||
| ------- binding `object2` declared here
|
||||
LL | object = &object2;
|
||||
| ---------^^^^^^^^
|
||||
| | |
|
||||
| | borrowed value does not live long enough
|
||||
| assignment requires that `object2` is borrowed for `'1`
|
||||
...
|
||||
LL | }
|
||||
| - `object2` dropped here while still borrowed
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: value assigned to `object` is never read
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:22:5
|
||||
|
|
||||
LL | object = &mut object2;
|
||||
| ^^^^^^
|
||||
|
|
||||
help: you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
|
||||
|
|
||||
LL ~ fn change_object3(object: &mut Object) {
|
||||
LL |
|
||||
LL | let object2 = Object;
|
||||
LL ~ *object = object2;
|
||||
|
|
||||
|
||||
Some errors have detailed explanations: E0308, E0597.
|
||||
error: variable `object` is assigned to, but never used
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:19:23
|
||||
|
|
||||
LL | fn change_object3(mut object: &mut Object) {
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: consider using `_object` instead
|
||||
|
||||
error[E0596]: cannot borrow `object2` as mutable, as it is not declared as mutable
|
||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:22:14
|
||||
|
|
||||
LL | object = &mut object2;
|
||||
| ^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
help: consider changing this to be mutable
|
||||
|
|
||||
LL | let mut object2 = Object;
|
||||
| +++
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0596, E0597.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
|
|
28
tests/ui/wasm/wasm-bindgen-broken-error.rs
Normal file
28
tests/ui/wasm/wasm-bindgen-broken-error.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
//@ only-wasm32
|
||||
//@ revisions: v0_1_0 v0_2_87 v0_2_88 v0_3_0 v1_0_0
|
||||
//@[v0_1_0] check-fail
|
||||
//@[v0_1_0] rustc-env:CARGO_PKG_VERSION_MAJOR=0
|
||||
//@[v0_1_0] rustc-env:CARGO_PKG_VERSION_MINOR=1
|
||||
//@[v0_1_0] rustc-env:CARGO_PKG_VERSION_PATCH=0
|
||||
//@[v0_2_87] check-fail
|
||||
//@[v0_2_87] rustc-env:CARGO_PKG_VERSION_MAJOR=0
|
||||
//@[v0_2_87] rustc-env:CARGO_PKG_VERSION_MINOR=2
|
||||
//@[v0_2_87] rustc-env:CARGO_PKG_VERSION_PATCH=87
|
||||
//@[v0_2_88] check-pass
|
||||
//@[v0_2_88] rustc-env:CARGO_PKG_VERSION_MAJOR=0
|
||||
//@[v0_2_88] rustc-env:CARGO_PKG_VERSION_MINOR=2
|
||||
//@[v0_2_88] rustc-env:CARGO_PKG_VERSION_PATCH=88
|
||||
//@[v0_3_0] check-pass
|
||||
//@[v0_3_0] rustc-env:CARGO_PKG_VERSION_MAJOR=0
|
||||
//@[v0_3_0] rustc-env:CARGO_PKG_VERSION_MINOR=3
|
||||
//@[v0_3_0] rustc-env:CARGO_PKG_VERSION_PATCH=0
|
||||
//@[v1_0_0] check-pass
|
||||
//@[v1_0_0] rustc-env:CARGO_PKG_VERSION_MAJOR=1
|
||||
//@[v1_0_0] rustc-env:CARGO_PKG_VERSION_MINOR=0
|
||||
//@[v1_0_0] rustc-env:CARGO_PKG_VERSION_PATCH=0
|
||||
|
||||
#![crate_name = "wasm_bindgen"]
|
||||
//[v0_1_0]~^ ERROR: older versions of the `wasm-bindgen` crate
|
||||
//[v0_2_87]~^^ ERROR: older versions of the `wasm-bindgen` crate
|
||||
|
||||
fn main() {}
|
8
tests/ui/wasm/wasm-bindgen-broken-error.v0_1_0.stderr
Normal file
8
tests/ui/wasm/wasm-bindgen-broken-error.v0_1_0.stderr
Normal file
|
@ -0,0 +1,8 @@
|
|||
error: older versions of the `wasm-bindgen` crate are incompatible with current versions of Rust; please update to `wasm-bindgen` v0.2.88
|
||||
--> $DIR/wasm-bindgen-broken-error.rs:24:1
|
||||
|
|
||||
LL | #![crate_name = "wasm_bindgen"]
|
||||
| ^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
8
tests/ui/wasm/wasm-bindgen-broken-error.v0_2_87.stderr
Normal file
8
tests/ui/wasm/wasm-bindgen-broken-error.v0_2_87.stderr
Normal file
|
@ -0,0 +1,8 @@
|
|||
error: older versions of the `wasm-bindgen` crate are incompatible with current versions of Rust; please update to `wasm-bindgen` v0.2.88
|
||||
--> $DIR/wasm-bindgen-broken-error.rs:24:1
|
||||
|
|
||||
LL | #![crate_name = "wasm_bindgen"]
|
||||
| ^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue