Auto merge of #119578 - matthiaskrgr:rollup-42yizmx, r=matthiaskrgr

Rollup of 10 pull requests

Successful merges:

 - #117636 (add test for #117626)
 - #118704 (Promote `riscv32{im|imafc}` targets to tier 2)
 - #119184 (Switch from using `//~ERROR` annotations with `--error-format` to `error-pattern`)
 - #119325 (custom mir: make it clear what the return block is)
 - #119391 (Use Result::flatten in catch_with_exit_code)
 - #119431 (Support reg_addr register class in s390x inline assembly)
 - #119475 (Remove libtest's dylib)
 - #119532 (Make offset_of field parsing use metavariable which handles any spacing)
 - #119553 (stop feed vis when cant access for trait item)
 - #119574 (Miri subtree update)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-01-04 19:44:14 +00:00
commit 4c5ce1f0d5
119 changed files with 2314 additions and 1673 deletions

View File

@ -634,6 +634,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
} }
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::Err => unreachable!(), InlineAsmRegClass::Err => unreachable!(),
} }
@ -704,7 +705,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V") bug!("LLVM backend does not support SPIR-V")
}, },
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::S390x(
S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr
) => cx.type_i32(),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
InlineAsmRegClass::Err => unreachable!(), InlineAsmRegClass::Err => unreachable!(),
} }

View File

@ -690,6 +690,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w", InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w",
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e", InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r", InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r", InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
@ -867,7 +868,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => cx.type_i16(), InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => cx.type_i16(),
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => cx.type_i16(), InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => cx.type_i16(),
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(), InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::S390x(
S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr,
) => cx.type_i32(),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),

View File

@ -12,6 +12,7 @@
#![feature(lazy_cell)] #![feature(lazy_cell)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(panic_update_hook)] #![feature(panic_update_hook)]
#![feature(result_flattening)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)] #![deny(rustc::diagnostic_outside_of_impl)]
@ -1249,8 +1250,7 @@ pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorGuarantee
/// Variant of `catch_fatal_errors` for the `interface::Result` return type /// Variant of `catch_fatal_errors` for the `interface::Result` return type
/// that also computes the exit code. /// that also computes the exit code.
pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
let result = catch_fatal_errors(f).and_then(|result| result); match catch_fatal_errors(f).flatten() {
match result {
Ok(()) => EXIT_SUCCESS, Ok(()) => EXIT_SUCCESS,
Err(_) => EXIT_FAILURE, Err(_) => EXIT_FAILURE,
} }

View File

