diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index c09b73b042013..c9c75aed7b0fb 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -244,6 +244,16 @@ pub fn std_cargo(builder: &Builder<'_>, target: Interned, stage: u32, ca if stage >= 1 { cargo.rustflag("-Cembed-bitcode=yes"); } + + // By default, rustc does not include unwind tables unless they are required + // for a particular target. They are not required by RISC-V targets, but + // compiling the standard library with them means that users can get + // backtraces without having to recompile the standard library themselves. + // + // This choice was discussed in https://github.com/rust-lang/rust/pull/69890 + if target.contains("riscv") { + cargo.rustflag("-Cforce-unwind-tables=yes"); + } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 1be05d5effff3..172b23a8d5a26 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -1399,3 +1399,70 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L } + +/// Create a `const` raw pointer to a place, without creating an intermediate reference. +/// +/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned +/// and points to initialized data. For cases where those requirements do not hold, +/// raw pointers should be used instead. However, `&expr as *const _` creates a reference +/// before casting it to a raw pointer, and that reference is subject to the same rules +/// as all other references. This macro can create a raw pointer *without* creating +/// a reference first. +/// +/// # Example +/// +/// ``` +/// #![feature(raw_ref_macros)] +/// use std::ptr; +/// +/// #[repr(packed)] +/// struct Packed { +/// f1: u8, +/// f2: u16, +/// } +/// +/// let packed = Packed { f1: 1, f2: 2 }; +/// // `&packed.f2` would create an unaligned reference, and thus be Undefined Behavior! +/// let raw_f2 = ptr::raw_const!(packed.f2); +/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2); +/// ``` +#[unstable(feature = "raw_ref_macros", issue = "73394")] +#[rustc_macro_transparency = "semitransparent"] +#[allow_internal_unstable(raw_ref_op)] +pub macro raw_const($e:expr) { + &raw const $e +} + +/// Create a `mut` raw pointer to a place, without creating an intermediate reference. +/// +/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned +/// and points to initialized data. For cases where those requirements do not hold, +/// raw pointers should be used instead. However, `&mut expr as *mut _` creates a reference +/// before casting it to a raw pointer, and that reference is subject to the same rules +/// as all other references. This macro can create a raw pointer *without* creating +/// a reference first. +/// +/// # Example +/// +/// ``` +/// #![feature(raw_ref_macros)] +/// use std::ptr; +/// +/// #[repr(packed)] +/// struct Packed { +/// f1: u8, +/// f2: u16, +/// } +/// +/// let mut packed = Packed { f1: 1, f2: 2 }; +/// // `&mut packed.f2` would create an unaligned reference, and thus be Undefined Behavior! +/// let raw_f2 = ptr::raw_mut!(packed.f2); +/// unsafe { raw_f2.write_unaligned(42); } +/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference. +/// ``` +#[unstable(feature = "raw_ref_macros", issue = "73394")] +#[rustc_macro_transparency = "semitransparent"] +#[allow_internal_unstable(raw_ref_op)] +pub macro raw_mut($e:expr) { + &raw mut $e +} diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 62406552e318f..ce186c4834d72 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -5,7 +5,7 @@ //! additional metadata), and [`ItemKind`] (which represents a concrete type and contains //! information specific to the type of the item). //! -//! Other module items that worth mentioning: +//! Other module items worth mentioning: //! - [`Ty`] and [`TyKind`]: A parsed Rust type. //! - [`Expr`] and [`ExprKind`]: A parsed Rust expression. //! - [`Pat`] and [`PatKind`]: A parsed Rust pattern. Patterns are often dual to expressions. diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index 849193151c335..53f32b7c800bd 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -216,8 +216,28 @@ impl<'a> Parser<'a> { } /// Parses the RHS of a local variable declaration (e.g., '= 14;'). - fn parse_initializer(&mut self, skip_eq: bool) -> PResult<'a, Option>> { - if self.eat(&token::Eq) || skip_eq { Ok(Some(self.parse_expr()?)) } else { Ok(None) } + fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option>> { + let eq_consumed = match self.token.kind { + token::BinOpEq(..) => { + // Recover `let x = 1` as `let x = 1` + self.struct_span_err( + self.token.span, + "can't reassign to an uninitialized variable", + ) + .span_suggestion_short( + self.token.span, + "initialize the variable", + "=".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + self.bump(); + true + } + _ => self.eat(&token::Eq), + }; + + Ok(if eq_consumed || eq_optional { Some(self.parse_expr()?) } else { None }) } /// Parses a block. No inner attributes are allowed. diff --git a/src/librustc_target/spec/riscv32i_unknown_none_elf.rs b/src/librustc_target/spec/riscv32i_unknown_none_elf.rs index aade1e708232e..d7b3e7e15307a 100644 --- a/src/librustc_target/spec/riscv32i_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv32i_unknown_none_elf.rs @@ -25,7 +25,6 @@ pub fn target() -> TargetResult { relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), - eliminate_frame_pointer: false, ..Default::default() }, }) diff --git a/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs b/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs index e2990eeb826f7..b93b6fcf8002a 100644 --- a/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs @@ -25,7 +25,6 @@ pub fn target() -> TargetResult { relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), - eliminate_frame_pointer: false, ..Default::default() }, }) diff --git a/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs b/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs index 55a4d58dfccca..a16e7e31c6619 100644 --- a/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs @@ -25,7 +25,6 @@ pub fn target() -> TargetResult { relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), - eliminate_frame_pointer: false, ..Default::default() }, }) diff --git a/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs b/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs index 7376a14e951f5..e5147a12ed320 100644 --- a/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs @@ -26,7 +26,6 @@ pub fn target() -> TargetResult { code_model: Some(CodeModel::Medium), emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), - eliminate_frame_pointer: false, ..Default::default() }, }) diff --git a/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs b/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs index a3b0eb5334f40..dc056b55b3868 100644 --- a/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs @@ -26,7 +26,6 @@ pub fn target() -> TargetResult { code_model: Some(CodeModel::Medium), emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), - eliminate_frame_pointer: false, ..Default::default() }, }) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 82d6cda986a9a..95d113166e001 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -165,9 +165,8 @@ fn opts() -> Vec { o.optmulti( "", "passes", - "list of passes to also run, you might want \ - to pass it multiple times; a value of `list` \ - will print available passes", + "list of passes to also run, you might want to pass it multiple times; a value of \ + `list` will print available passes", "PASSES", ) }), @@ -248,8 +247,8 @@ fn opts() -> Vec { "e", "extend-css", "To add some CSS rules with a given file to generate doc with your \ - own theme. However, your theme might break if the rustdoc's generated HTML \ - changes, so be careful!", + own theme. However, your theme might break if the rustdoc's generated HTML \ + changes, so be careful!", "PATH", ) }), @@ -262,7 +261,7 @@ fn opts() -> Vec { "", "playground-url", "URL to send code snippets to, may be reset by --markdown-playground-url \ - or `#![doc(html_playground_url=...)]`", + or `#![doc(html_playground_url=...)]`", "URL", ) }), @@ -276,8 +275,7 @@ fn opts() -> Vec { o.optflag( "", "sort-modules-by-appearance", - "sort modules by where they appear in the \ - program, rather than alphabetically", + "sort modules by where they appear in the program, rather than alphabetically", ) }), stable("theme", |o| { @@ -358,7 +356,7 @@ fn opts() -> Vec { "", "static-root-path", "Path string to force loading static files from in output pages. \ - If not set, uses combinations of '../' to reach the documentation root.", + If not set, uses combinations of '../' to reach the documentation root.", "PATH", ) }), diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d6493454db591..ef699ede2a140 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -298,6 +298,7 @@ #![feature(prelude_import)] #![feature(ptr_internals)] #![feature(raw)] +#![feature(raw_ref_macros)] #![feature(renamed_spin_loop)] #![feature(rustc_attrs)] #![feature(rustc_private)] diff --git a/src/test/codegen/issue-69101-bounds-check.rs b/src/test/codegen/issue-69101-bounds-check.rs new file mode 100644 index 0000000000000..cf062b6ad7588 --- /dev/null +++ b/src/test/codegen/issue-69101-bounds-check.rs @@ -0,0 +1,43 @@ +// no-system-llvm +// compile-flags: -O +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted in the loop when upfront slicing +// ensures that the slices are big enough. +// In particular, bounds checks were not always optimized out if the upfront +// check was for a greater len than the loop requires. +// (i.e. `already_sliced_no_bounds_check` was not always optimized even when +// `already_sliced_no_bounds_check_exact` was) +// CHECK-LABEL: @already_sliced_no_bounds_check +#[no_mangle] +pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_index_len_fail + // CHECK-NOT: panic_bounds_check + let _ = (&a[..2048], &b[..2048], &mut c[..2048]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} + +// CHECK-LABEL: @already_sliced_no_bounds_check_exact +#[no_mangle] +pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_index_len_fail + // CHECK-NOT: panic_bounds_check + let _ = (&a[..1024], &b[..1024], &mut c[..1024]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} + +// Make sure we're checking for the right thing: there can be a panic if the slice is too small. +// CHECK-LABEL: @already_sliced_bounds_check +#[no_mangle] +pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_index_len_fail + // CHECK: panic_bounds_check + let _ = (&a[..1023], &b[..2048], &mut c[..2048]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} diff --git a/src/test/ui/parser/let-binop.rs b/src/test/ui/parser/let-binop.rs new file mode 100644 index 0000000000000..7f58f5df2d412 --- /dev/null +++ b/src/test/ui/parser/let-binop.rs @@ -0,0 +1,8 @@ +fn main() { + let a: i8 *= 1; //~ ERROR can't reassign to an uninitialized variable + let _ = a; + let b += 1; //~ ERROR can't reassign to an uninitialized variable + let _ = b; + let c *= 1; //~ ERROR can't reassign to an uninitialized variable + let _ = c; +} diff --git a/src/test/ui/parser/let-binop.stderr b/src/test/ui/parser/let-binop.stderr new file mode 100644 index 0000000000000..71431499ac70b --- /dev/null +++ b/src/test/ui/parser/let-binop.stderr @@ -0,0 +1,20 @@ +error: can't reassign to an uninitialized variable + --> $DIR/let-binop.rs:2:15 + | +LL | let a: i8 *= 1; + | ^^ help: initialize the variable + +error: can't reassign to an uninitialized variable + --> $DIR/let-binop.rs:4:11 + | +LL | let b += 1; + | ^^ help: initialize the variable + +error: can't reassign to an uninitialized variable + --> $DIR/let-binop.rs:6:11 + | +LL | let c *= 1; + | ^^ help: initialize the variable + +error: aborting due to 3 previous errors +