From 60671268c897cecac8e93e667cfe48cdd848d58b Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Tue, 29 Oct 2019 23:32:51 +0100 Subject: [PATCH 01/14] Improved MaybeUninit::get_{ref,mut} documentation --- src/libcore/mem/maybe_uninit.rs | 159 ++++++++++++++++++++++++++++++-- 1 file changed, 151 insertions(+), 8 deletions(-) diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index 792ce9dfad419..e72a922a418f5 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -509,26 +509,169 @@ impl MaybeUninit { self.as_ptr().read() } - /// Gets a reference to the contained value. + /// Gets a shared reference to the contained value. + /// + /// This can be useful when we want to access a `MaybeUninit` that has been + /// initialized but don't have ownership of the `MaybeUninit` (preventing the use + /// of `.assume_init()`). /// /// # Safety /// - /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. + /// Calling this when the content is not yet fully initialized causes undefined + /// behavior: it is up to the caller to guarantee that the `MaybeUninit` really + /// is in an initialized state. + /// + /// # Examples + /// + /// ### Correct usage of this method: + /// + /// ```rust + /// use ::std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::>::uninit(); + /// // Initialize `x`: + /// unsafe { x.as_mut_ptr().write(vec![1, 2, 3]); } + /// /* The above line can also be done without unsafe: + /// x = MaybeUninit::new(vec![1, 2, 3]); // */ + /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to + /// // create a shared reference to it: + /// let x: &Vec = unsafe { + /// // # Safety + /// // + /// // - `x` has been initialized. + /// x.get_ref() + /// }; + /// assert_eq!(x, &vec![1, 2, 3]); + /// ``` + /// + /// ### *Incorrect* usages of this method: + /// + /// ```rust,no_run + /// use std::mem::MaybeUninit; + /// + /// let x = MaybeUninit::>::uninit(); + /// let x_vec: &Vec = unsafe { x.get_ref() }; + /// // We have created a reference to an uninitialized vector! This is undefined behavior. + /// ``` + /// + /// ```rust,no_run + /// use std::{cell::Cell, mem::MaybeUninit}; + /// + /// let b = MaybeUninit::>::uninit(); + /// // Initialize the `MaybeUninit` using `Cell::set`: + /// unsafe { + /// b.get_ref().set(true); + /// // ^^^^^^^^^^^ + /// // Reference to an uninitialized `Cell`: UB! + /// } + /// ``` #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] pub unsafe fn get_ref(&self) -> &T { &*self.value } - /// Gets a mutable reference to the contained value. + /// Gets a mutable (unique) reference to the contained value. + /// + /// This can be useful when we want to access a `MaybeUninit` that has been + /// initialized but don't have ownership of the `MaybeUninit` (preventing the use + /// of `.assume_init()`). /// /// # Safety /// - /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. + /// Calling this when the content is not yet fully initialized causes undefined + /// behavior: it is up to the caller to guarantee that the `MaybeUninit` really + /// is in an initialized state. For instance, `.get_mut()` cannot be used to + /// initialize a `MaybeUninit`. + /// + /// # Examples + /// + /// ### Correct usage of this method: + /// + /// ```rust + /// use ::std::mem::MaybeUninit; + /// + /// # unsafe extern "C" fn initialize_buffer (buf: *mut [u8; 2048]) { *buf = [0; 2048] } + /// # #[cfg(FALSE)] + /// extern "C" { + /// /// Initializes *all* the bytes of the input buffer. + /// fn initialize_buffer (buf: *mut [u8; 2048]); + /// } + /// + /// let mut buf = MaybeUninit::<[u8; 2048]>::uninit(); + /// // Initialize `buf`: + /// unsafe { initialize_buffer(buf.as_mut_ptr()); } + /// // Now we know that `buf` has been initialized; so we could `.assume_init()` it. + /// // However, using `.assume_init()` may trigger a `memcpy` of the 2048 bytes. + /// // To assert our buffer has been initialized without copying it, we upgrade + /// // the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`: + /// let buf: &mut [u8; 2048] = unsafe { + /// // # Safety + /// // + /// // - `buf` has been initialized. + /// buf.get_mut() + /// }; + /// // Now we can use `buf` as a normal slice: + /// buf.sort_unstable(); + /// assert!(buf.is_sorted()); + /// ``` + /// + /// ### *Incorrect* usages of this method: + /// + /// Do not use `.get_mut()` to initialize a value + /// + /// ```rust,no_run + /// use std::mem::MaybeUninit; + /// + /// let mut b = MaybeUninit::::uninit(); + /// unsafe { + /// *b.get_mut() = true; + /// // We have created a (mutable) reference to an uninitialized `bool`! + /// // This is undefined behavior. + /// } + /// ``` + /// + /// For instance, you cannot [`Read`] into an uninitialized buffer. + /// + /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html + /// + /// ```rust,no_run + /// use std::{io, mem::MaybeUninit}; + /// + /// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]> + /// { + /// let mut buffer = MaybeUninit::<[u8; 64]>::uninit(); + /// reader.read_exact(unsafe { buffer.get_mut() })?; + /// // ^^^^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. + /// Ok(buffer.assume_init()) + /// } + /// ``` + /// + /// Nor can you use direct field access to do field-by-field gradual initialization. + /// + /// ```rust,no_run + /// use std::mem::MaybeUninit; + /// + /// struct Foo { + /// a: u32, + /// b: u8, + /// } + /// + /// let foo: Foo = unsafe { + /// let foo = MaybeUninit::::uninit(); + /// ptr::write(&mut foo.get_mut().a as *mut u32, 1337); + /// // ^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. + /// ptr::write(&mut foo.get_mut().b as *mut u8, 42); + /// // ^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. + /// foo.assume_init() + /// }; + /// ``` // FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make // a final decision about the rules before stabilization. From 539de439ad6f32e9a9a8a593299072a106786890 Mon Sep 17 00:00:00 2001 From: Gui Andrade Date: Tue, 29 Oct 2019 21:12:05 -0700 Subject: [PATCH 02/14] Allow specifying key "llvm-abiname" in target specification This addresses #65024, as it allows RISC-V target specification files to set "llvm-abiname": "lp64d". In general, it is useful for the programmer to be able to set this codegen parameter, which other languages usually expose under a compiler argument like "-mabi=". --- src/librustc_codegen_llvm/back/write.rs | 3 ++- src/librustc_codegen_llvm/llvm/ffi.rs | 1 + src/librustc_target/spec/mod.rs | 8 +++++++- src/rustllvm/PassWrapper.cpp | 3 ++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 52f3a1cbb5c30..fa14ce7b03c8c 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -161,6 +161,7 @@ pub fn target_machine_factory(sess: &Session, optlvl: config::OptLevel, find_fea let cpu = SmallCStr::new(llvm_util::target_cpu(sess)); let features = features.join(","); let features = CString::new(features).unwrap(); + let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname); let is_pie_binary = !find_features && is_pie_binary(sess); let trap_unreachable = sess.target.target.options.trap_unreachable; let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; @@ -170,7 +171,7 @@ pub fn target_machine_factory(sess: &Session, optlvl: config::OptLevel, find_fea Arc::new(move || { let tm = unsafe { llvm::LLVMRustCreateTargetMachine( - triple.as_ptr(), cpu.as_ptr(), features.as_ptr(), + triple.as_ptr(), cpu.as_ptr(), features.as_ptr(), abi.as_ptr(), code_model, reloc_model, opt_level, diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index c69942ef3f2d5..85c181ba2f315 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -1684,6 +1684,7 @@ extern "C" { pub fn LLVMRustCreateTargetMachine(Triple: *const c_char, CPU: *const c_char, Features: *const c_char, + Abi: *const c_char, Model: CodeModel, Reloc: RelocMode, Level: CodeGenOptLevel, diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 6033d52c44112..e51772220b73f 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -793,7 +793,10 @@ pub struct TargetOptions { pub merge_functions: MergeFunctions, /// Use platform dependent mcount function - pub target_mcount: String + pub target_mcount: String, + + /// LLVM ABI name, corresponds to the '-mabi' parameter available in multilib C compilers + pub llvm_abiname: String, } impl Default for TargetOptions { @@ -880,6 +883,7 @@ impl Default for TargetOptions { override_export_symbols: None, merge_functions: MergeFunctions::Aliases, target_mcount: "mcount".to_string(), + llvm_abiname: "".to_string(), } } } @@ -1196,6 +1200,7 @@ impl Target { key!(override_export_symbols, opt_list); key!(merge_functions, MergeFunctions)?; key!(target_mcount); + key!(llvm_abiname); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -1414,6 +1419,7 @@ impl ToJson for Target { target_option_val!(override_export_symbols); target_option_val!(merge_functions); target_option_val!(target_mcount); + target_option_val!(llvm_abiname); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 0cda3465dc093..5b3900ab49611 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -343,7 +343,7 @@ extern "C" const char* LLVMRustGetHostCPUName(size_t *len) { extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( const char *TripleStr, const char *CPU, const char *Feature, - LLVMRustCodeModel RustCM, LLVMRustRelocMode RustReloc, + const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocMode RustReloc, LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat, bool PositionIndependentExecutable, bool FunctionSections, bool DataSections, @@ -374,6 +374,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.FunctionSections = FunctionSections; Options.MCOptions.AsmVerbose = AsmComments; Options.MCOptions.PreserveAsmComments = AsmComments; + Options.MCOptions.ABIName = ABIStr; if (TrapUnreachable) { // Tell LLVM to codegen `unreachable` into an explicit trap instruction. From 2ebf5e6e2f8ff1e5eea56e471303746ec626fb92 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Wed, 30 Oct 2019 11:45:43 +0100 Subject: [PATCH 03/14] Fix doctests --- src/libcore/mem/maybe_uninit.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index e72a922a418f5..60d20735db467 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -526,6 +526,7 @@ impl MaybeUninit { /// ### Correct usage of this method: /// /// ```rust + /// #![feature(maybe_uninit_ref)] /// use ::std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); @@ -547,6 +548,7 @@ impl MaybeUninit { /// ### *Incorrect* usages of this method: /// /// ```rust,no_run + /// #![feature(maybe_uninit_ref)] /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::>::uninit(); @@ -555,6 +557,7 @@ impl MaybeUninit { /// ``` /// /// ```rust,no_run + /// #![feature(maybe_uninit_ref)] /// use std::{cell::Cell, mem::MaybeUninit}; /// /// let b = MaybeUninit::>::uninit(); @@ -589,6 +592,7 @@ impl MaybeUninit { /// ### Correct usage of this method: /// /// ```rust + /// #![feature(maybe_uninit_ref)] /// use ::std::mem::MaybeUninit; /// /// # unsafe extern "C" fn initialize_buffer (buf: *mut [u8; 2048]) { *buf = [0; 2048] } @@ -599,6 +603,7 @@ impl MaybeUninit { /// } /// /// let mut buf = MaybeUninit::<[u8; 2048]>::uninit(); + /// /// // Initialize `buf`: /// unsafe { initialize_buffer(buf.as_mut_ptr()); } /// // Now we know that `buf` has been initialized; so we could `.assume_init()` it. @@ -611,16 +616,21 @@ impl MaybeUninit { /// // - `buf` has been initialized. /// buf.get_mut() /// }; + /// /// // Now we can use `buf` as a normal slice: /// buf.sort_unstable(); - /// assert!(buf.is_sorted()); + /// assert!( + /// buf.chunks(2).all(|chunk| chunk[0] <= chunk[1]), + /// "buffer is sorted", + /// ); /// ``` /// /// ### *Incorrect* usages of this method: /// - /// Do not use `.get_mut()` to initialize a value + /// You cannot use `.get_mut()` to initialize a value: /// /// ```rust,no_run + /// #![feature(maybe_uninit_ref)] /// use std::mem::MaybeUninit; /// /// let mut b = MaybeUninit::::uninit(); @@ -631,11 +641,12 @@ impl MaybeUninit { /// } /// ``` /// - /// For instance, you cannot [`Read`] into an uninitialized buffer. + /// For instance, you cannot [`Read`] into an uninitialized buffer: /// /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html /// /// ```rust,no_run + /// #![feature(maybe_uninit_ref)] /// use std::{io, mem::MaybeUninit}; /// /// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]> @@ -645,14 +656,15 @@ impl MaybeUninit { /// // ^^^^^^^^^^^^^^^^ /// // (mutable) reference to uninitialized memory! /// // This is undefined behavior. - /// Ok(buffer.assume_init()) + /// Ok(unsafe { buffer.assume_init() }) /// } /// ``` /// - /// Nor can you use direct field access to do field-by-field gradual initialization. + /// Nor can you use direct field access to do field-by-field gradual initialization: /// /// ```rust,no_run - /// use std::mem::MaybeUninit; + /// #![feature(maybe_uninit_ref)] + /// use std::{mem::MaybeUninit, ptr}; /// /// struct Foo { /// a: u32, @@ -660,7 +672,7 @@ impl MaybeUninit { /// } /// /// let foo: Foo = unsafe { - /// let foo = MaybeUninit::::uninit(); + /// let mut foo = MaybeUninit::::uninit(); /// ptr::write(&mut foo.get_mut().a as *mut u32, 1337); /// // ^^^^^^^^^^^^^ /// // (mutable) reference to uninitialized memory! From d9087cb388c00ec9a53f7a3049afb2ce00ce56fa Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Wed, 30 Oct 2019 14:52:56 +0100 Subject: [PATCH 04/14] Added a panic-on-uninhabited guard on get_ref and get_mut --- src/libcore/mem/maybe_uninit.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index 60d20735db467..d5893dd1d58f5 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -571,6 +571,7 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] pub unsafe fn get_ref(&self) -> &T { + intrinsics::panic_if_uninhabited::(); &*self.value } @@ -690,6 +691,7 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] pub unsafe fn get_mut(&mut self) -> &mut T { + intrinsics::panic_if_uninhabited::(); &mut *self.value } From 89719726ca7073ba6e767d767e9eba2f52ace3b3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 1 Nov 2019 14:48:58 +1100 Subject: [PATCH 05/14] De-querify `trivial_dropck_outlives`. It's sufficiently simple and fast that memoizing it is a slight pessimization. --- src/librustc/query/mod.rs | 6 ------ src/librustc/traits/query/dropck_outlives.rs | 16 ++++------------ src/librustc/traits/query/type_op/outlives.rs | 4 ++-- src/librustc/ty/mod.rs | 1 - src/librustc_traits/dropck_outlives.rs | 3 ++- 5 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index f628e19474876..2852c478c40a8 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -228,12 +228,6 @@ rustc_queries! { cycle_delay_bug } - query trivial_dropck_outlives(ty: Ty<'tcx>) -> bool { - anon - no_force - desc { "checking if `{:?}` has trivial dropck", ty } - } - query adt_dtorck_constraint( _: DefId ) -> Result, NoSolution> {} diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index e84c91daf293f..eaf5971e4592f 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -5,7 +5,6 @@ use std::iter::FromIterator; use syntax::source_map::Span; use crate::ty::subst::GenericArg; use crate::ty::{self, Ty, TyCtxt}; -use crate::ty::query::Providers; impl<'cx, 'tcx> At<'cx, 'tcx> { /// Given a type `ty` of some value being dropped, computes a set @@ -34,7 +33,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { // Quick check: there are a number of cases that we know do not require // any destructor. let tcx = self.infcx.tcx; - if tcx.trivial_dropck_outlives(ty) { + if trivial_dropck_outlives(tcx, ty) { return InferOk { value: vec![], obligations: vec![], @@ -208,15 +207,15 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::Error => true, // [T; N] and [T] have same properties as T. - ty::Array(ty, _) | ty::Slice(ty) => tcx.trivial_dropck_outlives(ty), + ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), // (T1..Tn) and closures have same properties as T1..Tn -- // check if *any* of those are trivial. - ty::Tuple(ref tys) => tys.iter().all(|t| tcx.trivial_dropck_outlives(t.expect_ty())), + ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), ty::Closure(def_id, ref substs) => substs .as_closure() .upvar_tys(def_id, tcx) - .all(|t| tcx.trivial_dropck_outlives(t)), + .all(|t| trivial_dropck_outlives(tcx, t)), ty::Adt(def, _) => { if Some(def.did) == tcx.lang_items().manually_drop() { @@ -244,10 +243,3 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), } } - -crate fn provide(p: &mut Providers<'_>) { - *p = Providers { - trivial_dropck_outlives, - ..*p - }; -} diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc/traits/query/type_op/outlives.rs index 86a32d68fc09e..81c3857cbf8d8 100644 --- a/src/librustc/traits/query/type_op/outlives.rs +++ b/src/librustc/traits/query/type_op/outlives.rs @@ -1,5 +1,5 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::dropck_outlives::DropckOutlivesResult; +use crate::traits::query::dropck_outlives::{DropckOutlivesResult, trivial_dropck_outlives}; use crate::traits::query::Fallible; use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; @@ -21,7 +21,7 @@ impl super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>, ) -> Option { - if tcx.trivial_dropck_outlives(key.value.dropped_ty) { + if trivial_dropck_outlives(tcx, key.value.dropped_ty) { Some(DropckOutlivesResult::default()) } else { None diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 60028f2488a33..1b1cc423fd457 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -3407,7 +3407,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { layout::provide(providers); util::provide(providers); constness::provide(providers); - crate::traits::query::dropck_outlives::provide(providers); *providers = ty::query::Providers { asyncness, associated_item, diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index c1316f415a559..d77ec3010f4b7 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -1,6 +1,7 @@ use rustc::hir::def_id::DefId; use rustc::infer::canonical::{Canonical, QueryResponse}; use rustc::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint}; +use rustc::traits::query::dropck_outlives::trivial_dropck_outlives; use rustc::traits::query::{CanonicalTyGoal, NoSolution}; use rustc::traits::{TraitEngine, Normalized, ObligationCause, TraitEngineExt}; use rustc::ty::query::Providers; @@ -172,7 +173,7 @@ fn dtorck_constraint_for_ty<'tcx>( return Ok(()); } - if tcx.trivial_dropck_outlives(ty) { + if trivial_dropck_outlives(tcx, ty) { return Ok(()); } From ecaa96418bfff378a229ebf79d14f9e3c312cf78 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 1 Nov 2019 23:24:07 +0300 Subject: [PATCH 06/14] `Span` cannot represent `span.hi < span.lo` So we can remove the corresponding checks from various code --- src/librustc/ich/hcx.rs | 5 ----- src/librustc/ty/query/on_disk_cache.rs | 5 ----- src/libsyntax/parse/lexer/mod.rs | 2 +- src/libsyntax/source_map.rs | 18 +++++------------- src/libsyntax_pos/lib.rs | 1 - 5 files changed, 6 insertions(+), 25 deletions(-) diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 957dab39414f0..a5b131520c243 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -309,11 +309,6 @@ impl<'a> HashStable> for Span { // position that belongs to it, as opposed to hashing the first // position past it. let span = self.data(); - - if span.hi < span.lo { - return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher); - } - let (file_lo, line_lo, col_lo) = match hcx.source_map() .byte_pos_to_line_and_col(span.lo) { Some(pos) => pos, diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 21a7cf00b283f..4dabea01c9e46 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -796,11 +796,6 @@ where } let span_data = span.data(); - - if span_data.hi < span_data.lo { - return TAG_INVALID_SPAN.encode(self); - } - let (file_lo, line_lo, col_lo) = match self.source_map .byte_pos_to_line_and_col(span_data.lo) { Some(pos) => pos, diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index e6dc9a4c13417..5ac60b017d3fc 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -68,7 +68,7 @@ impl<'a> StringReader<'a> { let end = sess.source_map().lookup_byte_offset(span.hi()); // Make the range zero-length if the span is invalid. - if span.lo() > span.hi() || begin.sf.start_pos != end.sf.start_pos { + if begin.sf.start_pos != end.sf.start_pos { span = span.shrink_to_lo(); } diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index d7760e0cf9ee4..d9f618602a40b 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -498,10 +498,6 @@ impl SourceMap { pub fn span_to_lines(&self, sp: Span) -> FileLinesResult { debug!("span_to_lines(sp={:?})", sp); - if sp.lo() > sp.hi() { - return Err(SpanLinesError::IllFormedSpan(sp)); - } - let lo = self.lookup_char_pos(sp.lo()); debug!("span_to_lines: lo={:?}", lo); let hi = self.lookup_char_pos(sp.hi()); @@ -549,10 +545,6 @@ impl SourceMap { fn span_to_source(&self, sp: Span, extract_source: F) -> Result where F: Fn(&str, usize, usize) -> Result { - if sp.lo() > sp.hi() { - return Err(SpanSnippetError::IllFormedSpan(sp)); - } - let local_begin = self.lookup_byte_offset(sp.lo()); let local_end = self.lookup_byte_offset(sp.hi()); @@ -762,14 +754,14 @@ impl SourceMap { /// Finds the width of a character, either before or after the provided span. fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 { - // Disregard malformed spans and assume a one-byte wide character. - if sp.lo() >= sp.hi() { - debug!("find_width_of_character_at_span: early return malformed span"); + let sp = sp.data(); + if sp.lo == sp.hi { + debug!("find_width_of_character_at_span: early return empty span"); return 1; } - let local_begin = self.lookup_byte_offset(sp.lo()); - let local_end = self.lookup_byte_offset(sp.hi()); + let local_begin = self.lookup_byte_offset(sp.lo); + let local_end = self.lookup_byte_offset(sp.hi); debug!("find_width_of_character_at_span: local_begin=`{:?}`, local_end=`{:?}`", local_begin, local_end); diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9034f8c1afd1b..dc29b189639ce 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -1512,7 +1512,6 @@ pub type FileLinesResult = Result; #[derive(Clone, PartialEq, Eq, Debug)] pub enum SpanLinesError { - IllFormedSpan(Span), DistinctSources(DistinctSources), } From 981e11e8ce17834713d354cc95755ea8a7905c6a Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 2 Nov 2019 11:23:16 -0700 Subject: [PATCH 07/14] Don't double-count `simd_shuffle` promotion candidates The proper attribute was added to `simd_shuffle*` in rust-lang/stdarch#825. This caused `promote_consts` to double-count its second argument when recording promotion candidates, which caused the promotion candidate compatibility check to fail. --- src/librustc_mir/transform/promote_consts.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 83f3aafc55cb1..f5e49e3283406 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -199,6 +199,8 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { bb: location.block, index: 2, }); + + return; // Don't double count `simd_shuffle` candidates } } From 9138d3bb80e2368062c58fad19cbd02ee65e7197 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2019 11:47:07 +0100 Subject: [PATCH 08/14] when Miri tests are not passing, do not add Miri component --- Cargo.lock | 1 + src/tools/build-manifest/Cargo.toml | 1 + src/tools/build-manifest/src/main.rs | 20 +++++++++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 46480aeb4476d..873f5da053787 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -208,6 +208,7 @@ name = "build-manifest" version = "0.1.0" dependencies = [ "serde", + "serde_json", "toml", ] diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index c364479d8db13..0bbbabd29989e 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" [dependencies] toml = "0.5" serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index fca57eec79fc6..afe170fe9032b 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -11,10 +11,11 @@ use serde::Serialize; use std::collections::BTreeMap; use std::env; -use std::fs; +use std::fs::{self, File}; use std::io::{self, Read, Write}; use std::path::{PathBuf, Path}; use std::process::{Command, Stdio}; +use std::collections::HashMap; static HOSTS: &[&str] = &[ "aarch64-unknown-linux-gnu", @@ -366,6 +367,7 @@ impl Builder { self.lldb_git_commit_hash = self.git_commit_hash("lldb", "x86_64-unknown-linux-gnu"); self.miri_git_commit_hash = self.git_commit_hash("miri", "x86_64-unknown-linux-gnu"); + self.check_toolstate(); self.digest_and_sign(); let manifest = self.build_manifest(); self.write_channel_files(&self.rust_release, &manifest); @@ -375,6 +377,22 @@ impl Builder { } } + /// If a tool does not pass its tests, don't ship it. + /// Right now, we do this only for Miri. + fn check_toolstate(&mut self) { + // Get the toolstate for this rust revision. + let toolstates = File::open(self.input.join("toolstates-linux.json")) + .expect("failed to open toolstates file"); + let toolstates: HashMap = serde_json::from_reader(&toolstates) + .expect("toolstates file contains malformed JSON"); + // Mark some tools as missing based on toolstate. + if toolstates.get("miri").map(|s| &*s as &str) != Some("test-pass") { + println!("Miri tests are not passing, removing component"); + self.miri_version = None; + self.miri_git_commit_hash = None; + } + } + /// Hash all files, compute their signatures, and collect the hashes in `self.digests`. fn digest_and_sign(&mut self) { for file in t!(self.input.read_dir()).map(|e| t!(e).path()) { From a675fd6f2e2fb623985fa87987a9c9ec22543279 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2019 11:55:05 +0100 Subject: [PATCH 09/14] don't fail manifest creation if the toolstate file is missing or mal-formed --- src/tools/build-manifest/src/main.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index afe170fe9032b..3822cccd63bd7 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -4,6 +4,7 @@ //! via `x.py dist hash-and-sign`; the cmdline arguments are set up //! by rustbuild (in `src/bootstrap/dist.rs`). +#![feature(try_blocks)] #![deny(warnings)] use toml; @@ -380,11 +381,14 @@ impl Builder { /// If a tool does not pass its tests, don't ship it. /// Right now, we do this only for Miri. fn check_toolstate(&mut self) { - // Get the toolstate for this rust revision. - let toolstates = File::open(self.input.join("toolstates-linux.json")) - .expect("failed to open toolstates file"); - let toolstates: HashMap = serde_json::from_reader(&toolstates) - .expect("toolstates file contains malformed JSON"); + let toolstates: Option> = try { + let toolstates = File::open(self.input.join("toolstates-linux.json")).ok()?; + serde_json::from_reader(&toolstates).ok()? + }; + let toolstates = toolstates.unwrap_or_else(|| { + println!("WARNING: `toolstates-linux.json` missing; assuming all tools failed"); + HashMap::default() // Use empty map if anything went wrong. + }); // Mark some tools as missing based on toolstate. if toolstates.get("miri").map(|s| &*s as &str) != Some("test-pass") { println!("Miri tests are not passing, removing component"); From 2cf7c29675583b8362a9116397b297f6fc872678 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 10:08:58 +0100 Subject: [PATCH 10/14] avoid using nightly features --- src/tools/build-manifest/src/main.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 3822cccd63bd7..373c72f9843c4 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -4,7 +4,6 @@ //! via `x.py dist hash-and-sign`; the cmdline arguments are set up //! by rustbuild (in `src/bootstrap/dist.rs`). -#![feature(try_blocks)] #![deny(warnings)] use toml; @@ -381,10 +380,9 @@ impl Builder { /// If a tool does not pass its tests, don't ship it. /// Right now, we do this only for Miri. fn check_toolstate(&mut self) { - let toolstates: Option> = try { - let toolstates = File::open(self.input.join("toolstates-linux.json")).ok()?; - serde_json::from_reader(&toolstates).ok()? - }; + let toolstates: Option> = + File::open(self.input.join("toolstates-linux.json")).ok() + .and_then(|f| serde_json::from_reader(&f).ok()); let toolstates = toolstates.unwrap_or_else(|| { println!("WARNING: `toolstates-linux.json` missing; assuming all tools failed"); HashMap::default() // Use empty map if anything went wrong. From 224378cc6addb0b3f3d40b4fbad5a7f031fbf57b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 10:10:40 +0100 Subject: [PATCH 11/14] more correct error msg --- src/tools/build-manifest/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 373c72f9843c4..d92924085e7c7 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -384,7 +384,8 @@ impl Builder { File::open(self.input.join("toolstates-linux.json")).ok() .and_then(|f| serde_json::from_reader(&f).ok()); let toolstates = toolstates.unwrap_or_else(|| { - println!("WARNING: `toolstates-linux.json` missing; assuming all tools failed"); + println!("WARNING: `toolstates-linux.json` missing/malformed; \ + assuming all tools failed"); HashMap::default() // Use empty map if anything went wrong. }); // Mark some tools as missing based on toolstate. From 1c78af7de24d9ff1f11531c5b5aa2f2ae44c4d8c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 Nov 2019 13:14:36 +0100 Subject: [PATCH 12/14] clean highlightSourceLines code --- src/librustdoc/html/static/main.js | 96 +++++++++++++++++------------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index de19ca3ed333a..53e16978ff12b 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -163,59 +163,71 @@ function getSearchElement() { var main = document.getElementById("main"); - function highlightSourceLines(ev) { - // If we're in mobile mode, we should add the sidebar in any case. + function onHashChange(ev) { + // If we're in mobile mode, we should hide the sidebar in any case. hideSidebar(); - var elem; - var search = getSearchElement(); - var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/); + var match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/); if (match) { - from = parseInt(match[1], 10); - to = from; - if (typeof match[2] !== "undefined") { - to = parseInt(match[2], 10); - } - if (to < from) { - var tmp = to; - to = from; - from = tmp; - } - elem = document.getElementById(from); - if (!elem) { - return; - } - if (ev === null) { - var x = document.getElementById(from); - if (x) { - x.scrollIntoView(); - } - } - onEachLazy(document.getElementsByClassName("line-numbers"), function(e) { - onEachLazy(e.getElementsByTagName("span"), function(i_e) { - removeClass(i_e, "line-highlighted"); - }); - }); - for (i = from; i <= to; ++i) { - elem = document.getElementById(i); - if (!elem) { - break; - } - addClass(elem, "line-highlighted"); - } - } else if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) { + return highlightSourceLines(match, ev); + } + var search = getSearchElement(); + if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) { addClass(search, "hidden"); removeClass(main, "hidden"); var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1); if (browserSupportsHistoryApi()) { history.replaceState(hash, "", "?search=#" + hash); } - elem = document.getElementById(hash); + var elem = document.getElementById(hash); if (elem) { elem.scrollIntoView(); } } } + function highlightSourceLines(match, ev) { + if (typeof match === "undefined") { + // If we're in mobile mode, we should hide the sidebar in any case. + hideSidebar(); + match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/); + } + if (!match) { + return; + } + var from = parseInt(match[1], 10); + var to = from; + if (typeof match[2] !== "undefined") { + to = parseInt(match[2], 10); + } + if (to < from) { + var tmp = to; + to = from; + from = tmp; + } + var elem = document.getElementById(from); + if (!elem) { + return; + } + if (!ev) { + var x = document.getElementById(from); + if (x) { + x.scrollIntoView(); + } + } + onEachLazy(document.getElementsByClassName("line-numbers"), function(e) { + onEachLazy(e.getElementsByTagName("span"), function(i_e) { + removeClass(i_e, "line-highlighted"); + }); + }); + for (var i = from; i <= to; ++i) { + elem = document.getElementById(i); + if (!elem) { + break; + } + addClass(elem, "line-highlighted"); + } + } + function expandSection(id) { var elem = document.getElementById(id); if (elem && isHidden(elem)) { @@ -234,8 +246,8 @@ function getSearchElement() { } } - highlightSourceLines(null); - window.onhashchange = highlightSourceLines; + highlightSourceLines(); + window.onhashchange = onHashChange; // Gets the human-readable string for the virtual-key code of the // given KeyboardEvent, ev. @@ -358,7 +370,7 @@ function getSearchElement() { var set_fragment = function(name) { if (browserSupportsHistoryApi()) { history.replaceState(null, null, "#" + name); - highlightSourceLines(null); + highlightSourceLines(); } else { location.replace("#" + name); } From 5083adeaad7af01b4cbc9244f75690950f7a0c92 Mon Sep 17 00:00:00 2001 From: Umesh Kalappa Date: Wed, 30 Oct 2019 01:38:32 -0700 Subject: [PATCH 13/14] Implemented the home_dir for VxWorks --- src/libstd/sys/vxworks/os.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/sys/vxworks/os.rs b/src/libstd/sys/vxworks/os.rs index f4798da1876cf..baa6c425d2e7f 100644 --- a/src/libstd/sys/vxworks/os.rs +++ b/src/libstd/sys/vxworks/os.rs @@ -287,7 +287,8 @@ pub fn temp_dir() -> PathBuf { } pub fn home_dir() -> Option { - None + crate::env::var_os("HOME").or_else(|| None + ).map(PathBuf::from) } pub fn exit(code: i32) -> ! { From 67f2200f4a1836742a605dca551408db56976b69 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Sun, 3 Nov 2019 21:53:21 +0100 Subject: [PATCH 14/14] Minor style improvements Co-Authored-By: Ralf Jung --- src/libcore/mem/maybe_uninit.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index d5893dd1d58f5..51ba260589f62 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -527,19 +527,15 @@ impl MaybeUninit { /// /// ```rust /// #![feature(maybe_uninit_ref)] - /// use ::std::mem::MaybeUninit; + /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); /// // Initialize `x`: /// unsafe { x.as_mut_ptr().write(vec![1, 2, 3]); } - /// /* The above line can also be done without unsafe: - /// x = MaybeUninit::new(vec![1, 2, 3]); // */ /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to /// // create a shared reference to it: /// let x: &Vec = unsafe { - /// // # Safety - /// // - /// // - `x` has been initialized. + /// // Safety: `x` has been initialized. /// x.get_ref() /// }; /// assert_eq!(x, &vec![1, 2, 3]); @@ -594,27 +590,25 @@ impl MaybeUninit { /// /// ```rust /// #![feature(maybe_uninit_ref)] - /// use ::std::mem::MaybeUninit; + /// use std::mem::MaybeUninit; /// - /// # unsafe extern "C" fn initialize_buffer (buf: *mut [u8; 2048]) { *buf = [0; 2048] } + /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 2048]) { *buf = [0; 2048] } /// # #[cfg(FALSE)] /// extern "C" { /// /// Initializes *all* the bytes of the input buffer. - /// fn initialize_buffer (buf: *mut [u8; 2048]); + /// fn initialize_buffer(buf: *mut [u8; 2048]); /// } /// /// let mut buf = MaybeUninit::<[u8; 2048]>::uninit(); /// /// // Initialize `buf`: /// unsafe { initialize_buffer(buf.as_mut_ptr()); } - /// // Now we know that `buf` has been initialized; so we could `.assume_init()` it. + /// // Now we know that `buf` has been initialized, so we could `.assume_init()` it. /// // However, using `.assume_init()` may trigger a `memcpy` of the 2048 bytes. /// // To assert our buffer has been initialized without copying it, we upgrade /// // the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`: /// let buf: &mut [u8; 2048] = unsafe { - /// // # Safety - /// // - /// // - `buf` has been initialized. + /// // Safety: `buf` has been initialized. /// buf.get_mut() /// }; ///