@ -61,7 +61,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
@call(mir_drop, args) => { @call(mir_drop, args) => {
Ok(TerminatorKind::Drop { Ok(TerminatorKind::Drop {
place: self.parse_place(args[0])?, place: self.parse_place(args[0])?,
target: self.parse_block(args[1])?, target: self.parse_return_to(args[1])?,
unwind: self.parse_unwind_action(args[2])?, unwind: self.parse_unwind_action(args[2])?,
replace: false, replace: false,
}) })
@ -104,6 +104,14 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
) )
} }
fn parse_return_to(&self, expr_id: ExprId) -> PResult<BasicBlock> {
parse_by_kind!(self, expr_id, _, "return block",
@call(mir_return_to, args) => {
self.parse_block(args[0])
},
)
}
fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> { fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
let Some((otherwise, rest)) = arms.split_last() else { let Some((otherwise, rest)) = arms.split_last() else {
return Err(ParseError { return Err(ParseError {
@ -146,7 +154,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
ExprKind::Assign { lhs, rhs } => (*lhs, *rhs), ExprKind::Assign { lhs, rhs } => (*lhs, *rhs),
); );
let destination = self.parse_place(destination)?; let destination = self.parse_place(destination)?;
let target = self.parse_block(args[1])?; let target = self.parse_return_to(args[1])?;
let unwind = self.parse_unwind_action(args[2])?; let unwind = self.parse_unwind_action(args[2])?;
parse_by_kind!(self, call, _, "function call", parse_by_kind!(self, call, _, "function call",

View File

@ -10,6 +10,8 @@ parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretat
parse_array_brackets_instead_of_braces = this is a block expression, not an array parse_array_brackets_instead_of_braces = this is a block expression, not an array
.suggestion = to make an array, use square brackets instead of curly braces .suggestion = to make an array, use square brackets instead of curly braces
parse_array_index_offset_of = array indexing not supported in offset_of
parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
parse_assoc_lifetime = associated lifetimes are not supported parse_assoc_lifetime = associated lifetimes are not supported
@ -405,6 +407,8 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}` parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
parse_invalid_offset_of = offset_of expects dot-separated field and variant names
parse_invalid_unicode_escape = invalid unicode character escape parse_invalid_unicode_escape = invalid unicode character escape
.label = invalid escape .label = invalid escape
.help = unicode escape must {$surrogate -> .help = unicode escape must {$surrogate ->

View File

@ -2887,3 +2887,11 @@ pub(crate) struct TransposeDynOrImplSugg<'a> {
pub insertion_span: Span, pub insertion_span: Span,
pub kw: &'a str, pub kw: &'a str,
} }
#[derive(Diagnostic)]
#[diag(parse_array_index_offset_of)]
pub(crate) struct ArrayIndexInOffsetOf(#[primary_span] pub Span);
#[derive(Diagnostic)]
#[diag(parse_invalid_offset_of)]
pub(crate) struct InvalidOffsetOf(#[primary_span] pub Span);

View File

@ -1023,7 +1023,7 @@ impl<'a> Parser<'a> {
// we should break everything including floats into more basic proc-macro style // we should break everything including floats into more basic proc-macro style
// tokens in the lexer (probably preferable). // tokens in the lexer (probably preferable).
// See also `TokenKind::break_two_token_op` which does similar splitting of `>>` into `>`. // See also `TokenKind::break_two_token_op` which does similar splitting of `>>` into `>`.
fn break_up_float(&mut self, float: Symbol) -> DestructuredFloat { fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {
#[derive(Debug)] #[derive(Debug)]
enum FloatComponent { enum FloatComponent {
IdentLike(String), IdentLike(String),
@ -1053,7 +1053,6 @@ impl<'a> Parser<'a> {
// With proc macros the span can refer to anything, the source may be too short, // With proc macros the span can refer to anything, the source may be too short,
// or too long, or non-ASCII. It only makes sense to break our span into components // or too long, or non-ASCII. It only makes sense to break our span into components
// if its underlying text is identical to our float literal. // if its underlying text is identical to our float literal.
let span = self.token.span;
let can_take_span_apart = let can_take_span_apart =
|| self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref(); || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();
@ -1115,7 +1114,7 @@ impl<'a> Parser<'a> {
float: Symbol, float: Symbol,
suffix: Option<Symbol>, suffix: Option<Symbol>,
) -> P<Expr> { ) -> P<Expr> {
match self.break_up_float(float) { match self.break_up_float(float, self.token.span) {
// 1e2 // 1e2
DestructuredFloat::Single(sym, _sp) => { DestructuredFloat::Single(sym, _sp) => {
self.parse_expr_tuple_field_access(lo, base, sym, suffix, None) self.parse_expr_tuple_field_access(lo, base, sym, suffix, None)
@ -1143,40 +1142,105 @@ impl<'a> Parser<'a> {
} }
} }
fn parse_field_name_maybe_tuple(&mut self) -> PResult<'a, ThinVec<Ident>> { /// Parse the field access used in offset_of, matched by `$(e:expr)+`.
let token::Literal(token::Lit { kind: token::Float, symbol, suffix }) = self.token.kind /// Currently returns a list of idents. However, it should be possible in
else { /// future to also do array indices, which might be arbitrary expressions.
return Ok(thin_vec![self.parse_field_name()?]); fn parse_floating_field_access(&mut self) -> PResult<'a, P<[Ident]>> {
}; let mut fields = Vec::new();
Ok(match self.break_up_float(symbol) { let mut trailing_dot = None;
// 1e2
DestructuredFloat::Single(sym, sp) => { loop {
self.bump(); // This is expected to use a metavariable $(args:expr)+, but the builtin syntax
thin_vec![Ident::new(sym, sp)] // could be called directly. Calling `parse_expr` allows this function to only
// consider `Expr`s.
let expr = self.parse_expr()?;
let mut current = &expr;
let start_idx = fields.len();
loop {
match current.kind {
ExprKind::Field(ref left, right) => {
// Field access is read right-to-left.
fields.insert(start_idx, right);
trailing_dot = None;
current = left;
}
// Parse this both to give helpful error messages and to
// verify it can be done with this parser setup.
ExprKind::Index(ref left, ref _right, span) => {
self.dcx().emit_err(errors::ArrayIndexInOffsetOf(span));
current = left;
}
ExprKind::Lit(token::Lit {
kind: token::Float | token::Integer,
symbol,
suffix,
}) => {
if let Some(suffix) = suffix {
self.expect_no_tuple_index_suffix(current.span, suffix);
}
match self.break_up_float(symbol, current.span) {
// 1e2
DestructuredFloat::Single(sym, sp) => {
trailing_dot = None;
fields.insert(start_idx, Ident::new(sym, sp));
}
// 1.
DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
assert!(suffix.is_none());
trailing_dot = Some(dot_span);
fields.insert(start_idx, Ident::new(sym, sym_span));
}
// 1.2 | 1.2e3
DestructuredFloat::MiddleDot(
symbol1,
span1,
_dot_span,
symbol2,
span2,
) => {
trailing_dot = None;
fields.insert(start_idx, Ident::new(symbol2, span2));
fields.insert(start_idx, Ident::new(symbol1, span1));
}
DestructuredFloat::Error => {
trailing_dot = None;
fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));
}
}
break;
}
ExprKind::Path(None, Path { ref segments, .. }) => {
match &segments[..] {
[PathSegment { ident, args: None, .. }] => {
trailing_dot = None;
fields.insert(start_idx, *ident)
}
_ => {
self.dcx().emit_err(errors::InvalidOffsetOf(current.span));
break;
}
}
break;
}
_ => {
self.dcx().emit_err(errors::InvalidOffsetOf(current.span));
break;
}
}
} }
// 1.
DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => { if matches!(self.token.kind, token::CloseDelim(..) | token::Comma) {
assert!(suffix.is_none()); break;
// Analogous to `Self::break_and_eat` } else if trailing_dot.is_none() {
self.break_last_token = true; // This loop should only repeat if there is a trailing dot.
// This might work, in cases like `1. 2`, and might not, self.dcx().emit_err(errors::InvalidOffsetOf(self.token.span));
// in cases like `offset_of!(Ty, 1.)`. It depends on what comes break;
// after the float-like token, and therefore we have to make
// the other parts of the parser think that there is a dot literal.
self.token = Token::new(token::Ident(sym, false), sym_span);
self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));
thin_vec![Ident::new(sym, sym_span)]
} }
// 1.2 | 1.2e3 }
DestructuredFloat::MiddleDot(symbol1, ident1_span, _dot_span, symbol2, ident2_span) => { if let Some(dot) = trailing_dot {
self.bump(); self.dcx().emit_err(errors::InvalidOffsetOf(dot));
thin_vec![Ident::new(symbol1, ident1_span), Ident::new(symbol2, ident2_span)] }
} Ok(fields.into_iter().collect())
DestructuredFloat::Error => {
self.bump();
thin_vec![Ident::new(symbol, self.prev_token.span)]
}
})
} }
fn parse_expr_tuple_field_access( fn parse_expr_tuple_field_access(
@ -1907,15 +1971,29 @@ impl<'a> Parser<'a> {
let container = self.parse_ty()?; let container = self.parse_ty()?;
self.expect(&TokenKind::Comma)?; self.expect(&TokenKind::Comma)?;
let seq_sep = SeqSep { sep: Some(token::Dot), trailing_sep_allowed: false }; let fields = self.parse_floating_field_access()?;
let (fields, _trailing, _recovered) = self.parse_seq_to_before_end( let trailing_comma = self.eat_noexpect(&TokenKind::Comma);
&TokenKind::CloseDelim(Delimiter::Parenthesis),
seq_sep, if let Err(mut e) =
Parser::parse_field_name_maybe_tuple, self.expect_one_of(&[], &[TokenKind::CloseDelim(Delimiter::Parenthesis)])
)?; {
let fields = fields.into_iter().flatten().collect::<Vec<_>>(); if trailing_comma {
e.note("unexpected third argument to offset_of");
} else {
e.note("offset_of expects dot-separated field and variant names");
}
e.emit();
}
// Eat tokens until the macro call ends.
if self.may_recover() {
while !matches!(self.token.kind, token::CloseDelim(..) | token::Eof) {
self.bump();
}
}
let span = lo.to(self.token.span); let span = lo.to(self.token.span);
Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.into()))) Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields)))
} }
/// Returns a string literal if the next token is a string literal. /// Returns a string literal if the next token is a string literal.

View File

@ -3076,7 +3076,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
} }
let feed_visibility = |this: &mut Self, def_id| { let feed_visibility = |this: &mut Self, def_id| {
let vis = this.r.tcx.visibility(def_id).expect_local(); let vis = this.r.tcx.visibility(def_id);
let vis = if vis.is_visible_locally() {
vis.expect_local()
} else {
this.r.dcx().span_delayed_bug(
span,
"error should be emitted when an unexpected trait item is used",
);
rustc_middle::ty::Visibility::Public
};
this.r.feed_visibility(this.r.local_def_id(id), vis); this.r.feed_visibility(this.r.local_def_id(id), vis);
}; };

View File

@ -1041,6 +1041,7 @@ symbols! {
mir_offset, mir_offset,
mir_retag, mir_retag,
mir_return, mir_return,
mir_return_to,
mir_set_discriminant, mir_set_discriminant,
mir_static, mir_static,
mir_static_mut, mir_static_mut,

View File

@ -6,6 +6,7 @@ use std::fmt;
def_reg_class! { def_reg_class! {
S390x S390xInlineAsmRegClass { S390x S390xInlineAsmRegClass {
reg, reg,
reg_addr,
freg, freg,
} }
} }
@ -36,7 +37,7 @@ impl S390xInlineAsmRegClass {
arch: InlineAsmArch, arch: InlineAsmArch,
) -> &'static [(InlineAsmType, Option<Symbol>)] { ) -> &'static [(InlineAsmType, Option<Symbol>)] {
match (self, arch) { match (self, arch) {
(Self::reg, _) => types! { _: I8, I16, I32, I64; }, (Self::reg | Self::reg_addr, _) => types! { _: I8, I16, I32, I64; },
(Self::freg, _) => types! { _: F32, F64; }, (Self::freg, _) => types! { _: F32, F64; },
} }
} }
@ -45,19 +46,19 @@ impl S390xInlineAsmRegClass {
def_regs! { def_regs! {
S390x S390xInlineAsmReg S390xInlineAsmRegClass { S390x S390xInlineAsmReg S390xInlineAsmRegClass {
r0: reg = ["r0"], r0: reg = ["r0"],
r1: reg = ["r1"], r1: reg, reg_addr = ["r1"],
r2: reg = ["r2"], r2: reg, reg_addr = ["r2"],
r3: reg = ["r3"], r3: reg, reg_addr = ["r3"],
r4: reg = ["r4"], r4: reg, reg_addr = ["r4"],
r5: reg = ["r5"], r5: reg, reg_addr = ["r5"],
r6: reg = ["r6"], r6: reg, reg_addr = ["r6"],
r7: reg = ["r7"], r7: reg, reg_addr = ["r7"],
r8: reg = ["r8"], r8: reg, reg_addr = ["r8"],
r9: reg = ["r9"], r9: reg, reg_addr = ["r9"],
r10: reg = ["r10"], r10: reg, reg_addr = ["r10"],
r12: reg = ["r12"], r12: reg, reg_addr = ["r12"],
r13: reg = ["r13"], r13: reg, reg_addr = ["r13"],
r14: reg = ["r14"], r14: reg, reg_addr = ["r14"],
f0: freg = ["f0"], f0: freg = ["f0"],
f1: freg = ["f1"], f1: freg = ["f1"],
f2: freg = ["f2"], f2: freg = ["f2"],

View File

@ -104,21 +104,22 @@
//! } //! }
//! //!
//! #[custom_mir(dialect = "runtime", phase = "optimized")] //! #[custom_mir(dialect = "runtime", phase = "optimized")]
#![cfg_attr(bootstrap, doc = "#[cfg(any())]")] // disable the following function in doctests when `bootstrap` is set
//! fn push_and_pop<T>(v: &mut Vec<T>, value: T) { //! fn push_and_pop<T>(v: &mut Vec<T>, value: T) {
//! mir!( //! mir!(
//! let _unused; //! let _unused;
//! let popped; //! let popped;
//! //!
//! { //! {
//! Call(_unused = Vec::push(v, value), pop, UnwindContinue()) //! Call(_unused = Vec::push(v, value), ReturnTo(pop), UnwindContinue())
//! } //! }
//! //!
//! pop = { //! pop = {
//! Call(popped = Vec::pop(v), drop, UnwindContinue()) //! Call(popped = Vec::pop(v), ReturnTo(drop), UnwindContinue())
//! } //! }
//! //!
//! drop = { //! drop = {
//! Drop(popped, ret, UnwindContinue()) //! Drop(popped, ReturnTo(ret), UnwindContinue())
//! } //! }
//! //!
//! ret = { //! ret = {
@ -242,9 +243,8 @@
//! - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block` //! - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
//! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the //! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
//! otherwise branch. //! otherwise branch.
//! - [`Call`] has an associated function as well. The third argument of this function is a normal //! - [`Call`] has an associated function as well, with special syntax:
//! function call expression, for example `my_other_function(a, 5)`. //! `Call(ret_val = function(arg1, arg2, ...), ReturnTo(next_block), UnwindContinue())`.
//!
#![unstable( #![unstable(
feature = "custom_mir", feature = "custom_mir",
@ -287,35 +287,68 @@ macro_rules! define {
} }
// Unwind actions // Unwind actions
pub struct UnwindActionArg;
define!( define!(
"mir_unwind_continue", "mir_unwind_continue",
/// An unwind action that continues unwinding. /// An unwind action that continues unwinding.
fn UnwindContinue() fn UnwindContinue() -> UnwindActionArg
); );
define!( define!(
"mir_unwind_unreachable", "mir_unwind_unreachable",
/// An unwind action that triggers undefined behaviour. /// An unwind action that triggers undefined behaviour.
fn UnwindUnreachable() -> BasicBlock fn UnwindUnreachable() -> UnwindActionArg
); );
define!( define!(
"mir_unwind_terminate", "mir_unwind_terminate",
/// An unwind action that terminates the execution. /// An unwind action that terminates the execution.
/// ///
/// `UnwindTerminate` can also be used as a terminator. /// `UnwindTerminate` can also be used as a terminator.
fn UnwindTerminate(reason: UnwindTerminateReason) fn UnwindTerminate(reason: UnwindTerminateReason) -> UnwindActionArg
); );
define!( define!(
"mir_unwind_cleanup", "mir_unwind_cleanup",
/// An unwind action that continues execution in a given basic blok. /// An unwind action that continues execution in a given basic blok.
fn UnwindCleanup(goto: BasicBlock) fn UnwindCleanup(goto: BasicBlock) -> UnwindActionArg
); );
// Return destination for `Call`
pub struct ReturnToArg;
define!("mir_return_to", fn ReturnTo(goto: BasicBlock) -> ReturnToArg);
// Terminators // Terminators
define!("mir_return", fn Return() -> BasicBlock); define!("mir_return", fn Return() -> BasicBlock);
define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock); define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
define!("mir_unreachable", fn Unreachable() -> BasicBlock); define!("mir_unreachable", fn Unreachable() -> BasicBlock);
define!("mir_drop", fn Drop<T, U>(place: T, goto: BasicBlock, unwind_action: U)); define!("mir_drop",
define!("mir_call", fn Call<U>(call: (), goto: BasicBlock, unwind_action: U)); /// Drop the contents of a place.
///
/// The first argument must be a place.
///
/// The second argument must be of the form `ReturnTo(bb)`, where `bb` is the basic block that
/// will be jumped to after the destructor returns.
///
/// The third argument describes what happens on unwind. It can be one of:
/// - [`UnwindContinue`]
/// - [`UnwindUnreachable`]
/// - [`UnwindTerminate`]
/// - [`UnwindCleanup`]
fn Drop<T>(place: T, goto: ReturnToArg, unwind_action: UnwindActionArg)
);
define!("mir_call",
/// Call a function.
///
/// The first argument must be of the form `ret_val = fun(arg1, arg2, ...)`.
///
/// The second argument must be of the form `ReturnTo(bb)`, where `bb` is the basic block that
/// will be jumped to after the function returns.
///
/// The third argument describes what happens on unwind. It can be one of:
/// - [`UnwindContinue`]
/// - [`UnwindUnreachable`]
/// - [`UnwindTerminate`]
/// - [`UnwindCleanup`]
fn Call(call: (), goto: ReturnToArg, unwind_action: UnwindActionArg)
);
define!("mir_unwind_resume", define!("mir_unwind_resume",
/// A terminator that resumes the unwinding. /// A terminator that resumes the unwinding.
fn UnwindResume() fn UnwindResume()

View File

@ -1395,8 +1395,18 @@ impl<T> SizedTypeProperties for T {}
/// ///
/// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0); /// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0);
/// ``` /// ```
#[cfg(not(bootstrap))]
#[unstable(feature = "offset_of", issue = "106655")] #[unstable(feature = "offset_of", issue = "106655")]
#[allow_internal_unstable(builtin_syntax, hint_must_use)] #[allow_internal_unstable(builtin_syntax, hint_must_use)]
pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) {
// The `{}` is for better error messages
crate::hint::must_use({builtin # offset_of($Container, $($fields)+)})
}
#[cfg(bootstrap)]
#[unstable(feature = "offset_of", issue = "106655")]
#[allow_internal_unstable(builtin_syntax, hint_must_use)]
#[allow(missing_docs)]
pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) {
// The `{}` is for better error messages // The `{}` is for better error messages
crate::hint::must_use({builtin # offset_of($Container, $($fields).+)}) crate::hint::must_use({builtin # offset_of($Container, $($fields).+)})

View File

@ -3,9 +3,6 @@ name = "test"
version = "0.0.0" version = "0.0.0"
edition = "2021" edition = "2021"
[lib]
crate-type = ["dylib", "rlib"]
[dependencies] [dependencies]
getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] }
std = { path = "../std" } std = { path = "../std" }

View File

@ -161,7 +161,9 @@ target | std | notes
[`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs] [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
[`riscv32imac-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAC ISA) [`riscv32imac-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAC ISA)
[`riscv32i-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32I ISA) [`riscv32i-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32I ISA)
[`riscv32im-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | | Bare RISC-V (RV32IM ISA)
[`riscv32imc-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA) [`riscv32imc-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA)
[`riscv32imafc-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAFC ISA)
`riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA)
`riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23)
@ -318,8 +320,6 @@ target | std | host | notes
[`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer)
`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33)
`riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches) `riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
[`riscv32imafc-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAFC ISA)
[`riscv32im-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | | Bare RISC-V (RV32IM ISA)
[`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? | | RISC-V Xous (RV32IMAC ISA) [`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? | | RISC-V Xous (RV32IMAC ISA)
[`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF
[`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF

View File

@ -1,6 +1,6 @@
# `riscv32{i,im,imc,imac,imafc}-unknown-none-elf` # `riscv32{i,im,imc,imac,imafc}-unknown-none-elf`
**Tier: 2/3** **Tier: 2**
Bare-metal target for RISC-V CPUs with the RV32I, RV32IM, RV32IMC, RV32IMAFC and RV32IMAC ISAs. Bare-metal target for RISC-V CPUs with the RV32I, RV32IM, RV32IMC, RV32IMAFC and RV32IMAC ISAs.
@ -24,11 +24,11 @@ This target is included in Rust and can be installed via `rustup`.
## Testing ## Testing
This is a cross-compiled no-std target, which must be run either in a simulator This is a cross-compiled `no-std` target, which must be run either in a simulator
or by programming them onto suitable hardware. It is not possible to run the or by programming them onto suitable hardware. It is not possible to run the
Rust testsuite on this target. Rust test-suite on this target.
## Cross-compilation toolchains and C code ## Cross-compilation toolchains and C code
This target supports C code. If interlinking with C or C++, you may need to use This target supports C code. If interlinking with C or C++, you may need to use
riscv64-unknown-elf-gcc as a linker instead of rust-lld. `riscv64-unknown-elf-gcc` as a linker instead of `rust-lld`.

View File

@ -84,7 +84,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| M68k | `reg_data` | None | `i8`, `i16`, `i32` | | M68k | `reg_data` | None | `i8`, `i16`, `i32` |
| CSKY | `reg` | None | `i8`, `i16`, `i32` | | CSKY | `reg` | None | `i8`, `i16`, `i32` |
| CSKY | `freg` | None | `f32`, | | CSKY | `freg` | None | `f32`, |
| s390x | `reg` | None | `i8`, `i16`, `i32`, `i64` | | s390x | `reg`, `reg_addr` | None | `i8`, `i16`, `i32`, `i64` |
| s390x | `freg` | None | `f32`, `f64` | | s390x | `freg` | None | `f32`, `f64` |
## Register aliases ## Register aliases
@ -158,9 +158,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| NVPTX | `reg64` | None | `rd0` | None | | NVPTX | `reg64` | None | `rd0` | None |
| Hexagon | `reg` | None | `r0` | None | | Hexagon | `reg` | None | `r0` | None |
| PowerPC | `reg` | None | `0` | None | | PowerPC | `reg` | None | `0` | None |
| PowerPC | `reg_nonzero` | None | `3` | `b` | | PowerPC | `reg_nonzero` | None | `3` | None |
| PowerPC | `freg` | None | `0` | None | | PowerPC | `freg` | None | `0` | None |
| s390x | `reg` | None | `%r0` | None | | s390x | `reg` | None | `%r0` | None |
| s390x | `reg_addr` | None | `%r1` | None |
| s390x | `freg` | None | `%f0` | None | | s390x | `freg` | None | `%f0` | None |
| CSKY | `reg` | None | `r0` | None | | CSKY | `reg` | None | `r0` | None |
| CSKY | `freg` | None | `f0` | None | | CSKY | `freg` | None | `f0` | None |

View File

@ -11,7 +11,7 @@ use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use tracing::*; use tracing::*;
#[derive(Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub enum ErrorKind { pub enum ErrorKind {
Help, Help,
Error, Error,

View File

@ -3977,23 +3977,29 @@ impl<'test> TestCx<'test> {
proc_res.status, proc_res.status,
self.props.error_patterns self.props.error_patterns
); );
let check_patterns = should_run == WillExecute::No
&& (!self.props.error_patterns.is_empty()
|| !self.props.regex_error_patterns.is_empty());
if !explicit && self.config.compare_mode.is_none() { if !explicit && self.config.compare_mode.is_none() {
let check_patterns = should_run == WillExecute::No
&& (!self.props.error_patterns.is_empty()
|| !self.props.regex_error_patterns.is_empty());
let check_annotations = !check_patterns || !expected_errors.is_empty(); let check_annotations = !check_patterns || !expected_errors.is_empty();
if check_patterns {
// "// error-pattern" comments
let output_to_check = self.get_output(&proc_res);
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
}
if check_annotations { if check_annotations {
// "//~ERROR comments" // "//~ERROR comments"
self.check_expected_errors(expected_errors, &proc_res); self.check_expected_errors(expected_errors, &proc_res);
} }
} else if explicit && !expected_errors.is_empty() {
let msg = format!(
"line {}: cannot combine `--error-format` with {} annotations; use `error-pattern` instead",
expected_errors[0].line_num,
expected_errors[0].kind.unwrap_or(ErrorKind::Error),
);
self.fatal(&msg);
}
if check_patterns {
// "// error-pattern" comments
let output_to_check = self.get_output(&proc_res);
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
} }
if self.props.run_rustfix && self.config.compare_mode.is_none() { if self.props.run_rustfix && self.config.compare_mode.is_none() {

View File

@ -6,6 +6,7 @@ use std::time::Duration;
use log::trace; use log::trace;
use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def::{DefKind, Namespace};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_index::IndexVec; use rustc_index::IndexVec;
@ -117,6 +118,50 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>)
} }
} }
/// Convert a softfloat type to its corresponding hostfloat type.
pub trait ToHost {
type HostFloat;
fn to_host(self) -> Self::HostFloat;
}
/// Convert a hostfloat type to its corresponding softfloat type.
pub trait ToSoft {
type SoftFloat;
fn to_soft(self) -> Self::SoftFloat;
}
impl ToHost for rustc_apfloat::ieee::Double {
type HostFloat = f64;
fn to_host(self) -> Self::HostFloat {
f64::from_bits(self.to_bits().try_into().unwrap())
}
}
impl ToSoft for f64 {
type SoftFloat = rustc_apfloat::ieee::Double;
fn to_soft(self) -> Self::SoftFloat {
Float::from_bits(self.to_bits().into())
}
}
impl ToHost for rustc_apfloat::ieee::Single {
type HostFloat = f32;
fn to_host(self) -> Self::HostFloat {
f32::from_bits(self.to_bits().try_into().unwrap())
}
}
impl ToSoft for f32 {
type SoftFloat = rustc_apfloat::ieee::Single;
fn to_soft(self) -> Self::SoftFloat {
Float::from_bits(self.to_bits().into())
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// Checks if the given crate/module exists. /// Checks if the given crate/module exists.
@ -1188,11 +1233,3 @@ pub(crate) fn simd_element_to_bool(elem: ImmTy<'_, Provenance>) -> InterpResult<
_ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"),
}) })
} }
// This looks like something that would be nice to have in the standard library...
pub(crate) fn round_to_next_multiple_of(x: u64, divisor: u64) -> u64 {
assert_ne!(divisor, 0);
// divisor is nonzero; multiplication cannot overflow since we just divided
#[allow(clippy::arithmetic_side_effects)]
return (x.checked_add(divisor - 1).unwrap() / divisor) * divisor;
}

View File

@ -11,6 +11,7 @@
#![feature(round_ties_even)] #![feature(round_ties_even)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(lint_reasons)] #![feature(lint_reasons)]
#![feature(int_roundings)]
// Configure clippy and other lints // Configure clippy and other lints
#![allow( #![allow(
clippy::collapsible_else_if, clippy::collapsible_else_if,

View File

@ -118,4 +118,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
nan nan
} }
} }
fn adjust_nan<F1: Float + FloatConvert<F2>, F2: Float>(&self, f: F2, inputs: &[F1]) -> F2 {
if f.is_nan() { self.generate_nan(inputs) } else { f }
}
} }

View File

@ -23,6 +23,7 @@ use rustc_target::{
use super::backtrace::EvalContextExt as _; use super::backtrace::EvalContextExt as _;
use crate::*; use crate::*;
use helpers::{ToHost, ToSoft};
/// Type of dynamic symbols (for `dlsym` et al) /// Type of dynamic symbols (for `dlsym` et al)
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -886,23 +887,26 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
| "tgammaf" | "tgammaf"
=> { => {
let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let f = this.read_scalar(f)?.to_f32()?;
// FIXME: Using host floats. // FIXME: Using host floats.
let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f_host = f.to_host();
let res = match link_name.as_str() { let res = match link_name.as_str() {
"cbrtf" => f.cbrt(), "cbrtf" => f_host.cbrt(),
"coshf" => f.cosh(), "coshf" => f_host.cosh(),
"sinhf" => f.sinh(), "sinhf" => f_host.sinh(),
"tanf" => f.tan(), "tanf" => f_host.tan(),
"tanhf" => f.tanh(), "tanhf" => f_host.tanh(),
"acosf" => f.acos(), "acosf" => f_host.acos(),
"asinf" => f.asin(), "asinf" => f_host.asin(),
"atanf" => f.atan(), "atanf" => f_host.atan(),
"log1pf" => f.ln_1p(), "log1pf" => f_host.ln_1p(),
"expm1f" => f.exp_m1(), "expm1f" => f_host.exp_m1(),
"tgammaf" => f.gamma(), "tgammaf" => f_host.gamma(),
_ => bug!(), _ => bug!(),
}; };
this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; let res = res.to_soft();
let res = this.adjust_nan(res, &[f]);
this.write_scalar(res, dest)?;
} }
#[rustfmt::skip] #[rustfmt::skip]
| "_hypotf" | "_hypotf"
@ -911,19 +915,20 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
| "fdimf" | "fdimf"
=> { => {
let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let f1 = this.read_scalar(f1)?.to_f32()?;
let f2 = this.read_scalar(f2)?.to_f32()?;
// underscore case for windows, here and below // underscore case for windows, here and below
// (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
// FIXME: Using host floats. // FIXME: Using host floats.
let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?);
let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?);
let res = match link_name.as_str() { let res = match link_name.as_str() {
"_hypotf" | "hypotf" => f1.hypot(f2), "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(),
"atan2f" => f1.atan2(f2), "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(),
#[allow(deprecated)] #[allow(deprecated)]
"fdimf" => f1.abs_sub(f2), "fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
_ => bug!(), _ => bug!(),
}; };
this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; let res = this.adjust_nan(res, &[f1, f2]);
this.write_scalar(res, dest)?;
} }
#[rustfmt::skip] #[rustfmt::skip]
| "cbrt" | "cbrt"
@ -939,23 +944,26 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
| "tgamma" | "tgamma"
=> { => {
let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let f = this.read_scalar(f)?.to_f64()?;
// FIXME: Using host floats. // FIXME: Using host floats.
let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f_host = f.to_host();
let res = match link_name.as_str() { let res = match link_name.as_str() {
"cbrt" => f.cbrt(), "cbrt" => f_host.cbrt(),
"cosh" => f.cosh(), "cosh" => f_host.cosh(),
"sinh" => f.sinh(), "sinh" => f_host.sinh(),
"tan" => f.tan(), "tan" => f_host.tan(),
"tanh" => f.tanh(), "tanh" => f_host.tanh(),
"acos" => f.acos(), "acos" => f_host.acos(),
"asin" => f.asin(), "asin" => f_host.asin(),
"atan" => f.atan(), "atan" => f_host.atan(),
"log1p" => f.ln_1p(), "log1p" => f_host.ln_1p(),
"expm1" => f.exp_m1(), "expm1" => f_host.exp_m1(),
"tgamma" => f.gamma(), "tgamma" => f_host.gamma(),
_ => bug!(), _ => bug!(),
}; };
this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; let res = res.to_soft();
let res = this.adjust_nan(res, &[f]);
this.write_scalar(res, dest)?;
} }
#[rustfmt::skip] #[rustfmt::skip]
| "_hypot" | "_hypot"
@ -964,17 +972,20 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
| "fdim" | "fdim"
=> { => {
let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let f1 = this.read_scalar(f1)?.to_f64()?;
let f2 = this.read_scalar(f2)?.to_f64()?;
// underscore case for windows, here and below
// (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
// FIXME: Using host floats. // FIXME: Using host floats.
let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?);
let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?);
let res = match link_name.as_str() { let res = match link_name.as_str() {
"_hypot" | "hypot" => f1.hypot(f2), "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(),
"atan2" => f1.atan2(f2), "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(),
#[allow(deprecated)] #[allow(deprecated)]
"fdim" => f1.abs_sub(f2), "fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
_ => bug!(), _ => bug!(),
}; };
this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; let res = this.adjust_nan(res, &[f1, f2]);
this.write_scalar(res, dest)?;
} }
#[rustfmt::skip] #[rustfmt::skip]
| "_ldexp" | "_ldexp"
@ -987,27 +998,30 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let exp = this.read_scalar(exp)?.to_i32()?; let exp = this.read_scalar(exp)?.to_i32()?;
let res = x.scalbn(exp); let res = x.scalbn(exp);
this.write_scalar(Scalar::from_f64(res), dest)?; let res = this.adjust_nan(res, &[x]);
this.write_scalar(res, dest)?;
} }
"lgammaf_r" => { "lgammaf_r" => {
let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
// FIXME: Using host floats. let x = this.read_scalar(x)?.to_f32()?;
let x = f32::from_bits(this.read_scalar(x)?.to_u32()?);
let signp = this.deref_pointer(signp)?; let signp = this.deref_pointer(signp)?;
let (res, sign) = x.ln_gamma(); // FIXME: Using host floats.
let (res, sign) = x.to_host().ln_gamma();
this.write_int(sign, &signp)?; this.write_int(sign, &signp)?;
this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; let res = this.adjust_nan(res.to_soft(), &[x]);
this.write_scalar(res, dest)?;
} }
"lgamma_r" => { "lgamma_r" => {
let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
// FIXME: Using host floats. let x = this.read_scalar(x)?.to_f64()?;
let x = f64::from_bits(this.read_scalar(x)?.to_u64()?);
let signp = this.deref_pointer(signp)?; let signp = this.deref_pointer(signp)?;
let (res, sign) = x.ln_gamma(); // FIXME: Using host floats.
let (res, sign) = x.to_host().ln_gamma();
this.write_int(sign, &signp)?; this.write_int(sign, &signp)?;
this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; let res = this.adjust_nan(res.to_soft(), &[x]);
this.write_scalar(res, dest)?;
} }
// LLVM intrinsics // LLVM intrinsics

View File

@ -15,7 +15,7 @@ use rustc_target::abi::Size;
use crate::*; use crate::*;
use atomic::EvalContextExt as _; use atomic::EvalContextExt as _;
use helpers::check_arg_count; use helpers::{check_arg_count, ToHost, ToSoft};
use simd::EvalContextExt as _; use simd::EvalContextExt as _;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
@ -146,12 +146,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let [f] = check_arg_count(args)?; let [f] = check_arg_count(args)?;
let f = this.read_scalar(f)?.to_f32()?; let f = this.read_scalar(f)?.to_f32()?;
// Can be implemented in soft-floats. // Can be implemented in soft-floats.
// This is a "bitwise" operation, so there's no NaN non-determinism.
this.write_scalar(Scalar::from_f32(f.abs()), dest)?; this.write_scalar(Scalar::from_f32(f.abs()), dest)?;
} }
"fabsf64" => { "fabsf64" => {
let [f] = check_arg_count(args)?; let [f] = check_arg_count(args)?;
let f = this.read_scalar(f)?.to_f64()?; let f = this.read_scalar(f)?.to_f64()?;
// Can be implemented in soft-floats. // Can be implemented in soft-floats.
// This is a "bitwise" operation, so there's no NaN non-determinism.
this.write_scalar(Scalar::from_f64(f.abs()), dest)?; this.write_scalar(Scalar::from_f64(f.abs()), dest)?;
} }
#[rustfmt::skip] #[rustfmt::skip]
@ -170,25 +172,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
| "rintf32" | "rintf32"
=> { => {
let [f] = check_arg_count(args)?; let [f] = check_arg_count(args)?;
let f = this.read_scalar(f)?.to_f32()?;
// FIXME: Using host floats. // FIXME: Using host floats.
let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f_host = f.to_host();
let f = match intrinsic_name { let res = match intrinsic_name {
"sinf32" => f.sin(), "sinf32" => f_host.sin(),
"cosf32" => f.cos(), "cosf32" => f_host.cos(),
"sqrtf32" => f.sqrt(), "sqrtf32" => f_host.sqrt(),
"expf32" => f.exp(), "expf32" => f_host.exp(),
"exp2f32" => f.exp2(), "exp2f32" => f_host.exp2(),
"logf32" => f.ln(), "logf32" => f_host.ln(),
"log10f32" => f.log10(), "log10f32" => f_host.log10(),
"log2f32" => f.log2(), "log2f32" => f_host.log2(),
"floorf32" => f.floor(), "floorf32" => f_host.floor(),
"ceilf32" => f.ceil(), "ceilf32" => f_host.ceil(),
"truncf32" => f.trunc(), "truncf32" => f_host.trunc(),
"roundf32" => f.round(), "roundf32" => f_host.round(),
"rintf32" => f.round_ties_even(), "rintf32" => f_host.round_ties_even(),
_ => bug!(), _ => bug!(),
}; };
this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; let res = res.to_soft();
let res = this.adjust_nan(res, &[f]);
this.write_scalar(res, dest)?;
} }
#[rustfmt::skip] #[rustfmt::skip]
@ -207,25 +212,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
| "rintf64" | "rintf64"
=> { => {
let [f] = check_arg_count(args)?; let [f] = check_arg_count(args)?;
let f = this.read_scalar(f)?.to_f64()?;
// FIXME: Using host floats. // FIXME: Using host floats.
let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f_host = f.to_host();
let f = match intrinsic_name { let res = match intrinsic_name {
"sinf64" => f.sin(), "sinf64" => f_host.sin(),
"cosf64" => f.cos(), "cosf64" => f_host.cos(),
"sqrtf64" => f.sqrt(), "sqrtf64" => f_host.sqrt(),
"expf64" => f.exp(), "expf64" => f_host.exp(),
"exp2f64" => f.exp2(), "exp2f64" => f_host.exp2(),
"logf64" => f.ln(), "logf64" => f_host.ln(),
"log10f64" => f.log10(), "log10f64" => f_host.log10(),
"log2f64" => f.log2(), "log2f64" => f_host.log2(),
"floorf64" => f.floor(), "floorf64" => f_host.floor(),
"ceilf64" => f.ceil(), "ceilf64" => f_host.ceil(),
"truncf64" => f.trunc(), "truncf64" => f_host.trunc(),
"roundf64" => f.round(), "roundf64" => f_host.round(),
"rintf64" => f.round_ties_even(), "rintf64" => f_host.round_ties_even(),
_ => bug!(), _ => bug!(),
}; };
this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; let res = res.to_soft();
let res = this.adjust_nan(res, &[f]);
this.write_scalar(res, dest)?;
} }
#[rustfmt::skip] #[rustfmt::skip]
@ -268,7 +276,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
), ),
_ => {} _ => {}
} }
this.binop_ignore_overflow(op, &a, &b, dest)?; let res = this.wrapping_binary_op(op, &a, &b)?;
if !float_finite(&res)? {
throw_ub_format!("`{intrinsic_name}` intrinsic produced non-finite value as result");
}
// This cannot be a NaN so we also don't have to apply any non-determinism.
// (Also, `wrapping_binary_op` already called `generate_nan` if needed.)
this.write_immediate(*res, dest)?;
} }
#[rustfmt::skip] #[rustfmt::skip]
@ -280,9 +294,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let a = this.read_scalar(a)?.to_f32()?; let a = this.read_scalar(a)?.to_f32()?;
let b = this.read_scalar(b)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?;
let res = match intrinsic_name { let res = match intrinsic_name {
"minnumf32" => a.min(b), "minnumf32" => this.adjust_nan(a.min(b), &[a, b]),
"maxnumf32" => a.max(b), "maxnumf32" => this.adjust_nan(a.max(b), &[a, b]),
"copysignf32" => a.copy_sign(b), "copysignf32" => a.copy_sign(b), // bitwise, no NaN adjustments
_ => bug!(), _ => bug!(),
}; };
this.write_scalar(Scalar::from_f32(res), dest)?; this.write_scalar(Scalar::from_f32(res), dest)?;
@ -297,68 +311,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let a = this.read_scalar(a)?.to_f64()?; let a = this.read_scalar(a)?.to_f64()?;
let b = this.read_scalar(b)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?;
let res = match intrinsic_name { let res = match intrinsic_name {
"minnumf64" => a.min(b), "minnumf64" => this.adjust_nan(a.min(b), &[a, b]),
"maxnumf64" => a.max(b), "maxnumf64" => this.adjust_nan(a.max(b), &[a, b]),
"copysignf64" => a.copy_sign(b), "copysignf64" => a.copy_sign(b), // bitwise, no NaN adjustments
_ => bug!(), _ => bug!(),
}; };
this.write_scalar(Scalar::from_f64(res), dest)?; this.write_scalar(Scalar::from_f64(res), dest)?;
} }
"powf32" => {
let [f, f2] = check_arg_count(args)?;
// FIXME: Using host floats.
let f = f32::from_bits(this.read_scalar(f)?.to_u32()?);
let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?);
let res = f.powf(f2);
this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?;
}
"powf64" => {
let [f, f2] = check_arg_count(args)?;
// FIXME: Using host floats.
let f = f64::from_bits(this.read_scalar(f)?.to_u64()?);
let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?);
let res = f.powf(f2);
this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?;
}
"fmaf32" => { "fmaf32" => {
let [a, b, c] = check_arg_count(args)?; let [a, b, c] = check_arg_count(args)?;
let a = this.read_scalar(a)?.to_f32()?;
let b = this.read_scalar(b)?.to_f32()?;
let c = this.read_scalar(c)?.to_f32()?;
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
let a = f32::from_bits(this.read_scalar(a)?.to_u32()?); let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
let b = f32::from_bits(this.read_scalar(b)?.to_u32()?); let res = this.adjust_nan(res, &[a, b, c]);
let c = f32::from_bits(this.read_scalar(c)?.to_u32()?); this.write_scalar(res, dest)?;
let res = a.mul_add(b, c);
this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?;
} }
"fmaf64" => { "fmaf64" => {
let [a, b, c] = check_arg_count(args)?; let [a, b, c] = check_arg_count(args)?;
let a = this.read_scalar(a)?.to_f64()?;
let b = this.read_scalar(b)?.to_f64()?;
let c = this.read_scalar(c)?.to_f64()?;
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
let a = f64::from_bits(this.read_scalar(a)?.to_u64()?); let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
let b = f64::from_bits(this.read_scalar(b)?.to_u64()?); let res = this.adjust_nan(res, &[a, b, c]);
let c = f64::from_bits(this.read_scalar(c)?.to_u64()?); this.write_scalar(res, dest)?;
let res = a.mul_add(b, c); }
this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?;
"powf32" => {
let [f1, f2] = check_arg_count(args)?;
let f1 = this.read_scalar(f1)?.to_f32()?;
let f2 = this.read_scalar(f2)?.to_f32()?;
// FIXME: Using host floats.
let res = f1.to_host().powf(f2.to_host()).to_soft();
let res = this.adjust_nan(res, &[f1, f2]);
this.write_scalar(res, dest)?;
}
"powf64" => {
let [f1, f2] = check_arg_count(args)?;
let f1 = this.read_scalar(f1)?.to_f64()?;
let f2 = this.read_scalar(f2)?.to_f64()?;
// FIXME: Using host floats.
let res = f1.to_host().powf(f2.to_host()).to_soft();
let res = this.adjust_nan(res, &[f1, f2]);
this.write_scalar(res, dest)?;
} }
"powif32" => { "powif32" => {
let [f, i] = check_arg_count(args)?; let [f, i] = check_arg_count(args)?;
// FIXME: Using host floats. let f = this.read_scalar(f)?.to_f32()?;
let f = f32::from_bits(this.read_scalar(f)?.to_u32()?);
let i = this.read_scalar(i)?.to_i32()?; let i = this.read_scalar(i)?.to_i32()?;
let res = f.powi(i); // FIXME: Using host floats.
this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; let res = f.to_host().powi(i).to_soft();
let res = this.adjust_nan(res, &[f]);
this.write_scalar(res, dest)?;
} }
"powif64" => { "powif64" => {
let [f, i] = check_arg_count(args)?; let [f, i] = check_arg_count(args)?;
// FIXME: Using host floats. let f = this.read_scalar(f)?.to_f64()?;
let f = f64::from_bits(this.read_scalar(f)?.to_u64()?);
let i = this.read_scalar(i)?.to_i32()?; let i = this.read_scalar(i)?.to_i32()?;
let res = f.powi(i); // FIXME: Using host floats.
this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; let res = f.to_host().powi(i).to_soft();
let res = this.adjust_nan(res, &[f]);
this.write_scalar(res, dest)?;
} }
"float_to_int_unchecked" => { "float_to_int_unchecked" => {

View File

@ -4,11 +4,15 @@ use rustc_middle::{mir, ty, ty::FloatTy};
use rustc_span::{sym, Symbol}; use rustc_span::{sym, Symbol};
use rustc_target::abi::{Endian, HasDataLayout}; use rustc_target::abi::{Endian, HasDataLayout};
use crate::helpers::{ use crate::helpers::{bool_to_simd_element, check_arg_count, simd_element_to_bool, ToHost, ToSoft};
bool_to_simd_element, check_arg_count, round_to_next_multiple_of, simd_element_to_bool,
};
use crate::*; use crate::*;
#[derive(Copy, Clone)]
pub(crate) enum MinMax {
Min,
Max,
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// Calls the simd intrinsic `intrinsic`; the `simd_` prefix has already been removed. /// Calls the simd intrinsic `intrinsic`; the `simd_` prefix has already been removed.
@ -67,13 +71,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let op = this.read_immediate(&this.project_index(&op, i)?)?; let op = this.read_immediate(&this.project_index(&op, i)?)?;
let dest = this.project_index(&dest, i)?; let dest = this.project_index(&dest, i)?;
let val = match which { let val = match which {
Op::MirOp(mir_op) => this.wrapping_unary_op(mir_op, &op)?.to_scalar(), Op::MirOp(mir_op) => {
// This already does NaN adjustments
this.wrapping_unary_op(mir_op, &op)?.to_scalar()
}
Op::Abs => { Op::Abs => {
// Works for f32 and f64. // Works for f32 and f64.
let ty::Float(float_ty) = op.layout.ty.kind() else { let ty::Float(float_ty) = op.layout.ty.kind() else {
span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name)
}; };
let op = op.to_scalar(); let op = op.to_scalar();
// "Bitwise" operation, no NaN adjustments
match float_ty { match float_ty {
FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()), FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()),
FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()),
@ -86,14 +94,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// FIXME using host floats // FIXME using host floats
match float_ty { match float_ty {
FloatTy::F32 => { FloatTy::F32 => {
let f = f32::from_bits(op.to_scalar().to_u32()?); let f = op.to_scalar().to_f32()?;
let res = f.sqrt(); let res = f.to_host().sqrt().to_soft();
Scalar::from_u32(res.to_bits()) let res = this.adjust_nan(res, &[f]);
Scalar::from(res)
} }
FloatTy::F64 => { FloatTy::F64 => {
let f = f64::from_bits(op.to_scalar().to_u64()?); let f = op.to_scalar().to_f64()?;
let res = f.sqrt(); let res = f.to_host().sqrt().to_soft();
Scalar::from_u64(res.to_bits()) let res = this.adjust_nan(res, &[f]);
Scalar::from(res)
} }
} }
} }
@ -105,11 +115,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
FloatTy::F32 => { FloatTy::F32 => {
let f = op.to_scalar().to_f32()?; let f = op.to_scalar().to_f32()?;
let res = f.round_to_integral(rounding).value; let res = f.round_to_integral(rounding).value;
let res = this.adjust_nan(res, &[f]);
Scalar::from_f32(res) Scalar::from_f32(res)
} }
FloatTy::F64 => { FloatTy::F64 => {
let f = op.to_scalar().to_f64()?; let f = op.to_scalar().to_f64()?;
let res = f.round_to_integral(rounding).value; let res = f.round_to_integral(rounding).value;
let res = this.adjust_nan(res, &[f]);
Scalar::from_f64(res) Scalar::from_f64(res)
} }
} }
@ -157,8 +169,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
enum Op { enum Op {
MirOp(BinOp), MirOp(BinOp),
SaturatingOp(BinOp), SaturatingOp(BinOp),
FMax, FMinMax(MinMax),
FMin,
WrappingOffset, WrappingOffset,
} }
let which = match intrinsic_name { let which = match intrinsic_name {
@ -178,8 +189,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"le" => Op::MirOp(BinOp::Le), "le" => Op::MirOp(BinOp::Le),
"gt" => Op::MirOp(BinOp::Gt), "gt" => Op::MirOp(BinOp::Gt),
"ge" => Op::MirOp(BinOp::Ge), "ge" => Op::MirOp(BinOp::Ge),
"fmax" => Op::FMax, "fmax" => Op::FMinMax(MinMax::Max),
"fmin" => Op::FMin, "fmin" => Op::FMinMax(MinMax::Min),
"saturating_add" => Op::SaturatingOp(BinOp::Add), "saturating_add" => Op::SaturatingOp(BinOp::Add),
"saturating_sub" => Op::SaturatingOp(BinOp::Sub), "saturating_sub" => Op::SaturatingOp(BinOp::Sub),
"arith_offset" => Op::WrappingOffset, "arith_offset" => Op::WrappingOffset,
@ -192,6 +203,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let dest = this.project_index(&dest, i)?; let dest = this.project_index(&dest, i)?;
let val = match which { let val = match which {
Op::MirOp(mir_op) => { Op::MirOp(mir_op) => {
// This does NaN adjustments.
let (val, overflowed) = this.overflowing_binary_op(mir_op, &left, &right)?; let (val, overflowed) = this.overflowing_binary_op(mir_op, &left, &right)?;
if matches!(mir_op, BinOp::Shl | BinOp::Shr) { if matches!(mir_op, BinOp::Shl | BinOp::Shr) {
// Shifts have extra UB as SIMD operations that the MIR binop does not have. // Shifts have extra UB as SIMD operations that the MIR binop does not have.
@ -225,11 +237,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, this); let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, this);
Scalar::from_maybe_pointer(offset_ptr, this) Scalar::from_maybe_pointer(offset_ptr, this)
} }
Op::FMax => { Op::FMinMax(op) => {
fmax_op(&left, &right)? this.fminmax_op(op, &left, &right)?
}
Op::FMin => {
fmin_op(&left, &right)?
} }
}; };
this.write_scalar(val, &dest)?; this.write_scalar(val, &dest)?;
@ -259,18 +268,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}; };
let val = match float_ty { let val = match float_ty {
FloatTy::F32 => { FloatTy::F32 => {
let a = f32::from_bits(a.to_u32()?); let a = a.to_f32()?;
let b = f32::from_bits(b.to_u32()?); let b = b.to_f32()?;
let c = f32::from_bits(c.to_u32()?); let c = c.to_f32()?;
let res = a.mul_add(b, c); let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
Scalar::from_u32(res.to_bits()) let res = this.adjust_nan(res, &[a, b, c]);
Scalar::from(res)
} }
FloatTy::F64 => { FloatTy::F64 => {
let a = f64::from_bits(a.to_u64()?); let a = a.to_f64()?;
let b = f64::from_bits(b.to_u64()?); let b = b.to_f64()?;
let c = f64::from_bits(c.to_u64()?); let c = c.to_f64()?;
let res = a.mul_add(b, c); let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
Scalar::from_u64(res.to_bits()) let res = this.adjust_nan(res, &[a, b, c]);
Scalar::from(res)
} }
}; };
this.write_scalar(val, &dest)?; this.write_scalar(val, &dest)?;
@ -295,8 +306,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
enum Op { enum Op {
MirOp(BinOp), MirOp(BinOp),
MirOpBool(BinOp), MirOpBool(BinOp),
Max, MinMax(MinMax),
Min,
} }
let which = match intrinsic_name { let which = match intrinsic_name {
"reduce_and" => Op::MirOp(BinOp::BitAnd), "reduce_and" => Op::MirOp(BinOp::BitAnd),
@ -304,8 +314,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"reduce_xor" => Op::MirOp(BinOp::BitXor), "reduce_xor" => Op::MirOp(BinOp::BitXor),
"reduce_any" => Op::MirOpBool(BinOp::BitOr), "reduce_any" => Op::MirOpBool(BinOp::BitOr),
"reduce_all" => Op::MirOpBool(BinOp::BitAnd), "reduce_all" => Op::MirOpBool(BinOp::BitAnd),
"reduce_max" => Op::Max, "reduce_max" => Op::MinMax(MinMax::Max),
"reduce_min" => Op::Min, "reduce_min" => Op::MinMax(MinMax::Min),
_ => unreachable!(), _ => unreachable!(),
}; };
@ -325,24 +335,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let op = imm_from_bool(simd_element_to_bool(op)?); let op = imm_from_bool(simd_element_to_bool(op)?);
this.wrapping_binary_op(mir_op, &res, &op)? this.wrapping_binary_op(mir_op, &res, &op)?
} }
Op::Max => { Op::MinMax(mmop) => {
if matches!(res.layout.ty.kind(), ty::Float(_)) { if matches!(res.layout.ty.kind(), ty::Float(_)) {
ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout) ImmTy::from_scalar(this.fminmax_op(mmop, &res, &op)?, res.layout)
} else { } else {
// Just boring integers, so NaNs to worry about // Just boring integers, so NaNs to worry about
if this.wrapping_binary_op(BinOp::Ge, &res, &op)?.to_scalar().to_bool()? { let mirop = match mmop {
res MinMax::Min => BinOp::Le,
} else { MinMax::Max => BinOp::Ge,
op };
} if this.wrapping_binary_op(mirop, &res, &op)?.to_scalar().to_bool()? {
}
}
Op::Min => {
if matches!(res.layout.ty.kind(), ty::Float(_)) {
ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout)
} else {
// Just boring integers, so NaNs to worry about
if this.wrapping_binary_op(BinOp::Le, &res, &op)?.to_scalar().to_bool()? {
res res
} else { } else {
op op
@ -402,7 +404,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let (yes, yes_len) = this.operand_to_simd(yes)?; let (yes, yes_len) = this.operand_to_simd(yes)?;
let (no, no_len) = this.operand_to_simd(no)?; let (no, no_len) = this.operand_to_simd(no)?;
let (dest, dest_len) = this.place_to_simd(dest)?; let (dest, dest_len) = this.place_to_simd(dest)?;
let bitmask_len = round_to_next_multiple_of(dest_len, 8); let bitmask_len = dest_len.next_multiple_of(8);
// The mask must be an integer or an array. // The mask must be an integer or an array.
assert!( assert!(
@ -448,7 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"bitmask" => { "bitmask" => {
let [op] = check_arg_count(args)?; let [op] = check_arg_count(args)?;
let (op, op_len) = this.operand_to_simd(op)?; let (op, op_len) = this.operand_to_simd(op)?;
let bitmask_len = round_to_next_multiple_of(op_len, 8); let bitmask_len = op_len.next_multiple_of(8);
// Returns either an unsigned integer or array of `u8`. // Returns either an unsigned integer or array of `u8`.
assert!( assert!(
@ -709,6 +711,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
Ok(()) Ok(())
} }
fn fminmax_op(
&self,
op: MinMax,
left: &ImmTy<'tcx, Provenance>,
right: &ImmTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_ref();
assert_eq!(left.layout.ty, right.layout.ty);
let ty::Float(float_ty) = left.layout.ty.kind() else {
bug!("fmax operand is not a float")
};
let left = left.to_scalar();
let right = right.to_scalar();
Ok(match float_ty {
FloatTy::F32 => {
let left = left.to_f32()?;
let right = right.to_f32()?;
let res = match op {
MinMax::Min => left.min(right),
MinMax::Max => left.max(right),
};
let res = this.adjust_nan(res, &[left, right]);
Scalar::from_f32(res)
}
FloatTy::F64 => {
let left = left.to_f64()?;
let right = right.to_f64()?;
let res = match op {
MinMax::Min => left.min(right),
MinMax::Max => left.max(right),
};
let res = this.adjust_nan(res, &[left, right]);
Scalar::from_f64(res)
}
})
}
} }
fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 { fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 {
@ -719,31 +758,3 @@ fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 {
Endian::Big => vec_len - 1 - idx, // reverse order of bits Endian::Big => vec_len - 1 - idx, // reverse order of bits
} }
} }
fn fmax_op<'tcx>(
left: &ImmTy<'tcx, Provenance>,
right: &ImmTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Scalar<Provenance>> {
assert_eq!(left.layout.ty, right.layout.ty);
let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmax operand is not a float") };
let left = left.to_scalar();
let right = right.to_scalar();
Ok(match float_ty {
FloatTy::F32 => Scalar::from_f32(left.to_f32()?.max(right.to_f32()?)),
FloatTy::F64 => Scalar::from_f64(left.to_f64()?.max(right.to_f64()?)),
})
}
fn fmin_op<'tcx>(
left: &ImmTy<'tcx, Provenance>,
right: &ImmTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Scalar<Provenance>> {
assert_eq!(left.layout.ty, right.layout.ty);
let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmin operand is not a float") };
let left = left.to_scalar();
let right = right.to_scalar();
Ok(match float_ty {
FloatTy::F32 => Scalar::from_f32(left.to_f32()?.min(right.to_f32()?)),
FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)),
})
}

View File

@ -559,8 +559,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
); );
}; };
if mode != 0o666 { #[cfg(unix)]
throw_unsup_format!("non-default mode 0o{:o} is not supported", mode); {
// Support all modes on UNIX host
use std::os::unix::fs::OpenOptionsExt;
options.mode(mode);
}
#[cfg(not(unix))]
{
// Only support default mode for non-UNIX (i.e. Windows) host
if mode != 0o666 {
throw_unsup_format!(
"non-default mode 0o{:o} is not supported on non-Unix hosts",
mode
);
}
} }
mirror |= o_creat; mirror |= o_creat;

View File

@ -14,7 +14,7 @@
//! munmap shim which would partily unmap a region of address space previously mapped by mmap will //! munmap shim which would partily unmap a region of address space previously mapped by mmap will
//! report UB. //! report UB.
use crate::{helpers::round_to_next_multiple_of, *}; use crate::*;
use rustc_target::abi::Size; use rustc_target::abi::Size;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
@ -96,7 +96,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
let align = this.machine.page_align(); let align = this.machine.page_align();
let map_length = round_to_next_multiple_of(length, this.machine.page_size); let Some(map_length) = length.checked_next_multiple_of(this.machine.page_size) else {
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?;
return Ok(this.eval_libc("MAP_FAILED"));
};
if map_length > this.target_usize_max() {
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?;
return Ok(this.eval_libc("MAP_FAILED"));
}
let ptr = let ptr =
this.allocate_ptr(Size::from_bytes(map_length), align, MiriMemoryKind::Mmap.into())?; this.allocate_ptr(Size::from_bytes(map_length), align, MiriMemoryKind::Mmap.into())?;
@ -129,7 +136,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
return Ok(Scalar::from_i32(-1)); return Ok(Scalar::from_i32(-1));
} }
let length = Size::from_bytes(round_to_next_multiple_of(length, this.machine.page_size)); let Some(length) = length.checked_next_multiple_of(this.machine.page_size) else {
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?;
return Ok(Scalar::from_i32(-1));
};
if length > this.target_usize_max() {
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?;
return Ok(this.eval_libc("MAP_FAILED"));
}
let length = Size::from_bytes(length);
this.deallocate_ptr( this.deallocate_ptr(
addr, addr,
Some((length, this.machine.page_align())), Some((length, this.machine.page_align())),

View File

@ -44,6 +44,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.14.0" version = "3.14.0"
@ -71,6 +77,22 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "errno"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "fastrand"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.1.16" version = "0.1.16"
@ -122,6 +144,12 @@ version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "linux-raw-sys"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.10" version = "0.4.10"
@ -161,7 +189,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [ dependencies = [
"libc", "libc",
"wasi 0.11.0+wasi-snapshot-preview1", "wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
@ -174,7 +202,9 @@ dependencies = [
"num_cpus", "num_cpus",
"page_size", "page_size",
"rand", "rand",
"tempfile",
"tokio", "tokio",
"windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -230,9 +260,9 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"redox_syscall", "redox_syscall 0.3.5",
"smallvec", "smallvec",
"windows-targets", "windows-targets 0.48.5",
] ]
[[package]] [[package]]
@ -301,7 +331,16 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
] ]
[[package]] [[package]]
@ -310,6 +349,19 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.38.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
dependencies = [
"bitflags 2.4.1",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
@ -338,7 +390,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
@ -352,6 +404,19 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "tempfile"
version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
dependencies = [
"cfg-if",
"fastrand",
"redox_syscall 0.4.1",
"rustix",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.32.0" version = "1.32.0"
@ -368,7 +433,7 @@ dependencies = [
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2",
"tokio-macros", "tokio-macros",
"windows-sys", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
@ -482,7 +547,16 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.0",
] ]
[[package]] [[package]]
@ -491,13 +565,28 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc", "windows_aarch64_msvc 0.48.5",
"windows_i686_gnu", "windows_i686_gnu 0.48.5",
"windows_i686_msvc", "windows_i686_msvc 0.48.5",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc", "windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
] ]
[[package]] [[package]]
@ -506,38 +595,80 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.48.5" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"

View File

@ -11,6 +11,7 @@ edition = "2021"
# all dependencies (and their transitive ones) listed here can be used in `tests/`. # all dependencies (and their transitive ones) listed here can be used in `tests/`.
libc = "0.2" libc = "0.2"
num_cpus = "1.10.1" num_cpus = "1.10.1"
tempfile = "3"
getrandom_01 = { package = "getrandom", version = "0.1" } getrandom_01 = { package = "getrandom", version = "0.1" }
getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] } getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] }
@ -20,4 +21,7 @@ rand = { version = "0.8", features = ["small_rng"] }
page_size = "0.6" page_size = "0.6"
tokio = { version = "1.24", features = ["full"] } tokio = { version = "1.24", features = ["full"] }
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.52", features = [ "Win32_Foundation", "Win32_System_Threading" ] }
[workspace] [workspace]

View File

@ -111,6 +111,8 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
"run".into(), // There is no `cargo miri build` so we just use `cargo miri run`. "run".into(), // There is no `cargo miri build` so we just use `cargo miri run`.
]); ]);
config.dependency_builder.args = builder_args.into_iter().map(Into::into).collect(); config.dependency_builder.args = builder_args.into_iter().map(Into::into).collect();
// Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>.
config.dependency_builder.envs.push(("RUSTFLAGS".into(), None));
} }
config config
} }

View File

@ -3,18 +3,16 @@
// Joining a detached thread is undefined behavior. // Joining a detached thread is undefined behavior.
use std::os::windows::io::{AsRawHandle, RawHandle}; use std::os::windows::io::AsRawHandle;
use std::thread; use std::thread;
extern "system" { use windows_sys::Win32::Foundation::{CloseHandle, HANDLE};
fn CloseHandle(handle: RawHandle) -> u32;
}
fn main() { fn main() {
let thread = thread::spawn(|| ()); let thread = thread::spawn(|| ());
unsafe { unsafe {
assert_ne!(CloseHandle(thread.as_raw_handle()), 0); assert_ne!(CloseHandle(thread.as_raw_handle() as HANDLE), 0);
} }
thread.join().unwrap(); thread.join().unwrap();

View File

@ -6,21 +6,18 @@
use std::thread; use std::thread;
extern "system" { use windows_sys::Win32::Foundation::{HANDLE, WAIT_OBJECT_0};
fn WaitForSingleObject(handle: isize, timeout: u32) -> u32; use windows_sys::Win32::System::Threading::{WaitForSingleObject, INFINITE};
}
const INFINITE: u32 = u32::MAX;
// XXX HACK: This is how miri represents the handle for thread 0. // XXX HACK: This is how miri represents the handle for thread 0.
// This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle` // This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle`
// but miri does not implement `DuplicateHandle` yet. // but miri does not implement `DuplicateHandle` yet.
const MAIN_THREAD: isize = (2i32 << 30) as isize; const MAIN_THREAD: HANDLE = (2i32 << 30) as HANDLE;
fn main() { fn main() {
thread::spawn(|| { thread::spawn(|| {
unsafe { unsafe {
assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), 0); //~ ERROR: deadlock: the evaluated program deadlocked assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJECT_0); //~ ERROR: deadlock: the evaluated program deadlocked
} }
}) })
.join() .join()

View File

@ -1,8 +1,8 @@
error: deadlock: the evaluated program deadlocked error: deadlock: the evaluated program deadlocked
--> $DIR/windows_join_main.rs:LL:CC --> $DIR/windows_join_main.rs:LL:CC
| |
LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), 0); LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJECT_0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked
| |
= note: inside closure at RUSTLIB/core/src/macros/mod.rs:LL:CC = note: inside closure at RUSTLIB/core/src/macros/mod.rs:LL:CC
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -6,18 +6,14 @@
use std::thread; use std::thread;
extern "system" { use windows_sys::Win32::Foundation::WAIT_OBJECT_0;
fn GetCurrentThread() -> usize; use windows_sys::Win32::System::Threading::{GetCurrentThread, WaitForSingleObject, INFINITE};
fn WaitForSingleObject(handle: usize, timeout: u32) -> u32;
}
const INFINITE: u32 = u32::MAX;
fn main() { fn main() {
thread::spawn(|| { thread::spawn(|| {
unsafe { unsafe {
let native = GetCurrentThread(); let native = GetCurrentThread();
assert_eq!(WaitForSingleObject(native, INFINITE), 0); //~ ERROR: deadlock: the evaluated program deadlocked assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0); //~ ERROR: deadlock: the evaluated program deadlocked
} }
}) })
.join() .join()

View File

@ -1,7 +1,7 @@
error: deadlock: the evaluated program deadlocked error: deadlock: the evaluated program deadlocked
--> $DIR/windows_join_self.rs:LL:CC --> $DIR/windows_join_self.rs:LL:CC
| |
LL | assert_eq!(WaitForSingleObject(native, INFINITE), 0); LL | assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0);
| ^ the evaluated program deadlocked | ^ the evaluated program deadlocked
| |
= note: inside closure at $DIR/windows_join_self.rs:LL:CC = note: inside closure at $DIR/windows_join_self.rs:LL:CC

View File

@ -14,7 +14,7 @@ fn main() {
let ptr = std::ptr::addr_of_mut!(non_copy); let ptr = std::ptr::addr_of_mut!(non_copy);
// Inside `callee`, the first argument and `*ptr` are basically // Inside `callee`, the first argument and `*ptr` are basically
// aliasing places! // aliasing places!
Call(_unit = callee(Move(*ptr), ptr), after_call, UnwindContinue()) Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
} }
after_call = { after_call = {
Return() Return()

View File

@ -27,8 +27,8 @@ LL | unsafe { ptr.write(S(0)) };
note: inside `main` note: inside `main`
--> $DIR/arg_inplace_mutate.rs:LL:CC --> $DIR/arg_inplace_mutate.rs:LL:CC
| |
LL | Call(_unit = callee(Move(*ptr), ptr), after_call, UnwindContinue()) LL | Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -35,8 +35,8 @@ LL | unsafe { ptr.write(S(0)) };
note: inside `main` note: inside `main`
--> $DIR/arg_inplace_mutate.rs:LL:CC --> $DIR/arg_inplace_mutate.rs:LL:CC
| |
LL | Call(_unit = callee(Move(*ptr), ptr), after_call, UnwindContinue()) LL | Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -11,7 +11,7 @@ fn main() {
{ {
let non_copy = S(42); let non_copy = S(42);
// This could change `non_copy` in-place // This could change `non_copy` in-place
Call(_unit = change_arg(Move(non_copy)), after_call, UnwindContinue()) Call(_unit = change_arg(Move(non_copy)), ReturnTo(after_call), UnwindContinue())
} }
after_call = { after_call = {
// So now we must not be allowed to observe non-copy again. // So now we must not be allowed to observe non-copy again.

View File

@ -11,8 +11,8 @@ LL | unsafe { ptr.read() };
note: inside `main` note: inside `main`
--> $DIR/arg_inplace_observe_during.rs:LL:CC --> $DIR/arg_inplace_observe_during.rs:LL:CC
| |
LL | Call(_unit = change_arg(Move(*ptr), ptr), after_call, UnwindContinue()) LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -14,7 +14,7 @@ fn main() {
let non_copy = S(42); let non_copy = S(42);
let ptr = std::ptr::addr_of_mut!(non_copy); let ptr = std::ptr::addr_of_mut!(non_copy);
// This could change `non_copy` in-place // This could change `non_copy` in-place
Call(_unit = change_arg(Move(*ptr), ptr), after_call, UnwindContinue()) Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
} }
after_call = { after_call = {
Return() Return()

View File

@ -27,8 +27,8 @@ LL | x.0 = 0;
note: inside `main` note: inside `main`
--> $DIR/arg_inplace_observe_during.rs:LL:CC --> $DIR/arg_inplace_observe_during.rs:LL:CC
| |
LL | Call(_unit = change_arg(Move(*ptr), ptr), after_call, UnwindContinue()) LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -35,8 +35,8 @@ LL | x.0 = 0;
note: inside `main` note: inside `main`
--> $DIR/arg_inplace_observe_during.rs:LL:CC --> $DIR/arg_inplace_observe_during.rs:LL:CC
| |
LL | Call(_unit = change_arg(Move(*ptr), ptr), after_call, UnwindContinue()) LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -11,8 +11,8 @@ LL | unsafe { ptr.read() };
note: inside `main` note: inside `main`
--> $DIR/return_pointer_aliasing.rs:LL:CC --> $DIR/return_pointer_aliasing.rs:LL:CC
| |
LL | Call(*ptr = myfun(ptr), after_call, UnwindContinue()) LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -15,7 +15,7 @@ pub fn main() {
let ptr = &raw mut x; let ptr = &raw mut x;
// We arrange for `myfun` to have a pointer that aliases // We arrange for `myfun` to have a pointer that aliases
// its return place. Even just reading from that pointer is UB. // its return place. Even just reading from that pointer is UB.
Call(*ptr = myfun(ptr), after_call, UnwindContinue()) Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
} }
after_call = { after_call = {

View File

@ -27,8 +27,8 @@ LL | unsafe { ptr.read() };
note: inside `main` note: inside `main`
--> $DIR/return_pointer_aliasing.rs:LL:CC --> $DIR/return_pointer_aliasing.rs:LL:CC
| |
LL | Call(*ptr = myfun(ptr), after_call, UnwindContinue()) LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -35,8 +35,8 @@ LL | unsafe { ptr.read() };
note: inside `main` note: inside `main`
--> $DIR/return_pointer_aliasing.rs:LL:CC --> $DIR/return_pointer_aliasing.rs:LL:CC
| |
LL | Call(*ptr = myfun(ptr), after_call, UnwindContinue()) LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -15,7 +15,7 @@ pub fn main() {
let ptr = &raw mut _x; let ptr = &raw mut _x;
// We arrange for `myfun` to have a pointer that aliases // We arrange for `myfun` to have a pointer that aliases
// its return place. Even just reading from that pointer is UB. // its return place. Even just reading from that pointer is UB.
Call(_x = myfun(ptr), after_call, UnwindContinue()) Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
} }
after_call = { after_call = {

View File

@ -30,8 +30,8 @@ LL | unsafe { ptr.write(0) };
note: inside `main` note: inside `main`
--> $DIR/return_pointer_aliasing2.rs:LL:CC --> $DIR/return_pointer_aliasing2.rs:LL:CC
| |
LL | Call(_x = myfun(ptr), after_call, UnwindContinue()) LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -35,8 +35,8 @@ LL | unsafe { ptr.write(0) };
note: inside `main` note: inside `main`
--> $DIR/return_pointer_aliasing2.rs:LL:CC --> $DIR/return_pointer_aliasing2.rs:LL:CC
| |
LL | Call(_x = myfun(ptr), after_call, UnwindContinue()) LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -14,7 +14,7 @@ struct S(i32, [u8; 128]);
fn docall(out: &mut S) { fn docall(out: &mut S) {
mir! { mir! {
{ {
Call(*out = callee(), after_call, UnwindContinue()) Call(*out = callee(), ReturnTo(after_call), UnwindContinue())
} }
after_call = { after_call = {
@ -37,7 +37,7 @@ fn callee() -> S {
// become visible to the outside. In codegen we can see them // become visible to the outside. In codegen we can see them
// but Miri should detect this as UB! // but Miri should detect this as UB!
RET.0 = 42; RET.0 = 42;
Call(_unit = startpanic(), after_call, UnwindContinue()) Call(_unit = startpanic(), ReturnTo(after_call), UnwindContinue())
} }
after_call = { after_call = {

View File

@ -0,0 +1,7 @@
#![feature(core_intrinsics)]
fn main() {
unsafe {
let _x: f32 = core::intrinsics::fdiv_fast(1.0, 0.0); //~ ERROR: `fdiv_fast` intrinsic produced non-finite value as result
}
}

View File

@ -0,0 +1,15 @@
error: Undefined Behavior: `fdiv_fast` intrinsic produced non-finite value as result
--> $DIR/fast_math_result.rs:LL:CC
|
LL | let _x: f32 = core::intrinsics::fdiv_fast(1.0, 0.0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fdiv_fast` intrinsic produced non-finite value as result
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at $DIR/fast_math_result.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View File

@ -20,7 +20,7 @@ fn call(f: fn(NonZeroU32)) {
let tmp = ptr::addr_of!(c); let tmp = ptr::addr_of!(c);
let ptr = tmp as *const NonZeroU32; let ptr = tmp as *const NonZeroU32;
// The call site now is a NonZeroU32-to-u32 transmute. // The call site now is a NonZeroU32-to-u32 transmute.
Call(_res = f(*ptr), retblock, UnwindContinue()) //~ERROR: expected something greater or equal to 1 Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) //~ERROR: expected something greater or equal to 1
} }
retblock = { retblock = {
Return() Return()

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1
--> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
| |
LL | Call(_res = f(*ptr), retblock, UnwindContinue()) LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -2,39 +2,30 @@
// We are making scheduler assumptions here. // We are making scheduler assumptions here.
//@compile-flags: -Zmiri-preemption-rate=0 //@compile-flags: -Zmiri-preemption-rate=0
use std::ffi::c_void;
use std::ptr::null_mut; use std::ptr::null_mut;
use std::thread; use std::thread;
use windows_sys::Win32::System::Threading::{
AcquireSRWLockExclusive, AcquireSRWLockShared, ReleaseSRWLockExclusive, ReleaseSRWLockShared,
SleepConditionVariableSRW, WakeAllConditionVariable, CONDITION_VARIABLE,
CONDITION_VARIABLE_LOCKMODE_SHARED, INFINITE, SRWLOCK,
};
// not in windows-sys
const SRWLOCK_INIT: SRWLOCK = SRWLOCK { Ptr: null_mut() };
const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { Ptr: null_mut() };
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct SendPtr<T>(*mut T); struct SendPtr<T>(*mut T);
unsafe impl<T> Send for SendPtr<T> {} unsafe impl<T> Send for SendPtr<T> {}
extern "system" {
fn SleepConditionVariableSRW(
condvar: *mut *mut c_void,
lock: *mut *mut c_void,
timeout: u32,
flags: u32,
) -> i32;
fn WakeAllConditionVariable(condvar: *mut *mut c_void);
fn AcquireSRWLockExclusive(lock: *mut *mut c_void);
fn AcquireSRWLockShared(lock: *mut *mut c_void);
fn ReleaseSRWLockExclusive(lock: *mut *mut c_void);
fn ReleaseSRWLockShared(lock: *mut *mut c_void);
}
const CONDITION_VARIABLE_LOCKMODE_SHARED: u32 = 1;
const INFINITE: u32 = u32::MAX;
/// threads should be able to reacquire the lock while it is locked by multiple other threads in shared mode /// threads should be able to reacquire the lock while it is locked by multiple other threads in shared mode
fn all_shared() { fn all_shared() {
println!("all_shared"); println!("all_shared");
let mut lock = null_mut(); let mut lock = SRWLOCK_INIT;
let mut condvar = null_mut(); let mut condvar = CONDITION_VARIABLE_INIT;
let lock_ptr = SendPtr(&mut lock); let lock_ptr = SendPtr(&mut lock);
let condvar_ptr = SendPtr(&mut condvar); let condvar_ptr = SendPtr(&mut condvar);
@ -105,8 +96,8 @@ fn all_shared() {
fn shared_sleep_and_exclusive_lock() { fn shared_sleep_and_exclusive_lock() {
println!("shared_sleep_and_exclusive_lock"); println!("shared_sleep_and_exclusive_lock");
let mut lock = null_mut(); let mut lock = SRWLOCK_INIT;
let mut condvar = null_mut(); let mut condvar = CONDITION_VARIABLE_INIT;
let lock_ptr = SendPtr(&mut lock); let lock_ptr = SendPtr(&mut lock);
let condvar_ptr = SendPtr(&mut condvar); let condvar_ptr = SendPtr(&mut condvar);
@ -166,8 +157,8 @@ fn shared_sleep_and_exclusive_lock() {
fn exclusive_sleep_and_shared_lock() { fn exclusive_sleep_and_shared_lock() {
println!("exclusive_sleep_and_shared_lock"); println!("exclusive_sleep_and_shared_lock");
let mut lock = null_mut(); let mut lock = SRWLOCK_INIT;
let mut condvar = null_mut(); let mut condvar = CONDITION_VARIABLE_INIT;
let lock_ptr = SendPtr(&mut lock); let lock_ptr = SendPtr(&mut lock);
let condvar_ptr = SendPtr(&mut condvar); let condvar_ptr = SendPtr(&mut condvar);

View File

@ -5,12 +5,10 @@
use std::os::windows::io::IntoRawHandle; use std::os::windows::io::IntoRawHandle;
use std::thread; use std::thread;
extern "system" { use windows_sys::Win32::Foundation::{CloseHandle, HANDLE};
fn CloseHandle(handle: usize) -> i32;
}
fn main() { fn main() {
let thread = thread::spawn(|| {}).into_raw_handle() as usize; let thread = thread::spawn(|| {}).into_raw_handle() as HANDLE;
// this yield ensures that `thread` is terminated by this point // this yield ensures that `thread` is terminated by this point
thread::yield_now(); thread::yield_now();

View File

@ -2,33 +2,24 @@
// We are making scheduler assumptions here. // We are making scheduler assumptions here.
//@compile-flags: -Zmiri-preemption-rate=0 //@compile-flags: -Zmiri-preemption-rate=0
use std::ffi::c_void;
use std::ptr::null_mut; use std::ptr::null_mut;
use std::thread; use std::thread;
use windows_sys::Win32::Foundation::{FALSE, TRUE};
use windows_sys::Win32::System::Threading::{
InitOnceBeginInitialize, InitOnceComplete, INIT_ONCE, INIT_ONCE_INIT_FAILED,
};
// not in windows-sys
const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE { Ptr: null_mut() };
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct SendPtr<T>(*mut T); struct SendPtr<T>(*mut T);
unsafe impl<T> Send for SendPtr<T> {} unsafe impl<T> Send for SendPtr<T> {}
extern "system" {
fn InitOnceBeginInitialize(
init: *mut *mut c_void,
flags: u32,
pending: *mut i32,
context: *mut c_void,
) -> i32;
fn InitOnceComplete(init: *mut *mut c_void, flags: u32, context: *mut c_void) -> i32;
}
const TRUE: i32 = 1;
const FALSE: i32 = 0;
const INIT_ONCE_INIT_FAILED: u32 = 4;
fn single_thread() { fn single_thread() {
let mut init_once = null_mut(); let mut init_once = INIT_ONCE_STATIC_INIT;
let mut pending = 0; let mut pending = 0;
unsafe { unsafe {
@ -41,7 +32,7 @@ fn single_thread() {
assert_eq!(pending, FALSE); assert_eq!(pending, FALSE);
} }
let mut init_once = null_mut(); let mut init_once = INIT_ONCE_STATIC_INIT;
unsafe { unsafe {
assert_eq!(InitOnceBeginInitialize(&mut init_once, 0, &mut pending, null_mut()), TRUE); assert_eq!(InitOnceBeginInitialize(&mut init_once, 0, &mut pending, null_mut()), TRUE);
@ -55,7 +46,7 @@ fn single_thread() {
} }
fn block_until_complete() { fn block_until_complete() {
let mut init_once = null_mut(); let mut init_once = INIT_ONCE_STATIC_INIT;
let mut pending = 0; let mut pending = 0;
unsafe { unsafe {
@ -92,7 +83,7 @@ fn block_until_complete() {
} }
fn retry_on_fail() { fn retry_on_fail() {
let mut init_once = null_mut(); let mut init_once = INIT_ONCE_STATIC_INIT;
let mut pending = 0; let mut pending = 0;
unsafe { unsafe {
@ -134,7 +125,7 @@ fn retry_on_fail() {
} }
fn no_data_race_after_complete() { fn no_data_race_after_complete() {
let mut init_once = null_mut(); let mut init_once = INIT_ONCE_STATIC_INIT;
let mut pending = 0; let mut pending = 0;
unsafe { unsafe {

View File

@ -6,11 +6,8 @@ use std::os::windows::io::IntoRawHandle;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::thread; use std::thread;
extern "system" { use windows_sys::Win32::Foundation::{HANDLE, WAIT_OBJECT_0};
fn WaitForSingleObject(handle: usize, timeout: u32) -> u32; use windows_sys::Win32::System::Threading::{WaitForSingleObject, INFINITE};
}
const INFINITE: u32 = u32::MAX;
fn main() { fn main() {
static FLAG: AtomicBool = AtomicBool::new(false); static FLAG: AtomicBool = AtomicBool::new(false);
@ -20,10 +17,10 @@ fn main() {
thread::yield_now(); thread::yield_now();
} }
}) })
.into_raw_handle() as usize; .into_raw_handle() as HANDLE;
let waiter = move || unsafe { let waiter = move || unsafe {
assert_eq!(WaitForSingleObject(blocker, INFINITE), 0); assert_eq!(WaitForSingleObject(blocker, INFINITE), WAIT_OBJECT_0);
}; };
let waiter1 = thread::spawn(waiter); let waiter1 = thread::spawn(waiter);

View File

@ -90,9 +90,30 @@ fn test_mmap() {
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP); assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP);
} }
// We report an error for mappings whose length cannot be rounded up to a multiple of
// the page size.
let ptr = unsafe {
libc::mmap(
ptr::null_mut(),
usize::MAX - 1,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
-1,
0,
)
};
assert_eq!(ptr, libc::MAP_FAILED);
// We report an error when trying to munmap an address which is not a multiple of the page size
let res = unsafe { libc::munmap(ptr::invalid_mut(1), page_size) }; let res = unsafe { libc::munmap(ptr::invalid_mut(1), page_size) };
assert_eq!(res, -1); assert_eq!(res, -1);
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL); assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
// We report an error when trying to munmap a length that cannot be rounded up to a multiple of
// the page size.
let res = unsafe { libc::munmap(ptr::invalid_mut(page_size), usize::MAX - 1) };
assert_eq!(res, -1);
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]

View File

@ -0,0 +1,21 @@
//@ignore-target-windows: File handling is not implemented yet
//@ignore-host-windows: Only supported for UNIX hosts
//@compile-flags: -Zmiri-disable-isolation
#[path = "../utils/mod.rs"]
mod utils;
/// Test that the [`tempfile`] crate is compatible with miri for UNIX hosts and targets
fn main() {
test_tempfile();
test_tempfile_in();
}
fn test_tempfile() {
tempfile::tempfile().unwrap();
}
fn test_tempfile_in() {
let dir_path = utils::tmp();
tempfile::tempfile_in(dir_path).unwrap();
}

View File

@ -1,8 +1,16 @@
#![feature(float_gamma, portable_simd, core_intrinsics, platform_intrinsics)]
use std::collections::HashSet; use std::collections::HashSet;
use std::fmt; use std::fmt;
use std::hash::Hash; use std::hash::Hash;
use std::hint::black_box; use std::hint::black_box;
fn ldexp(a: f64, b: i32) -> f64 {
extern "C" {
fn ldexp(x: f64, n: i32) -> f64;
}
unsafe { ldexp(a, b) }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Sign { enum Sign {
Neg = 1, Neg = 1,
@ -249,6 +257,58 @@ fn test_f32() {
check_all_outcomes(HashSet::from_iter([F32::nan(Neg, Signaling, all1_payload)]), || { check_all_outcomes(HashSet::from_iter([F32::nan(Neg, Signaling, all1_payload)]), || {
F32::from(-all1_snan) F32::from(-all1_snan)
}); });
// Intrinsics
let nan = F32::nan(Neg, Quiet, 0).as_f32();
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(f32::min(nan, nan)),
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(nan.sin()),
);
check_all_outcomes(
HashSet::from_iter([
F32::nan(Pos, Quiet, 0),
F32::nan(Neg, Quiet, 0),
F32::nan(Pos, Quiet, 1),
F32::nan(Neg, Quiet, 1),
F32::nan(Pos, Quiet, 2),
F32::nan(Neg, Quiet, 2),
F32::nan(Pos, Quiet, all1_payload),
F32::nan(Neg, Quiet, all1_payload),
F32::nan(Pos, Signaling, all1_payload),
F32::nan(Neg, Signaling, all1_payload),
]),
|| F32::from(just1.mul_add(F32::nan(Neg, Quiet, 2).as_f32(), all1_snan)),
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(nan.powf(nan)),
);
check_all_outcomes(
HashSet::from_iter([1.0f32.into()]),
|| F32::from(1.0f32.powf(nan)), // special `pow` rule
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(nan.powi(1)),
);
// libm functions
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(nan.sinh()),
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(nan.atan2(nan)),
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(nan.ln_gamma().0),
);
} }
fn test_f64() { fn test_f64() {
@ -309,6 +369,62 @@ fn test_f64() {
]), ]),
|| F64::from(just1 % all1_snan), || F64::from(just1 % all1_snan),
); );
// Intrinsics
let nan = F64::nan(Neg, Quiet, 0).as_f64();
check_all_outcomes(
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(f64::min(nan, nan)),
);
check_all_outcomes(
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(nan.sin()),
);
check_all_outcomes(
HashSet::from_iter([
F64::nan(Pos, Quiet, 0),
F64::nan(Neg, Quiet, 0),
F64::nan(Pos, Quiet, 1),
F64::nan(Neg, Quiet, 1),
F64::nan(Pos, Quiet, 2),
F64::nan(Neg, Quiet, 2),
F64::nan(Pos, Quiet, all1_payload),
F64::nan(Neg, Quiet, all1_payload),
F64::nan(Pos, Signaling, all1_payload),
F64::nan(Neg, Signaling, all1_payload),
]),
|| F64::from(just1.mul_add(F64::nan(Neg, Quiet, 2).as_f64(), all1_snan)),
);
check_all_outcomes(
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(nan.powf(nan)),
);
check_all_outcomes(
HashSet::from_iter([1.0f64.into()]),
|| F64::from(1.0f64.powf(nan)), // special `pow` rule
);
check_all_outcomes(
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(nan.powi(1)),
);
// libm functions
check_all_outcomes(
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(nan.sinh()),
);
check_all_outcomes(
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(nan.atan2(nan)),
);
check_all_outcomes(
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(ldexp(nan, 1)),
);
check_all_outcomes(
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(nan.ln_gamma().0),
);
} }
fn test_casts() { fn test_casts() {
@ -397,6 +513,61 @@ fn test_casts() {
); );
} }
fn test_simd() {
use std::intrinsics::simd::*;
use std::simd::*;
extern "platform-intrinsic" {
fn simd_fsqrt<T>(x: T) -> T;
fn simd_ceil<T>(x: T) -> T;
fn simd_fma<T>(x: T, y: T, z: T) -> T;
}
let nan = F32::nan(Neg, Quiet, 0).as_f32();
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(unsafe { simd_div(f32x4::splat(0.0), f32x4::splat(0.0)) }[0]),
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(unsafe { simd_fmin(f32x4::splat(nan), f32x4::splat(nan)) }[0]),
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(unsafe { simd_fmax(f32x4::splat(nan), f32x4::splat(nan)) }[0]),
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| {
F32::from(
unsafe { simd_fma(f32x4::splat(nan), f32x4::splat(nan), f32x4::splat(nan)) }[0],
)
},
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(unsafe { simd_reduce_add_ordered::<_, f32>(f32x4::splat(nan), nan) }),
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(unsafe { simd_reduce_max::<_, f32>(f32x4::splat(nan)) }),
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(unsafe { simd_fsqrt(f32x4::splat(nan)) }[0]),
);
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(unsafe { simd_ceil(f32x4::splat(nan)) }[0]),
);
// Casts
check_all_outcomes(
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(unsafe { simd_cast::<f32x4, f64x4>(f32x4::splat(nan)) }[0]),
);
}
fn main() { fn main() {
// Check our constants against std, just to be sure. // Check our constants against std, just to be sure.
// We add 1 since our numbers are the number of bits stored // We add 1 since our numbers are the number of bits stored
@ -408,4 +579,5 @@ fn main() {
test_f32(); test_f32();
test_f64(); test_f64();
test_casts(); test_casts();
test_simd();
} }

View File

@ -11,7 +11,7 @@ pub fn main() {
{ {
let x = 0; let x = 0;
let ptr = &raw mut x; let ptr = &raw mut x;
Call(*ptr = myfun(), after_call, UnwindContinue()) Call(*ptr = myfun(), ReturnTo(after_call), UnwindContinue())
} }
after_call = { after_call = {

View File

@ -112,6 +112,30 @@ check!(reg_i32, i32, reg, "lgr");
// CHECK: #NO_APP // CHECK: #NO_APP
check!(reg_i64, i64, reg, "lgr"); check!(reg_i64, i64, reg, "lgr");
// CHECK-LABEL: reg_i8_addr:
// CHECK: #APP
// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i8_addr, i8, reg_addr, "lgr");
// CHECK-LABEL: reg_i16_addr:
// CHECK: #APP
// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i16_addr, i16, reg_addr, "lgr");
// CHECK-LABEL: reg_i32_addr:
// CHECK: #APP
// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i32_addr, i32, reg_addr, "lgr");
// CHECK-LABEL: reg_i64_addr:
// CHECK: #APP
// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}}
// CHECK: #NO_APP
check!(reg_i64_addr, i64, reg_addr, "lgr");
// CHECK-LABEL: reg_f32: // CHECK-LABEL: reg_f32:
// CHECK: #APP // CHECK: #APP
// CHECK: ler %f{{[0-9]+}}, %f{{[0-9]+}} // CHECK: ler %f{{[0-9]+}}, %f{{[0-9]+}}

View File

@ -13,7 +13,7 @@ fn ident<T>(t: T) -> T {
fn direct_call(x: i32) -> i32 { fn direct_call(x: i32) -> i32 {
mir!( mir!(
{ {
Call(RET = ident(x), retblock, UnwindContinue()) Call(RET = ident(x), ReturnTo(retblock), UnwindContinue())
} }
retblock = { retblock = {
@ -27,7 +27,7 @@ fn direct_call(x: i32) -> i32 {
fn indirect_call(x: i32, f: fn(i32) -> i32) -> i32 { fn indirect_call(x: i32, f: fn(i32) -> i32) -> i32 {
mir!( mir!(
{ {
Call(RET = f(x), retblock, UnwindContinue()) Call(RET = f(x), ReturnTo(retblock), UnwindContinue())
} }
retblock = { retblock = {
@ -49,7 +49,7 @@ impl<'a> Drop for WriteOnDrop<'a> {
fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) { fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
mir!( mir!(
{ {
Drop(a, retblock, UnwindContinue()) Drop(a, ReturnTo(retblock), UnwindContinue())
} }
retblock = { retblock = {
@ -64,7 +64,7 @@ fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
fn drop_second<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) { fn drop_second<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
mir!( mir!(
{ {
Drop(b, retblock, UnwindContinue()) Drop(b, ReturnTo(retblock), UnwindContinue())
} }
retblock = { retblock = {

View File

@ -11,7 +11,7 @@ use core::intrinsics::mir::*;
pub fn a() { pub fn a() {
mir!( mir!(
{ {
Call(RET = a(), bb1, UnwindUnreachable()) Call(RET = a(), ReturnTo(bb1), UnwindUnreachable())
} }
bb1 = { bb1 = {
Return() Return()
@ -26,7 +26,7 @@ pub fn a() {
pub fn b() { pub fn b() {
mir!( mir!(
{ {
Call(RET = b(), bb1, UnwindContinue()) Call(RET = b(), ReturnTo(bb1), UnwindContinue())
} }
bb1 = { bb1 = {
Return() Return()
@ -41,7 +41,7 @@ pub fn b() {
pub fn c() { pub fn c() {
mir!( mir!(
{ {
Call(RET = c(), bb1, UnwindTerminate(ReasonAbi)) Call(RET = c(), ReturnTo(bb1), UnwindTerminate(ReasonAbi))
} }
bb1 = { bb1 = {
Return() Return()
@ -56,7 +56,7 @@ pub fn c() {
pub fn d() { pub fn d() {
mir!( mir!(
{ {
Call(RET = d(), bb1, UnwindCleanup(bb2)) Call(RET = d(), ReturnTo(bb1), UnwindCleanup(bb2))
} }
bb1 = { bb1 = {
Return() Return()

View File

@ -22,11 +22,11 @@ fn f() -> bool {
let b = a; let b = a;
// We cannot propagate the place `a`. // We cannot propagate the place `a`.
let r2 = &b; let r2 = &b;
Call(RET = cmp_ref(r1, r2), next, UnwindContinue()) Call(RET = cmp_ref(r1, r2), ReturnTo(next), UnwindContinue())
} }
next = { next = {
// But we can propagate the value `a`. // But we can propagate the value `a`.
Call(RET = opaque(b), ret, UnwindContinue()) Call(RET = opaque(b), ReturnTo(ret), UnwindContinue())
} }
ret = { ret = {
Return() Return()

View File

@ -26,7 +26,7 @@ fn multiple_edges(t: bool) -> u8 {
match t { true => bbt, _ => ret } match t { true => bbt, _ => ret }
} }
bbt = { bbt = {
Call(x = dummy(13), ret, UnwindContinue()) Call(x = dummy(13), ReturnTo(ret), UnwindContinue())
} }
ret = { ret = {
// `x` is not assigned on the `bb0 -> ret` edge, // `x` is not assigned on the `bb0 -> ret` edge,

View File

@ -14,11 +14,11 @@ struct NotCopy(bool);
fn f(_1: NotCopy) { fn f(_1: NotCopy) {
mir!({ mir!({
let _2 = _1; let _2 = _1;
Call(RET = opaque(Move(_1)), bb1, UnwindContinue()) Call(RET = opaque(Move(_1)), ReturnTo(bb1), UnwindContinue())
} }
bb1 = { bb1 = {
let _3 = Move(_2); let _3 = Move(_2);
Call(RET = opaque(_3), bb2, UnwindContinue()) Call(RET = opaque(_3), ReturnTo(bb2), UnwindContinue())
} }
bb2 = { bb2 = {
Return() Return()

View File

@ -18,10 +18,10 @@ fn f(a: Foo) -> bool {
let b = a; let b = a;
// This is a move out of a copy, so must become a copy of `a.0`. // This is a move out of a copy, so must become a copy of `a.0`.
let c = Move(b.0); let c = Move(b.0);
Call(RET = opaque(Move(a)), bb1, UnwindContinue()) Call(RET = opaque(Move(a)), ReturnTo(bb1), UnwindContinue())
} }
bb1 = { bb1 = {
Call(RET = opaque(Move(c)), ret, UnwindContinue()) Call(RET = opaque(Move(c)), ReturnTo(ret), UnwindContinue())
} }
ret = { ret = {
Return() Return()

View File

@ -28,7 +28,7 @@ struct Packed {
fn move_packed(packed: Packed) { fn move_packed(packed: Packed) {
mir!( mir!(
{ {
Call(RET = use_both(0, packed.y), ret, UnwindContinue()) Call(RET = use_both(0, packed.y), ReturnTo(ret), UnwindContinue())
} }
ret = { ret = {
Return() Return()

View File

@ -20,7 +20,7 @@ fn cycle(mut x: i32, mut y: i32, mut z: i32) {
mir!( mir!(
let condition: bool; let condition: bool;
{ {
Call(condition = cond(), bb1, UnwindContinue()) Call(condition = cond(), ReturnTo(bb1), UnwindContinue())
} }
bb1 = { bb1 = {
match condition { true => bb2, _ => ret } match condition { true => bb2, _ => ret }
@ -30,7 +30,7 @@ fn cycle(mut x: i32, mut y: i32, mut z: i32) {
z = y; z = y;
y = x; y = x;
x = temp; x = temp;
Call(condition = cond(), bb1, UnwindContinue()) Call(condition = cond(), ReturnTo(bb1), UnwindContinue())
} }
ret = { ret = {
Return() Return()

View File

@ -529,31 +529,31 @@ fn duplicate_slice() -> (bool, bool) {
// CHECK: [[a:_.*]] = (const "a",); // CHECK: [[a:_.*]] = (const "a",);
// CHECK: [[au:_.*]] = ([[a]].0: &str) as u128 (Transmute); // CHECK: [[au:_.*]] = ([[a]].0: &str) as u128 (Transmute);
let a = ("a",); let a = ("a",);
Call(au = transmute::<_, u128>(a.0), bb1, UnwindContinue()) Call(au = transmute::<_, u128>(a.0), ReturnTo(bb1), UnwindContinue())
} }
bb1 = { bb1 = {
// CHECK: [[c:_.*]] = identity::<&str>(([[a]].0: &str)) // CHECK: [[c:_.*]] = identity::<&str>(([[a]].0: &str))
Call(c = identity(a.0), bb2, UnwindContinue()) Call(c = identity(a.0), ReturnTo(bb2), UnwindContinue())
} }
bb2 = { bb2 = {
// CHECK: [[cu:_.*]] = [[c]] as u128 (Transmute); // CHECK: [[cu:_.*]] = [[c]] as u128 (Transmute);
Call(cu = transmute::<_, u128>(c), bb3, UnwindContinue()) Call(cu = transmute::<_, u128>(c), ReturnTo(bb3), UnwindContinue())
} }
bb3 = { bb3 = {
// This slice is different from `a.0`. Hence `bu` is not `au`. // This slice is different from `a.0`. Hence `bu` is not `au`.
// CHECK: [[b:_.*]] = const "a"; // CHECK: [[b:_.*]] = const "a";
// CHECK: [[bu:_.*]] = [[b]] as u128 (Transmute); // CHECK: [[bu:_.*]] = [[b]] as u128 (Transmute);
let b = "a"; let b = "a";
Call(bu = transmute::<_, u128>(b), bb4, UnwindContinue()) Call(bu = transmute::<_, u128>(b), ReturnTo(bb4), UnwindContinue())
} }
bb4 = { bb4 = {
// This returns a copy of `b`, which is not `a`. // This returns a copy of `b`, which is not `a`.
// CHECK: [[d:_.*]] = identity::<&str>([[b]]) // CHECK: [[d:_.*]] = identity::<&str>([[b]])
Call(d = identity(b), bb5, UnwindContinue()) Call(d = identity(b), ReturnTo(bb5), UnwindContinue())
} }
bb5 = { bb5 = {
// CHECK: [[du:_.*]] = [[d]] as u128 (Transmute); // CHECK: [[du:_.*]] = [[d]] as u128 (Transmute);
Call(du = transmute::<_, u128>(d), bb6, UnwindContinue()) Call(du = transmute::<_, u128>(d), ReturnTo(bb6), UnwindContinue())
} }
bb6 = { bb6 = {
// `direct` must not fold to `true`, as `indirect` will not. // `direct` must not fold to `true`, as `indirect` will not.

View File

@ -25,7 +25,7 @@ pub fn f(a: *mut u8) {
Goto(bb1) Goto(bb1)
} }
bb1 = { bb1 = {
Call(*a = g(), bb1, UnwindUnreachable()) Call(*a = g(), ReturnTo(bb1), UnwindUnreachable())
} }
} }
} }

View File

@ -696,7 +696,7 @@ fn multiple_storage() {
// As there are multiple `StorageLive` statements for `x`, we cannot know if this `z`'s // As there are multiple `StorageLive` statements for `x`, we cannot know if this `z`'s
// pointer address is the address of `x`, so do nothing. // pointer address is the address of `x`, so do nothing.
let y = *z; let y = *z;
Call(RET = opaque(y), retblock, UnwindContinue()) Call(RET = opaque(y), ReturnTo(retblock), UnwindContinue())
} }
retblock = { retblock = {
@ -724,7 +724,7 @@ fn dominate_storage() {
} }
bb1 = { bb1 = {
let c = *r; let c = *r;
Call(RET = opaque(c), bb2, UnwindContinue()) Call(RET = opaque(c), ReturnTo(bb2), UnwindContinue())
} }
bb2 = { bb2 = {
StorageDead(x); StorageDead(x);
@ -760,18 +760,18 @@ fn maybe_dead(m: bool) {
bb1 = { bb1 = {
StorageDead(x); StorageDead(x);
StorageDead(y); StorageDead(y);
Call(RET = opaque(u), bb2, UnwindContinue()) Call(RET = opaque(u), ReturnTo(bb2), UnwindContinue())
} }
bb2 = { bb2 = {
// As `x` may be `StorageDead`, `a` may be dangling, so we do nothing. // As `x` may be `StorageDead`, `a` may be dangling, so we do nothing.
let z = *a; let z = *a;
Call(RET = opaque(z), bb3, UnwindContinue()) Call(RET = opaque(z), ReturnTo(bb3), UnwindContinue())
} }
bb3 = { bb3 = {
// As `y` may be `StorageDead`, `b` may be dangling, so we do nothing. // As `y` may be `StorageDead`, `b` may be dangling, so we do nothing.
// This implies that we also do not substitute `b` in `bb0`. // This implies that we also do not substitute `b` in `bb0`.
let t = *b; let t = *b;
Call(RET = opaque(t), retblock, UnwindContinue()) Call(RET = opaque(t), ReturnTo(retblock), UnwindContinue())
} }
retblock = { retblock = {
Return() Return()

View File

@ -1,4 +1,6 @@
// compile-flags:--test --error-format=short // compile-flags:--test --error-format=short
// check-stdout
// error-pattern:cannot find function `foo` in this scope
// normalize-stdout-test: "tests/rustdoc-ui/issues" -> "$$DIR" // normalize-stdout-test: "tests/rustdoc-ui/issues" -> "$$DIR"
// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
// failure-status: 101 // failure-status: 101
@ -6,7 +8,6 @@
/// ```rust /// ```rust
/// foo(); /// foo();
/// ``` /// ```
//~^^ ERROR cannot find function `foo` in this scope
fn foo() { fn foo() {
println!("Hello, world!"); println!("Hello, world!");
} }

View File

@ -1,16 +1,16 @@
running 1 test running 1 test
test $DIR/issue-81662-shortness.rs - foo (line 6) ... FAILED test $DIR/issue-81662-shortness.rs - foo (line 8) ... FAILED
failures: failures:
---- $DIR/issue-81662-shortness.rs - foo (line 6) stdout ---- ---- $DIR/issue-81662-shortness.rs - foo (line 8) stdout ----
$DIR/issue-81662-shortness.rs:7:1: error[E0425]: cannot find function `foo` in this scope $DIR/issue-81662-shortness.rs:9:1: error[E0425]: cannot find function `foo` in this scope
error: aborting due to 1 previous error error: aborting due to 1 previous error
Couldn't compile the test. Couldn't compile the test.
failures: failures:
$DIR/issue-81662-shortness.rs - foo (line 6) $DIR/issue-81662-shortness.rs - foo (line 8)
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME

View File

@ -1,5 +1,6 @@
// compile-flags: --error-format human-annotate-rs -Z unstable-options // compile-flags: --error-format human-annotate-rs -Z unstable-options
// error-pattern:cannot find type `Iter` in this scope
pub fn main() { pub fn main() {
let x: Iter; //~ ERROR cannot find type `Iter` in this scope let x: Iter;
} }

View File

@ -1,5 +1,5 @@
error[E0412]: cannot find type `Iter` in this scope error[E0412]: cannot find type `Iter` in this scope
--> $DIR/missing-type.rs:4:12 --> $DIR/missing-type.rs:5:12
| |
LL | let x: Iter; LL | let x: Iter;
| ^^^^ not found in this scope | ^^^^ not found in this scope

View File

@ -1,4 +1,5 @@
// aux-build:multispan.rs // aux-build:multispan.rs
// error-pattern:hello to you, too!
// compile-flags: --error-format human-annotate-rs -Z unstable-options // compile-flags: --error-format human-annotate-rs -Z unstable-options
#![feature(proc_macro_hygiene)] #![feature(proc_macro_hygiene)]
@ -12,17 +13,17 @@ fn main() {
hello!(); hello!();
// Exactly one 'hi'. // Exactly one 'hi'.
hello!(hi); //~ ERROR hello to you, too! hello!(hi);
// Now two, back to back. // Now two, back to back.
hello!(hi hi); //~ ERROR hello to you, too! hello!(hi hi);
// Now three, back to back. // Now three, back to back.
hello!(hi hi hi); //~ ERROR hello to you, too! hello!(hi hi hi);
// Now several, with spacing. // Now several, with spacing.
hello!(hi hey hi yo hi beep beep hi hi); //~ ERROR hello to you, too! hello!(hi hey hi yo hi beep beep hi hi);
hello!(hi there, hi how are you? hi... hi.); //~ ERROR hello to you, too! hello!(hi there, hi how are you? hi... hi.);
hello!(whoah. hi di hi di ho); //~ ERROR hello to you, too! hello!(whoah. hi di hi di ho);
hello!(hi good hi and good bye); //~ ERROR hello to you, too! hello!(hi good hi and good bye);
} }

View File

@ -1,41 +1,41 @@
error: hello to you, too! error: hello to you, too!
--> $DIR/multispan.rs:15:5 --> $DIR/multispan.rs:16:5
| |
LL | hello!(hi); LL | hello!(hi);
| ^^^^^^^^^^ | ^^^^^^^^^^
| |
error: hello to you, too! error: hello to you, too!
--> $DIR/multispan.rs:18:5 --> $DIR/multispan.rs:19:5
| |
LL | hello!(hi hi); LL | hello!(hi hi);
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
| |
error: hello to you, too! error: hello to you, too!
--> $DIR/multispan.rs:21:5 --> $DIR/multispan.rs:22:5
| |
LL | hello!(hi hi hi); LL | hello!(hi hi hi);
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
| |
error: hello to you, too! error: hello to you, too!
--> $DIR/multispan.rs:24:5 --> $DIR/multispan.rs:25:5
| |
LL | hello!(hi hey hi yo hi beep beep hi hi); LL | hello!(hi hey hi yo hi beep beep hi hi);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
error: hello to you, too! error: hello to you, too!
--> $DIR/multispan.rs:25:5 --> $DIR/multispan.rs:26:5
| |
LL | hello!(hi there, hi how are you? hi... hi.); LL | hello!(hi there, hi how are you? hi... hi.);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
error: hello to you, too! error: hello to you, too!
--> $DIR/multispan.rs:26:5 --> $DIR/multispan.rs:27:5
| |
LL | hello!(whoah. hi di hi di ho); LL | hello!(whoah. hi di hi di ho);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
error: hello to you, too! error: hello to you, too!
--> $DIR/multispan.rs:27:5 --> $DIR/multispan.rs:28:5
| |
LL | hello!(hi good hi and good bye); LL | hello!(hi good hi and good bye);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -1,9 +1,9 @@
// compile-flags: --diagnostic-width=20 --error-format=json // compile-flags: --diagnostic-width=20 --error-format=json
// error-pattern:expected `()`, found integer
// This test checks that `-Z output-width` effects the JSON error output by restricting it to an // This test checks that `-Z output-width` effects the JSON error output by restricting it to an
// arbitrarily low value so that the effect is visible. // arbitrarily low value so that the effect is visible.
fn main() { fn main() {
let _: () = 42; let _: () = 42;
//~^ ERROR arguments to this function are incorrect
} }

View File

@ -24,8 +24,8 @@ This error occurs when an expression was used in a place where the compiler
expected an expression of a different type. It can occur in several cases, the expected an expression of a different type. It can occur in several cases, the
most common being when calling a function and passing an argument which has a most common being when calling a function and passing an argument which has a
different type than the matching type in the function declaration. different type than the matching type in the function declaration.
"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":243,"byte_end":245,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":238,"byte_end":240,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types "},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":289,"byte_end":291,"line_start":8,"line_end":8,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":284,"byte_end":286,"line_start":8,"line_end":8,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types
--> $DIR/flag-json.rs:7:17 --> $DIR/flag-json.rs:8:17
| |
LL | ..._: () = 42; LL | ..._: () = 42;
| -- ^^ expected `()`, found integer | -- ^^ expected `()`, found integer

View File

@ -1,4 +1,5 @@
// compile-flags: --error-format json // compile-flags: --error-format json
// error-pattern:unnecessary parentheses
// run-rustfix // run-rustfix
// The output for humans should just highlight the whole span without showing // The output for humans should just highlight the whole span without showing
@ -13,7 +14,7 @@
fn main() { fn main() {
// We want to suggest the properly-balanced expression `1 / (2 + 3)`, not // We want to suggest the properly-balanced expression `1 / (2 + 3)`, not
// the malformed `1 / (2 + 3` // the malformed `1 / (2 + 3`
let _a = 1 / (2 + 3); //~ERROR unnecessary parentheses let _a = 1 / (2 + 3);
f(); f();
} }

View File

@ -1,4 +1,5 @@
// compile-flags: --error-format json // compile-flags: --error-format json
// error-pattern:unnecessary parentheses
// run-rustfix // run-rustfix
// The output for humans should just highlight the whole span without showing // The output for humans should just highlight the whole span without showing
@ -13,7 +14,7 @@
fn main() { fn main() {
// We want to suggest the properly-balanced expression `1 / (2 + 3)`, not // We want to suggest the properly-balanced expression `1 / (2 + 3)`, not
// the malformed `1 / (2 + 3` // the malformed `1 / (2 + 3`
let _a = (1 / (2 + 3)); //~ERROR unnecessary parentheses let _a = (1 / (2 + 3));
f(); f();
} }

View File

@ -1,11 +1,11 @@
{"$message_type":"diagnostic","message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":577,"byte_end":578,"line_start":16,"line_end":16,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3)); {"$message_type":"diagnostic","message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":618,"byte_end":619,"line_start":17,"line_end":17,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":630,"byte_end":631,"line_start":17,"line_end":17,"column_start":26,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":26,"highlight_end":27}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":436,"byte_end":449,"line_start":11,"line_end":11,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":618,"byte_end":619,"line_start":17,"line_end":17,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":630,"byte_end":631,"line_start":17,"line_end":17,"column_start":26,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":26,"highlight_end":27}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around assigned value
--> $DIR/unused_parens_json_suggestion.rs:16:14 --> $DIR/unused_parens_json_suggestion.rs:17:14
| |
LL | let _a = (1 / (2 + 3)); LL | let _a = (1 / (2 + 3));
| ^ ^ | ^ ^
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/unused_parens_json_suggestion.rs:10:9 --> $DIR/unused_parens_json_suggestion.rs:11:9
| |
LL | #![deny(unused_parens)] LL | #![deny(unused_parens)]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^

View File

@ -1,4 +1,5 @@
// compile-flags: --error-format json // compile-flags: --error-format json
// error-pattern:unnecessary parentheses
// run-rustfix // run-rustfix
// The output for humans should just highlight the whole span without showing // The output for humans should just highlight the whole span without showing
@ -14,7 +15,7 @@ fn main() {
let _b = false; let _b = false;
if _b { //~ ERROR unnecessary parentheses if _b {
println!("hello"); println!("hello");
} }
@ -25,29 +26,29 @@ fn main() {
fn f() -> bool { fn f() -> bool {
let c = false; let c = false;
if c { //~ ERROR unnecessary parentheses if c {
println!("next"); println!("next");
} }
if c { //~ ERROR unnecessary parentheses if c {
println!("prev"); println!("prev");
} }
while false && true { while false && true {
if c { //~ ERROR unnecessary parentheses if c {
println!("norm"); println!("norm");
} }
} }
while true && false { //~ ERROR unnecessary parentheses while true && false {
for _ in 0 .. 3 { //~ ERROR unnecessary parentheses for _ in 0 .. 3 {
println!("e~") println!("e~")
} }
} }
for _ in 0 .. 3 { //~ ERROR unnecessary parentheses for _ in 0 .. 3 {
while true && false { //~ ERROR unnecessary parentheses while true && false {
println!("e~") println!("e~")
} }
} }

View File

@ -1,4 +1,5 @@
// compile-flags: --error-format json // compile-flags: --error-format json
// error-pattern:unnecessary parentheses
// run-rustfix // run-rustfix
// The output for humans should just highlight the whole span without showing // The output for humans should just highlight the whole span without showing
@ -14,7 +15,7 @@ fn main() {
let _b = false; let _b = false;
if (_b) { //~ ERROR unnecessary parentheses if (_b) {
println!("hello"); println!("hello");
} }
@ -25,29 +26,29 @@ fn main() {
fn f() -> bool { fn f() -> bool {
let c = false; let c = false;
if(c) { //~ ERROR unnecessary parentheses if(c) {
println!("next"); println!("next");
} }
if (c){ //~ ERROR unnecessary parentheses if (c){
println!("prev"); println!("prev");
} }
while (false && true){ while (false && true){
if (c) { //~ ERROR unnecessary parentheses if (c) {
println!("norm"); println!("norm");
} }
} }
while(true && false) { //~ ERROR unnecessary parentheses while(true && false) {
for _ in (0 .. 3){ //~ ERROR unnecessary parentheses for _ in (0 .. 3){
println!("e~") println!("e~")
} }
} }
for _ in (0 .. 3) { //~ ERROR unnecessary parentheses for _ in (0 .. 3) {
while (true && false) { //~ ERROR unnecessary parentheses while (true && false) {
println!("e~") println!("e~")
} }
} }

View File

@ -1,11 +1,11 @@
{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":481,"byte_end":482,"line_start":17,"line_end":17,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) { {"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":522,"byte_end":523,"line_start":18,"line_end":18,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":525,"byte_end":526,"line_start":18,"line_end":18,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":436,"byte_end":449,"line_start":11,"line_end":11,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":522,"byte_end":523,"line_start":18,"line_end":18,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":525,"byte_end":526,"line_start":18,"line_end":18,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:17:8 --> $DIR/unused_parens_remove_json_suggestion.rs:18:8
| |
LL | if (_b) { LL | if (_b) {
| ^ ^ | ^ ^
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/unused_parens_remove_json_suggestion.rs:10:9 --> $DIR/unused_parens_remove_json_suggestion.rs:11:9
| |
LL | #![deny(unused_parens)] LL | #![deny(unused_parens)]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
@ -16,8 +16,8 @@ LL + if _b {
| |
"} "}
{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":612,"byte_end":613,"line_start":28,"line_end":28,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) { {"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":619,"byte_end":620,"line_start":29,"line_end":29,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":7,"highlight_end":8}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":621,"byte_end":622,"line_start":29,"line_end":29,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":619,"byte_end":620,"line_start":29,"line_end":29,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":7,"highlight_end":8}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":621,"byte_end":622,"line_start":29,"line_end":29,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:28:7 --> $DIR/unused_parens_remove_json_suggestion.rs:29:7
| |
LL | if(c) { LL | if(c) {
| ^ ^ | ^ ^
@ -29,8 +29,8 @@ LL + if c {
| |
"} "}
{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":692,"byte_end":693,"line_start":32,"line_end":32,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){ {"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":665,"byte_end":666,"line_start":33,"line_end":33,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":667,"byte_end":668,"line_start":33,"line_end":33,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" if (c){","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":665,"byte_end":666,"line_start":33,"line_end":33,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":667,"byte_end":668,"line_start":33,"line_end":33,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" if (c){","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:32:8 --> $DIR/unused_parens_remove_json_suggestion.rs:33:8
| |
LL | if (c){ LL | if (c){
| ^ ^ | ^ ^
@ -42,8 +42,8 @@ LL + if c {
| |
"} "}
{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":774,"byte_end":775,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":788,"byte_end":789,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":774,"byte_end":775,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":788,"byte_end":789,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition {"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":713,"byte_end":714,"line_start":37,"line_end":37,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":727,"byte_end":728,"line_start":37,"line_end":37,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":713,"byte_end":714,"line_start":37,"line_end":37,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":727,"byte_end":728,"line_start":37,"line_end":37,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:36:11 --> $DIR/unused_parens_remove_json_suggestion.rs:37:11
| |
LL | while (false && true){ LL | while (false && true){
| ^ ^ | ^ ^
@ -55,8 +55,8 @@ LL + while false && true {
| |
"} "}
{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":802,"byte_end":803,"line_start":37,"line_end":37,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) { {"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":741,"byte_end":742,"line_start":38,"line_end":38,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":12,"highlight_end":13}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":743,"byte_end":744,"line_start":38,"line_end":38,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":741,"byte_end":742,"line_start":38,"line_end":38,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":12,"highlight_end":13}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":743,"byte_end":744,"line_start":38,"line_end":38,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:37:12 --> $DIR/unused_parens_remove_json_suggestion.rs:38:12
| |
LL | if (c) { LL | if (c) {
| ^ ^ | ^ ^
@ -68,8 +68,8 @@ LL + if c {
| |
"} "}
{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":899,"byte_end":900,"line_start":43,"line_end":43,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) { {"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":804,"byte_end":805,"line_start":44,"line_end":44,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":818,"byte_end":819,"line_start":44,"line_end":44,"column_start":24,"column_end":25,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":24,"highlight_end":25}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":804,"byte_end":805,"line_start":44,"line_end":44,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":818,"byte_end":819,"line_start":44,"line_end":44,"column_start":24,"column_end":25,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":24,"highlight_end":25}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:43:10 --> $DIR/unused_parens_remove_json_suggestion.rs:44:10
| |
LL | while(true && false) { LL | while(true && false) {
| ^ ^ | ^ ^
@ -81,8 +81,8 @@ LL + while true && false {
| |
"} "}
{"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":968,"byte_end":969,"line_start":44,"line_end":44,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){ {"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":839,"byte_end":840,"line_start":45,"line_end":45,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":18,"highlight_end":19}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":846,"byte_end":847,"line_start":45,"line_end":45,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":839,"byte_end":840,"line_start":45,"line_end":45,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":18,"highlight_end":19}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":846,"byte_end":847,"line_start":45,"line_end":45,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `for` iterator expression
--> $DIR/unused_parens_remove_json_suggestion.rs:44:18 --> $DIR/unused_parens_remove_json_suggestion.rs:45:18
| |
LL | for _ in (0 .. 3){ LL | for _ in (0 .. 3){
| ^ ^ | ^ ^
@ -94,8 +94,8 @@ LL + for _ in 0 .. 3 {
| |
"} "}
{"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1069,"byte_end":1070,"line_start":49,"line_end":49,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) { {"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":906,"byte_end":907,"line_start":50,"line_end":50,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":913,"byte_end":914,"line_start":50,"line_end":50,"column_start":21,"column_end":22,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":21,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":906,"byte_end":907,"line_start":50,"line_end":50,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":913,"byte_end":914,"line_start":50,"line_end":50,"column_start":21,"column_end":22,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":21,"highlight_end":22}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `for` iterator expression
--> $DIR/unused_parens_remove_json_suggestion.rs:49:14 --> $DIR/unused_parens_remove_json_suggestion.rs:50:14
| |
LL | for _ in (0 .. 3) { LL | for _ in (0 .. 3) {
| ^ ^ | ^ ^
@ -107,8 +107,8 @@ LL + for _ in 0 .. 3 {
| |
"} "}
{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1128,"byte_end":1129,"line_start":50,"line_end":50,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) { {"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":931,"byte_end":932,"line_start":51,"line_end":51,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":15,"highlight_end":16}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":945,"byte_end":946,"line_start":51,"line_end":51,"column_start":29,"column_end":30,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":29,"highlight_end":30}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":931,"byte_end":932,"line_start":51,"line_end":51,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":15,"highlight_end":16}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":945,"byte_end":946,"line_start":51,"line_end":51,"column_start":29,"column_end":30,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":29,"highlight_end":30}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:50:15 --> $DIR/unused_parens_remove_json_suggestion.rs:51:15
| |
LL | while (true && false) { LL | while (true && false) {
| ^ ^ | ^ ^

View File

@ -13,7 +13,7 @@ pub fn f() -> u32 {
mir!( mir!(
let a: u32; let a: u32;
{ {
Call(a = g(), bb1, UnwindCleanup(bb2)) Call(a = g(), ReturnTo(bb1), UnwindCleanup(bb2))
} }
bb1 = { bb1 = {
RET = a; RET = a;

View File

@ -20,7 +20,7 @@ pub fn f(a: u32) -> u32 {
} }
} }
bb1 = { bb1 = {
Call(RET = f(1), bb2, UnwindTerminate(ReasonAbi)) Call(RET = f(1), ReturnTo(bb2), UnwindTerminate(ReasonAbi))
} }
bb2 = { bb2 = {

View File

@ -11,7 +11,7 @@ use core::intrinsics::mir::*;
pub fn main() { pub fn main() {
mir!( mir!(
{ {
Call(RET = main(), block, UnwindCleanup(block)) Call(RET = main(), ReturnTo(block), UnwindCleanup(block))
} }
block = { block = {
Return() Return()

Some files were not shown because too many files have changed in this diff Show More