diff --git a/RELEASES.md b/RELEASES.md index 4409b6ad7b1..18492213a5d 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,123 @@ +Version 1.50.0 (2021-02-11) +============================ + +Language +----------------------- +- [You can now use `const` values for `x` in `[x; N]` array expressions.][79270] + This has been technically possible since 1.38.0, as it was unintentionally stabilized. +- [Assignments to `ManuallyDrop<T>` union fields are now considered safe.][78068] + +Compiler +----------------------- +- [Added tier 3\* support for the `armv5te-unknown-linux-uclibceabi` target.][78142] +- [Added tier 3 support for the `aarch64-apple-ios-macabi` target.][77484] +- [The `x86_64-unknown-freebsd` is now built with the full toolset.][79484] + +\* Refer to Rust's [platform support page][forge-platform-support] for more +information on Rust's tiered platform support. + +Libraries +----------------------- + +- [`proc_macro::Punct` now implements `PartialEq<char>`.][78636] +- [`ops::{Index, IndexMut}` are now implemented for fixed sized arrays of any length.][74989] +- [On Unix platforms, the `std::fs::File` type now has a "niche" of `-1`.][74699] + This value cannot be a valid file descriptor, and now means `Option<File>` takes + up the same amount of space as `File`. + +Stabilized APIs +--------------- + +- [`bool::then`] +- [`btree_map::Entry::or_insert_with_key`] +- [`f32::clamp`] +- [`f64::clamp`] +- [`hash_map::Entry::or_insert_with_key`] +- [`Ord::clamp`] +- [`RefCell::take`] +- [`slice::fill`] +- [`UnsafeCell::get_mut`] + +The following previously stable methods are now `const`. + +- [`IpAddr::is_ipv4`] +- [`IpAddr::is_ipv6`] +- [`Layout::size`] +- [`Layout::align`] +- [`Layout::from_size_align`] +- `pow` for all integer types. +- `checked_pow` for all integer types. +- `saturating_pow` for all integer types. +- `wrapping_pow` for all integer types. +- `next_power_of_two` for all unsigned integer types. +- `checked_power_of_two` for all unsigned integer types. + +Cargo +----------------------- + +- [Added the `[build.rustc-workspace-wrapper]` option.][cargo/8976] + This option sets a wrapper to execute instead of `rustc`, for workspace members only. +- [`cargo:rerun-if-changed` will now, if provided a directory, scan the entire + contents of that directory for changes.][cargo/8973] +- [Added the `--workspace` flag to the `cargo update` command.][cargo/8725] + +Misc +---- + +- [The search results tab and the help button are focusable with keyboard in rustdoc.][79896] +- [Running tests will now print the total time taken to execute.][75752] + +Compatibility Notes +------------------- + +- [The `compare_and_swap` method on atomics has been deprecated.][79261] It's + recommended to use the `compare_exchange` and `compare_exchange_weak` methods instead. +- [Changes in how `TokenStream`s are checked have fixed some cases where you could write + unhygenic `macro_rules!` macros.][79472] +- [`#![test]` as an inner attribute is now considered unstable like other inner macro + attributes, and reports an error by default through the `soft_unstable` lint.][79003] +- [Overriding a `forbid` lint at the same level that it was set is now a hard error.][78864] +- [Dropped support for all cloudabi targets.][78439] +- [You can no longer intercept `panic!` calls by supplying your own macro.][78343] It's + recommended to use the `#[panic_handler]` attribute to provide your own implementation. +- [Semi-colons after item statements (e.g. `struct Foo {};`) now produce a warning.][78296] + +[74989]: https://github.com/rust-lang/rust/pull/74989 +[79261]: https://github.com/rust-lang/rust/pull/79261 +[79896]: https://github.com/rust-lang/rust/pull/79896 +[79484]: https://github.com/rust-lang/rust/pull/79484 +[79472]: https://github.com/rust-lang/rust/pull/79472 +[79270]: https://github.com/rust-lang/rust/pull/79270 +[79003]: https://github.com/rust-lang/rust/pull/79003 +[78864]: https://github.com/rust-lang/rust/pull/78864 +[78636]: https://github.com/rust-lang/rust/pull/78636 +[78439]: https://github.com/rust-lang/rust/pull/78439 +[78343]: https://github.com/rust-lang/rust/pull/78343 +[78296]: https://github.com/rust-lang/rust/pull/78296 +[78068]: https://github.com/rust-lang/rust/pull/78068 +[75752]: https://github.com/rust-lang/rust/pull/75752 +[74699]: https://github.com/rust-lang/rust/pull/74699 +[78142]: https://github.com/rust-lang/rust/pull/78142 +[77484]: https://github.com/rust-lang/rust/pull/77484 +[cargo/8976]: https://github.com/rust-lang/cargo/pull/8976 +[cargo/8973]: https://github.com/rust-lang/cargo/pull/8973 +[cargo/8725]: https://github.com/rust-lang/cargo/pull/8725 +[`IpAddr::is_ipv4`]: https://doc.rust-lang.org/stable/std/net/enum.IpAddr.html#method.is_ipv4 +[`IpAddr::is_ipv6`]: https://doc.rust-lang.org/stable/std/net/enum.IpAddr.html#method.is_ipv6 +[`Layout::align`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.align +[`Layout::from_size_align`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.from_size_align +[`Layout::size`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.size +[`Ord::clamp`]: https://doc.rust-lang.org/stable/std/cmp/trait.Ord.html#method.clamp +[`RefCell::take`]: https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html#method.take +[`UnsafeCell::get_mut`]: https://doc.rust-lang.org/stable/std/cell/struct.UnsafeCell.html#method.get_mut +[`bool::then`]: https://doc.rust-lang.org/stable/std/primitive.bool.html#method.then +[`btree_map::Entry::or_insert_with_key`]: https://doc.rust-lang.org/stable/std/collections/btree_map/enum.Entry.html#method.or_insert_with_key +[`f32::clamp`]: https://doc.rust-lang.org/stable/std/primitive.f32.html#method.clamp +[`f64::clamp`]: https://doc.rust-lang.org/stable/std/primitive.f64.html#method.clamp +[`hash_map::Entry::or_insert_with_key`]: https://doc.rust-lang.org/stable/std/collections/hash_map/enum.Entry.html#method.or_insert_with_key +[`slice::fill`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.fill + + Version 1.49.0 (2020-12-31) ============================ diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index b205ea9cf6c..ca7d3d1d81b 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -13,7 +13,7 @@ use crate::{CachedModuleCodegen, CrateInfo, MemFlags, ModuleCodegen, ModuleKind} use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::print_time_passes_entry; -use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator}; +use rustc_data_structures::sync::{par_iter, ParallelIterator}; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; @@ -554,8 +554,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>( codegen_units }; - let total_codegen_time = Lock::new(Duration::new(0, 0)); - // The non-parallel compiler can only translate codegen units to LLVM IR // on a single thread, leading to a staircase effect where the N LLVM // threads have to wait on the single codegen threads to generate work @@ -578,23 +576,25 @@ pub fn codegen_crate<B: ExtraBackendMethods>( .collect(); // Compile the found CGUs in parallel. - par_iter(cgus) + let start_time = Instant::now(); + + let pre_compiled_cgus = par_iter(cgus) .map(|(i, _)| { - let start_time = Instant::now(); let module = backend.compile_codegen_unit(tcx, codegen_units[i].name()); - let mut time = total_codegen_time.lock(); - *time += start_time.elapsed(); (i, module) }) - .collect() + .collect(); + + (pre_compiled_cgus, start_time.elapsed()) }) } else { - FxHashMap::default() + (FxHashMap::default(), Duration::new(0, 0)) } }; let mut cgu_reuse = Vec::new(); let mut pre_compiled_cgus: Option<FxHashMap<usize, _>> = None; + let mut total_codegen_time = Duration::new(0, 0); for (i, cgu) in codegen_units.iter().enumerate() { ongoing_codegen.wait_for_signal_to_codegen_item(); @@ -607,7 +607,9 @@ pub fn codegen_crate<B: ExtraBackendMethods>( codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect() }); // Pre compile some CGUs - pre_compiled_cgus = Some(pre_compile_cgus(&cgu_reuse)); + let (compiled_cgus, codegen_time) = pre_compile_cgus(&cgu_reuse); + pre_compiled_cgus = Some(compiled_cgus); + total_codegen_time += codegen_time; } let cgu_reuse = cgu_reuse[i]; @@ -621,8 +623,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( } else { let start_time = Instant::now(); let module = backend.compile_codegen_unit(tcx, cgu.name()); - let mut time = total_codegen_time.lock(); - *time += start_time.elapsed(); + total_codegen_time += start_time.elapsed(); module }; submit_codegened_module_to_llvm( @@ -663,11 +664,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( // Since the main thread is sometimes blocked during codegen, we keep track // -Ztime-passes output manually. - print_time_passes_entry( - tcx.sess.time_passes(), - "codegen_to_LLVM_IR", - total_codegen_time.into_inner(), - ); + print_time_passes_entry(tcx.sess.time_passes(), "codegen_to_LLVM_IR", total_codegen_time); ongoing_codegen.check_for_errors(tcx.sess); diff --git a/compiler/rustc_error_codes/src/error_codes/E0207.md b/compiler/rustc_error_codes/src/error_codes/E0207.md index cb4f5d5157d..8a7923ac93f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0207.md +++ b/compiler/rustc_error_codes/src/error_codes/E0207.md @@ -14,7 +14,7 @@ impl<T: Default> Foo { } ``` -Any type parameter parameter of an `impl` must meet at least one of +Any type parameter of an `impl` must meet at least one of the following criteria: - it appears in the _implementing type_ of the impl, e.g. `impl<T> Foo<T>` diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 1305b5c9f00..26b35e87ac4 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -566,6 +566,17 @@ impl<'hir> Map<'hir> { ) } + /// Checks if the node is left-hand side of an assignment. + pub fn is_lhs(&self, id: HirId) -> bool { + match self.find(self.get_parent_node(id)) { + Some(Node::Expr(expr)) => match expr.kind { + ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id, + _ => false, + }, + _ => false, + } + } + /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context. /// Used exclusively for diagnostics, to avoid suggestion function calls. pub fn is_inside_const_context(&self, hir_id: HirId) -> bool { diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 423d1270ac8..0b7492631c4 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -515,7 +515,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' Ok(true) } ty::Float(_) | ty::Int(_) | ty::Uint(_) => { - let value = self.ecx.read_scalar(value)?; + let value = try_validation!( + self.ecx.read_scalar(value), + self.path, + err_unsup!(ReadPointerAsBytes) => { "read of part of a pointer" }, + ); // NOTE: Keep this in sync with the array optimization for int/float // types below! if self.ctfe_mode.is_some() { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 1830aaa4471..0724a9290e9 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -286,21 +286,32 @@ fn suggest_restriction( ); } else { // Trivial case: `T` needs an extra bound: `T: Bound`. - let (sp, suggestion) = match super_traits { - None => predicate_constraint( + let (sp, suggestion) = match ( + generics + .params + .iter() + .filter( + |p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: Some(_), ..}), + ) + .next(), + super_traits, + ) { + (_, None) => predicate_constraint( generics, trait_ref.without_const().to_predicate(tcx).to_string(), ), - Some((ident, bounds)) => match bounds { - [.., bound] => ( - bound.span().shrink_to_hi(), - format!(" + {}", trait_ref.print_only_trait_path().to_string()), - ), - [] => ( - ident.span.shrink_to_hi(), - format!(": {}", trait_ref.print_only_trait_path().to_string()), - ), - }, + (None, Some((ident, []))) => ( + ident.span.shrink_to_hi(), + format!(": {}", trait_ref.print_only_trait_path().to_string()), + ), + (_, Some((_, [.., bounds]))) => ( + bounds.span().shrink_to_hi(), + format!(" + {}", trait_ref.print_only_trait_path().to_string()), + ), + (Some(_), Some((_, []))) => ( + generics.span.shrink_to_hi(), + format!(": {}", trait_ref.print_only_trait_path().to_string()), + ), }; err.span_suggestion_verbose( @@ -888,8 +899,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // no return, suggest removal of semicolon on last statement. // Once that is added, close #54771. if let Some(ref stmt) = blk.stmts.last() { - let sp = self.tcx.sess.source_map().end_point(stmt.span); - err.span_label(sp, "consider removing this semicolon"); + if let hir::StmtKind::Semi(_) = stmt.kind { + let sp = self.tcx.sess.source_map().end_point(stmt.span); + err.span_label(sp, "consider removing this semicolon"); + } } } } diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index c22f0017446..3c9c683f4b0 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -816,6 +816,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |err: &mut DiagnosticBuilder<'_>, found_to_exp_is_fallible: bool, exp_to_found_is_fallible: bool| { + let exp_is_lhs = + expected_ty_expr.map(|e| self.tcx.hir().is_lhs(e.hir_id)).unwrap_or(false); + + if exp_is_lhs { + return; + } + let always_fallible = found_to_exp_is_fallible && (exp_to_found_is_fallible || expected_ty_expr.is_none()); let msg = if literal_is_ty_suffixed(expr) { diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index f92aed8ce15..ba5a4442f56 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -777,7 +777,7 @@ fn test_range_backwards_4() { #[test] #[should_panic] -fn test_range_backwards_5() { +fn test_range_finding_ill_order_in_map() { let mut map = BTreeMap::new(); map.insert(Cyclic3::B, ()); // Lacking static_assert, call `range` conditionally, to emphasise that @@ -788,6 +788,47 @@ fn test_range_backwards_5() { } } +#[test] +#[should_panic] +fn test_range_finding_ill_order_in_range_ord() { + // Has proper order the first time asked, then flips around. + struct EvilTwin(i32); + + impl PartialOrd for EvilTwin { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } + } + + static COMPARES: AtomicUsize = AtomicUsize::new(0); + impl Ord for EvilTwin { + fn cmp(&self, other: &Self) -> Ordering { + let ord = self.0.cmp(&other.0); + if COMPARES.fetch_add(1, SeqCst) > 0 { ord.reverse() } else { ord } + } + } + + impl PartialEq for EvilTwin { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } + } + + impl Eq for EvilTwin {} + + #[derive(PartialEq, Eq, PartialOrd, Ord)] + struct CompositeKey(i32, EvilTwin); + + impl Borrow<EvilTwin> for CompositeKey { + fn borrow(&self) -> &EvilTwin { + &self.1 + } + } + + let map = (0..12).map(|i| (CompositeKey(i, EvilTwin(i)), ())).collect::<BTreeMap<_, _>>(); + map.range(EvilTwin(5)..=EvilTwin(7)); +} + #[test] fn test_range_1000() { // Miri is too slow @@ -1222,6 +1263,51 @@ fn test_borrow() { map.insert(Rc::new(0), 1); assert_eq!(map[&0], 1); } + + #[allow(dead_code)] + fn get<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) { + v.get(t); + } + + #[allow(dead_code)] + fn get_mut<T: Ord>(v: &mut BTreeMap<Box<T>, ()>, t: &T) { + v.get_mut(t); + } + + #[allow(dead_code)] + fn get_key_value<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) { + v.get_key_value(t); + } + + #[allow(dead_code)] + fn contains_key<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) { + v.contains_key(t); + } + + #[allow(dead_code)] + fn range<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: T) { + v.range(t..); + } + + #[allow(dead_code)] + fn range_mut<T: Ord>(v: &mut BTreeMap<Box<T>, ()>, t: T) { + v.range_mut(t..); + } + + #[allow(dead_code)] + fn remove<T: Ord>(v: &mut BTreeMap<Box<T>, ()>, t: &T) { + v.remove(t); + } + + #[allow(dead_code)] + fn remove_entry<T: Ord>(v: &mut BTreeMap<Box<T>, ()>, t: &T) { + v.remove_entry(t); + } + + #[allow(dead_code)] + fn split_off<T: Ord>(v: &mut BTreeMap<Box<T>, ()>, t: &T) { + v.split_off(t); + } } #[test] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index fda0553f94c..05bcd90d3ca 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -839,7 +839,7 @@ impl<T> MaybeUninit<T> { // * MaybeUnint does not drop, so there are no double-frees // And thus the conversion is safe unsafe { - intrinsics::assert_inhabited::<T>(); + intrinsics::assert_inhabited::<[T; N]>(); (&array as *const _ as *const [T; N]).read() } } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 0051c9eede0..14e4e4da3b9 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -428,6 +428,40 @@ impl<T> Option<T> { } } + /// Returns the contained [`Some`] value, consuming the `self` value, + /// without checking that the value is not [`None`]. + /// + /// # Safety + /// + /// Calling this method on [`None`] is *[undefined behavior]*. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(option_result_unwrap_unchecked)] + /// let x = Some("air"); + /// assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); + /// ``` + /// + /// ```no_run + /// #![feature(option_result_unwrap_unchecked)] + /// let x: Option<&str> = None; + /// assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); // Undefined behavior! + /// ``` + #[inline] + #[track_caller] + #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")] + pub unsafe fn unwrap_unchecked(self) -> T { + debug_assert!(self.is_some()); + match self { + Some(val) => val, + // SAFETY: the safety contract must be upheld by the caller. + None => unsafe { hint::unreachable_unchecked() }, + } + } + ///////////////////////////////////////////////////////////////////////// // Transforming contained values ///////////////////////////////////////////////////////////////////////// diff --git a/library/core/src/result.rs b/library/core/src/result.rs index d6d17625729..a43ba5882ed 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -229,7 +229,7 @@ use crate::iter::{self, FromIterator, FusedIterator, TrustedLen}; use crate::ops::{self, Deref, DerefMut}; -use crate::{convert, fmt}; +use crate::{convert, fmt, hint}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// @@ -821,6 +821,74 @@ impl<T, E> Result<T, E> { Err(e) => op(e), } } + + /// Returns the contained [`Ok`] value, consuming the `self` value, + /// without checking that the value is not an [`Err`]. + /// + /// # Safety + /// + /// Calling this method on an [`Err`] is *[undefined behavior]*. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(option_result_unwrap_unchecked)] + /// let x: Result<u32, &str> = Ok(2); + /// assert_eq!(unsafe { x.unwrap_unchecked() }, 2); + /// ``` + /// + /// ```no_run + /// #![feature(option_result_unwrap_unchecked)] + /// let x: Result<u32, &str> = Err("emergency failure"); + /// unsafe { x.unwrap_unchecked(); } // Undefined behavior! + /// ``` + #[inline] + #[track_caller] + #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")] + pub unsafe fn unwrap_unchecked(self) -> T { + debug_assert!(self.is_ok()); + match self { + Ok(t) => t, + // SAFETY: the safety contract must be upheld by the caller. + Err(_) => unsafe { hint::unreachable_unchecked() }, + } + } + + /// Returns the contained [`Err`] value, consuming the `self` value, + /// without checking that the value is not an [`Ok`]. + /// + /// # Safety + /// + /// Calling this method on an [`Ok`] is *[undefined behavior]*. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ```no_run + /// #![feature(option_result_unwrap_unchecked)] + /// let x: Result<u32, &str> = Ok(2); + /// unsafe { x.unwrap_err_unchecked() }; // Undefined behavior! + /// ``` + /// + /// ``` + /// #![feature(option_result_unwrap_unchecked)] + /// let x: Result<u32, &str> = Err("emergency failure"); + /// assert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure"); + /// ``` + #[inline] + #[track_caller] + #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")] + pub unsafe fn unwrap_err_unchecked(self) -> E { + debug_assert!(self.is_err()); + match self { + // SAFETY: the safety contract must be upheld by the caller. + Ok(_) => unsafe { hint::unreachable_unchecked() }, + Err(e) => e, + } + } } impl<T: Copy, E> Result<&T, E> { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 98f5982fbb2..b7a406c30e9 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -64,6 +64,7 @@ #![feature(const_raw_ptr_deref)] #![feature(never_type)] #![feature(unwrap_infallible)] +#![feature(option_result_unwrap_unchecked)] #![feature(option_unwrap_none)] #![feature(peekable_next_if)] #![feature(peekable_peek_mut)] diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 2279a16429f..38084f401bc 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -152,6 +152,8 @@ fn uninit_array_assume_init() { let array = unsafe { MaybeUninit::array_assume_init(array) }; assert_eq!(array, [3, 1, 4, 1, 5]); + + let [] = unsafe { MaybeUninit::<!>::array_assume_init([]) }; } #[test] diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index 5388b475624..9470451278c 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -160,6 +160,13 @@ fn test_unwrap_or_else() { assert_eq!(x.unwrap_or_else(|| 2), 2); } +#[test] +fn test_unwrap_unchecked() { + assert_eq!(unsafe { Some(1).unwrap_unchecked() }, 1); + let s = unsafe { Some("hello".to_string()).unwrap_unchecked() }; + assert_eq!(s, "hello"); +} + #[test] fn test_iter() { let val = 5; diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 81660870e95..7aa44c6e593 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -119,6 +119,18 @@ pub fn test_unwrap_or_else_panic() { let _: isize = bad_err.unwrap_or_else(handler); } +#[test] +fn test_unwrap_unchecked() { + let ok: Result<isize, &'static str> = Ok(100); + assert_eq!(unsafe { ok.unwrap_unchecked() }, 100); +} + +#[test] +fn test_unwrap_err_unchecked() { + let ok_err: Result<isize, &'static str> = Err("Err"); + assert_eq!(unsafe { ok_err.unwrap_err_unchecked() }, "Err"); +} + #[test] pub fn test_expect_ok() { let ok: Result<isize, &'static str> = Ok(100); diff --git a/src/doc/book b/src/doc/book index ac57a0ddd23..e724bd82658 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ac57a0ddd23d173b26731ccf939f3ba729753275 +Subproject commit e724bd826580ff95df48a8533af7dec1080693d4 diff --git a/src/doc/nomicon b/src/doc/nomicon index a8584998eac..bbf06ad39d1 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit a8584998eacdea7106a1dfafcbf6c1c06fcdf925 +Subproject commit bbf06ad39d1f45654047e9596b750cc6e6d1b693 diff --git a/src/doc/reference b/src/doc/reference index 50af691f838..f02b09eb6e8 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 50af691f838937c300b47812d0507c6d88c14f97 +Subproject commit f02b09eb6e8af340ad1256a54adb7aae2ff3163e diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 03e23af01f0..f633769acef 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 03e23af01f0b4f83a3a513da280e1ca92587f2ec +Subproject commit f633769acef68574427a6fae6c06f13bc2199573 diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md index ca6db26da31..41736e5ee3a 100644 --- a/src/doc/rustdoc/src/how-to-write-documentation.md +++ b/src/doc/rustdoc/src/how-to-write-documentation.md @@ -153,11 +153,73 @@ and finally provides a code example. ## Markdown -`rustdoc` uses the [commonmark markdown specification]. You might be +`rustdoc` uses the [CommonMark markdown specification]. You might be interested into taking a look at their website to see what's possible to do. - [commonmark quick reference] - [current spec] +In addition to the standard CommonMark syntax, `rustdoc` supports several +extensions: + +### Strikethrough + +Text may be rendered with a horizontal line through the center by wrapping the +text with two tilde characters on each side: + +```text +An example of ~~strikethrough text~~. +``` + +This example will render as: + +> An example of ~~strikethrough text~~. + +This follows the [GitHub Strikethrough extension][strikethrough]. + +### Footnotes + +A footnote generates a small numbered link in the text which when clicked +takes the reader to the footnote text at the bottom of the item. The footnote +label is written similarly to a link reference with a caret at the front. The +footnote text is written like a link reference definition, with the text +following the label. Example: + +```text +This is an example of a footnote[^note]. + +[^note]: This text is the contents of the footnote, which will be rendered + towards the bottom. +``` + +This example will render as: + +> This is an example of a footnote[^note]. +> +> [^note]: This text is the contents of the footnote, which will be rendered +> towards the bottom. + +The footnotes are automatically numbered based on the order the footnotes are +written. + +### Tables + +Tables can be written using pipes and dashes to draw the rows and columns of +the table. These will be translated to HTML table matching the shape. Example: + +```text +| Header1 | Header2 | +|---------|---------| +| abc | def | +``` + +This example will render similarly to this: + +> | Header1 | Header2 | +> |---------|---------| +> | abc | def | + +See the specification for the [GitHub Tables extension][tables] for more +details on the exact syntax supported. [`backtrace`]: https://docs.rs/backtrace/0.3.50/backtrace/ [commonmark markdown specification]: https://commonmark.org/ @@ -170,3 +232,5 @@ interested into taking a look at their website to see what's possible to do. [standard library]: https://doc.rust-lang.org/stable/std/index.html [current spec]: https://spec.commonmark.org/current/ [`std::env`]: https://doc.rust-lang.org/stable/std/env/index.html#functions +[strikethrough]: https://github.github.com/gfm/#strikethrough-extension- +[tables]: https://github.github.com/gfm/#tables-extension- diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 74bd348e9ac..53f08318524 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1,9 +1,6 @@ -// From rust: -/* global ALIASES */ - // Local js definitions: -/* global addClass, getCurrentValue, hasClass */ -/* global onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */ +/* global addClass, getSettingValue, hasClass */ +/* global onEach, onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */ /* global hideThemeButtonState, showThemeButtonState */ if (!String.prototype.startsWith) { @@ -2214,7 +2211,7 @@ function defocusSearchBar() { } } - function toggleAllDocs(pageId, fromAutoCollapse) { + function toggleAllDocs(fromAutoCollapse) { var innerToggle = document.getElementById(toggleAllDocsId); if (!innerToggle) { return; @@ -2257,14 +2254,14 @@ function defocusSearchBar() { } if (!parent || !superParent || superParent.id !== "main" || hasClass(parent, "impl") === false) { - collapseDocs(e, "hide", pageId); + collapseDocs(e, "hide"); } }); } } } - function collapseDocs(toggle, mode, pageId) { + function collapseDocs(toggle, mode) { if (!toggle || !toggle.parentNode) { return; } @@ -2384,27 +2381,27 @@ function defocusSearchBar() { } } - function collapser(pageId, e, collapse) { + function collapser(e, collapse) { // inherent impl ids are like "impl" or impl-<number>'. // they will never be hidden by default. var n = e.parentElement; if (n.id.match(/^impl(?:-\d+)?$/) === null) { // Automatically minimize all non-inherent impls if (collapse || hasClass(n, "impl")) { - collapseDocs(e, "hide", pageId); + collapseDocs(e, "hide"); } } } - function autoCollapse(pageId, collapse) { + function autoCollapse(collapse) { if (collapse) { - toggleAllDocs(pageId, true); + toggleAllDocs(true); } else if (getSettingValue("auto-hide-trait-implementations") !== "false") { var impl_list = document.getElementById("trait-implementations-list"); if (impl_list !== null) { onEachLazy(impl_list.getElementsByClassName("collapse-toggle"), function(e) { - collapser(pageId, e, collapse); + collapser(e, collapse); }); } @@ -2412,7 +2409,7 @@ function defocusSearchBar() { if (blanket_list !== null) { onEachLazy(blanket_list.getElementsByClassName("collapse-toggle"), function(e) { - collapser(pageId, e, collapse); + collapser(e, collapse); }); } } @@ -2475,7 +2472,6 @@ function defocusSearchBar() { var toggle = createSimpleToggle(false); var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true"; var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false"; - var pageId = getPageId(); var func = function(e) { var next = e.nextElementSibling; @@ -2489,7 +2485,7 @@ function defocusSearchBar() { var newToggle = toggle.cloneNode(true); insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]); if (hideMethodDocs === true && hasClass(e, "method") === true) { - collapseDocs(newToggle, "hide", pageId); + collapseDocs(newToggle, "hide"); } } }; @@ -2513,7 +2509,7 @@ function defocusSearchBar() { // In case the option "auto-collapse implementors" is not set to false, we collapse // all implementors. if (hideImplementors === true && e.parentNode.id === "implementors-list") { - collapseDocs(newToggle, "hide", pageId); + collapseDocs(newToggle, "hide"); } } }; @@ -2527,7 +2523,7 @@ function defocusSearchBar() { if (e.id.match(/^impl(?:-\d+)?$/) === null) { // Automatically minimize all non-inherent impls if (hasClass(e, "impl") === true) { - collapseDocs(newToggle, "hide", pageId); + collapseDocs(newToggle, "hide"); } } }; @@ -2562,14 +2558,12 @@ function defocusSearchBar() { } onEachLazy(document.getElementsByClassName("impl-items"), function(e) { onEachLazy(e.getElementsByClassName("associatedconstant"), func); - var hiddenElems = e.getElementsByClassName("hidden"); - var needToggle = false; - - var needToggle = onEachLazy(e.getElementsByClassName("hidden"), function(hiddenElem) { - if (hasClass(hiddenElem, "content") === false && - hasClass(hiddenElem, "docblock") === false) { - return true; - } + // We transform the DOM iterator into a vec of DOM elements to prevent performance + // issues on webkit browsers. + var hiddenElems = Array.prototype.slice.call(e.getElementsByClassName("hidden")); + var needToggle = hiddenElems.some(function(hiddenElem) { + return hasClass(hiddenElem, "content") === false && + hasClass(hiddenElem, "docblock") === false; }); if (needToggle === true) { var inner_toggle = newToggle.cloneNode(true); @@ -2672,10 +2666,10 @@ function defocusSearchBar() { onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper); onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper); + + autoCollapse(getSettingValue("collapse") === "true"); + var pageId = getPageId(); - - autoCollapse(pageId, getSettingValue("collapse") === "true"); - if (pageId !== null) { expandSection(pageId); } diff --git a/src/librustdoc/html/static/settings.js b/src/librustdoc/html/static/settings.js index bc14420232c..4f10e14e855 100644 --- a/src/librustdoc/html/static/settings.js +++ b/src/librustdoc/html/static/settings.js @@ -1,5 +1,5 @@ // Local js definitions: -/* global getCurrentValue, getVirtualKey, updateLocalStorage, updateSystemTheme */ +/* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, updateSystemTheme */ (function () { function changeSetting(settingName, value) { diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index a9cc0ffdf79..42b54e4cc1e 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -113,6 +113,8 @@ function createSidebarToggle() { return sidebarToggle; } +// This function is called from "source-files.js", generated in `html/render/mod.rs`. +// eslint-disable-next-line no-unused-vars function createSourceSidebar() { if (window.rootPath.endsWith("/") === false) { window.rootPath += "/"; diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index d081781f14b..9c5ac1625af 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -1,5 +1,5 @@ // From rust: -/* global resourcesSuffix, getSettingValue */ +/* global resourcesSuffix */ var darkThemes = ["dark", "ayu"]; var currentTheme = document.getElementById("themeStyle"); @@ -35,10 +35,12 @@ var localStoredTheme = getSettingValue("theme"); var savedHref = []; +// eslint-disable-next-line no-unused-vars function hasClass(elem, className) { return elem && elem.classList && elem.classList.contains(className); } +// eslint-disable-next-line no-unused-vars function addClass(elem, className) { if (!elem || !elem.classList) { return; @@ -46,6 +48,7 @@ function addClass(elem, className) { elem.classList.add(className); } +// eslint-disable-next-line no-unused-vars function removeClass(elem, className) { if (!elem || !elem.classList) { return; @@ -81,6 +84,7 @@ function onEachLazy(lazyArray, func, reversed) { reversed); } +// eslint-disable-next-line no-unused-vars function hasOwnProperty(obj, property) { return Object.prototype.hasOwnProperty.call(obj, property); } @@ -148,6 +152,8 @@ function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { } } +// This function is called from "theme.js", generated in `html/render/mod.rs`. +// eslint-disable-next-line no-unused-vars function useSystemTheme(value) { if (value === undefined) { value = true; @@ -172,7 +178,7 @@ var updateSystemTheme = (function() { switchTheme( currentTheme, mainTheme, - JSON.parse(cssTheme) || light, + JSON.parse(cssTheme) || "light", true ); }; diff --git a/src/test/ui/bound-suggestions.fixed b/src/test/ui/bound-suggestions.fixed index a3fe67a9595..be61b7dda25 100644 --- a/src/test/ui/bound-suggestions.fixed +++ b/src/test/ui/bound-suggestions.fixed @@ -40,4 +40,29 @@ fn test_many_bounds_where<X>(x: X) where X: Sized, X: Sized, X: Debug { //~^ ERROR doesn't implement } -pub fn main() { } +trait Foo<T>: Sized { + const SIZE: usize = core::mem::size_of::<Self>(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Bar: std::fmt::Display + Sized { + const SIZE: usize = core::mem::size_of::<Self>(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Baz: Sized where Self: std::fmt::Display { + const SIZE: usize = core::mem::size_of::<Self>(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Qux<T>: Sized where Self: std::fmt::Display { + const SIZE: usize = core::mem::size_of::<Self>(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Bat<T>: std::fmt::Display + Sized { + const SIZE: usize = core::mem::size_of::<Self>(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +fn main() { } diff --git a/src/test/ui/bound-suggestions.rs b/src/test/ui/bound-suggestions.rs index de6133d7f59..86f708d42f5 100644 --- a/src/test/ui/bound-suggestions.rs +++ b/src/test/ui/bound-suggestions.rs @@ -40,4 +40,29 @@ fn test_many_bounds_where<X>(x: X) where X: Sized, X: Sized { //~^ ERROR doesn't implement } -pub fn main() { } +trait Foo<T> { + const SIZE: usize = core::mem::size_of::<Self>(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Bar: std::fmt::Display { + const SIZE: usize = core::mem::size_of::<Self>(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Baz where Self: std::fmt::Display { + const SIZE: usize = core::mem::size_of::<Self>(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Qux<T> where Self: std::fmt::Display { + const SIZE: usize = core::mem::size_of::<Self>(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +trait Bat<T>: std::fmt::Display { + const SIZE: usize = core::mem::size_of::<Self>(); + //~^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +fn main() { } diff --git a/src/test/ui/bound-suggestions.stderr b/src/test/ui/bound-suggestions.stderr index 010f95d8ad6..12e67e90265 100644 --- a/src/test/ui/bound-suggestions.stderr +++ b/src/test/ui/bound-suggestions.stderr @@ -76,6 +76,86 @@ help: consider further restricting type parameter `X` LL | fn test_many_bounds_where<X>(x: X) where X: Sized, X: Sized, X: Debug { | ^^^^^^^^^^ -error: aborting due to 6 previous errors +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/bound-suggestions.rs:44:46 + | +LL | const SIZE: usize = core::mem::size_of::<Self>(); + | ^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL + | +LL | pub const fn size_of<T>() -> usize { + | - required by this bound in `std::mem::size_of` + | +help: consider further restricting `Self` + | +LL | trait Foo<T>: Sized { + | ^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/bound-suggestions.rs:49:46 + | +LL | const SIZE: usize = core::mem::size_of::<Self>(); + | ^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL + | +LL | pub const fn size_of<T>() -> usize { + | - required by this bound in `std::mem::size_of` + | +help: consider further restricting `Self` + | +LL | trait Bar: std::fmt::Display + Sized { + | ^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/bound-suggestions.rs:54:46 + | +LL | const SIZE: usize = core::mem::size_of::<Self>(); + | ^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL + | +LL | pub const fn size_of<T>() -> usize { + | - required by this bound in `std::mem::size_of` + | +help: consider further restricting `Self` + | +LL | trait Baz: Sized where Self: std::fmt::Display { + | ^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/bound-suggestions.rs:59:46 + | +LL | const SIZE: usize = core::mem::size_of::<Self>(); + | ^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL + | +LL | pub const fn size_of<T>() -> usize { + | - required by this bound in `std::mem::size_of` + | +help: consider further restricting `Self` + | +LL | trait Qux<T>: Sized where Self: std::fmt::Display { + | ^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/bound-suggestions.rs:64:46 + | +LL | const SIZE: usize = core::mem::size_of::<Self>(); + | ^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL + | +LL | pub const fn size_of<T>() -> usize { + | - required by this bound in `std::mem::size_of` + | +help: consider further restricting `Self` + | +LL | trait Bat<T>: std::fmt::Display + Sized { + | ^^^^^^^ + +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/issue-79690.rs b/src/test/ui/consts/issue-79690.rs new file mode 100644 index 00000000000..a2e7b97b318 --- /dev/null +++ b/src/test/ui/consts/issue-79690.rs @@ -0,0 +1,32 @@ +// ignore-32bit +// This test gives a different error on 32-bit architectures. + +union Transmute<T: Copy, U: Copy> { + t: T, + u: U, +} +trait Bar { + fn bar(&self) -> u32; +} +struct Foo { + foo: u32, + bar: bool, +} +impl Bar for Foo { + fn bar(&self) -> u32 { + self.foo + } +} +#[derive(Copy, Clone)] +struct Fat<'a>(&'a Foo, &'static VTable); +struct VTable { + size: Foo, +} +const FOO: &dyn Bar = &Foo { + foo: 128, + bar: false, +}; +const G: Fat = unsafe { Transmute { t: FOO }.u }; +//~^ ERROR it is undefined behavior to use this value + +fn main() {} diff --git a/src/test/ui/consts/issue-79690.stderr b/src/test/ui/consts/issue-79690.stderr new file mode 100644 index 00000000000..918dd4c20f9 --- /dev/null +++ b/src/test/ui/consts/issue-79690.stderr @@ -0,0 +1,11 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/issue-79690.rs:29:1 + | +LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered read of part of a pointer at .1.<deref>.size.foo + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/suggestions/issue-81098.rs b/src/test/ui/suggestions/issue-81098.rs new file mode 100644 index 00000000000..a601b5866f4 --- /dev/null +++ b/src/test/ui/suggestions/issue-81098.rs @@ -0,0 +1,13 @@ +// Don't suggest removing a semicolon if the last statement isn't an expression with semicolon +// (#81098) +fn wat() -> impl core::fmt::Display { //~ ERROR: `()` doesn't implement `std::fmt::Display` + fn why() {} +} + +// Do it if the last statement is an expression with semicolon +// (#54771) +fn ok() -> impl core::fmt::Display { //~ ERROR: `()` doesn't implement `std::fmt::Display` + 1; +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-81098.stderr b/src/test/ui/suggestions/issue-81098.stderr new file mode 100644 index 00000000000..2a72159e577 --- /dev/null +++ b/src/test/ui/suggestions/issue-81098.stderr @@ -0,0 +1,23 @@ +error[E0277]: `()` doesn't implement `std::fmt::Display` + --> $DIR/issue-81098.rs:3:13 + | +LL | fn wat() -> impl core::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `()` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + +error[E0277]: `()` doesn't implement `std::fmt::Display` + --> $DIR/issue-81098.rs:9:12 + | +LL | fn ok() -> impl core::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter +LL | 1; + | - consider removing this semicolon + | + = help: the trait `std::fmt::Display` is not implemented for `()` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/typeck/issue-81293.rs b/src/test/ui/typeck/issue-81293.rs new file mode 100644 index 00000000000..076b8c944b8 --- /dev/null +++ b/src/test/ui/typeck/issue-81293.rs @@ -0,0 +1,9 @@ +fn main() { + let a: u16; + let b: u16 = 42; + let c: usize = 5; + + a = c + b * 5; //~ ERROR: mismatched types [E0308] + //~| ERROR: mismatched types [E0308] + //~| ERROR: cannot add `u16` to `usize` [E0277] +} diff --git a/src/test/ui/typeck/issue-81293.stderr b/src/test/ui/typeck/issue-81293.stderr new file mode 100644 index 00000000000..1e6ff3b5f9e --- /dev/null +++ b/src/test/ui/typeck/issue-81293.stderr @@ -0,0 +1,24 @@ +error[E0308]: mismatched types + --> $DIR/issue-81293.rs:6:13 + | +LL | a = c + b * 5; + | ^^^^^ expected `usize`, found `u16` + +error[E0308]: mismatched types + --> $DIR/issue-81293.rs:6:9 + | +LL | a = c + b * 5; + | ^^^^^^^^^ expected `u16`, found `usize` + +error[E0277]: cannot add `u16` to `usize` + --> $DIR/issue-81293.rs:6:11 + | +LL | a = c + b * 5; + | ^ no implementation for `usize + u16` + | + = help: the trait `Add<u16>` is not implemented for `usize` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs deleted file mode 100644 index e06616a59f3..00000000000 --- a/src/tools/tidy/src/cargo.rs +++ /dev/null @@ -1,90 +0,0 @@ -//! Tidy check to ensure that `[dependencies]` and `extern crate` are in sync. -//! -//! This tidy check ensures that all crates listed in the `[dependencies]` -//! section of a `Cargo.toml` are present in the corresponding `lib.rs` as -//! `extern crate` declarations. This should help us keep the DAG correctly -//! structured through various refactorings to prune out unnecessary edges. - -use std::fs; -use std::path::Path; - -pub fn check(path: &Path, bad: &mut bool) { - if !super::filter_dirs(path) { - return; - } - for entry in t!(path.read_dir(), path).map(|e| t!(e)) { - // Look for `Cargo.toml` with a sibling `src/lib.rs` or `lib.rs`. - if entry.file_name().to_str() == Some("Cargo.toml") { - if path.join("src/lib.rs").is_file() { - verify(&entry.path(), &path.join("src/lib.rs"), bad) - } - if path.join("lib.rs").is_file() { - verify(&entry.path(), &path.join("lib.rs"), bad) - } - } else if t!(entry.file_type()).is_dir() { - check(&entry.path(), bad); - } - } -} - -/// Verifies that the dependencies in Cargo.toml at `tomlfile` are synced with -/// the `extern crate` annotations in the lib.rs at `libfile`. -fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) { - let toml = t!(fs::read_to_string(&tomlfile)); - let librs = t!(fs::read_to_string(&libfile)); - - if toml.contains("name = \"bootstrap\"") { - return; - } - - // "Poor man's TOML parser" -- just assume we use one syntax for now. - // - // We just look for: - // - // ```` - // [dependencies] - // name = ... - // name2 = ... - // name3 = ... - // ``` - // - // If we encounter a line starting with `[` then we assume it's the end of - // the dependency section and bail out. - let deps = match toml.find("[dependencies]") { - Some(i) => &toml[i + 1..], - None => return, - }; - for line in deps.lines() { - if line.starts_with('[') { - break; - } - - let krate = match line.split_once('=') { - None => continue, - Some((krate, _)) => krate.trim(), - }; - - // Don't worry about depending on core/std while not writing `extern crate - // core/std` -- that's intentional. - if krate == "core" || krate == "std" { - continue; - } - - // This is intentional -- this dependency just makes the crate available - // for others later on. - let allowed = krate.starts_with("panic"); - if toml.contains("name = \"std\"") && allowed { - continue; - } - - if !librs.contains(&format!("extern crate {}", krate)) { - tidy_error!( - bad, - "{} doesn't have `extern crate {}`, but Cargo.toml \ - depends on it", - libfile.display(), - krate - ); - } - } -} diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs index 7761ae64ee0..283c43e325c 100644 --- a/src/tools/tidy/src/edition.rs +++ b/src/tools/tidy/src/edition.rs @@ -2,20 +2,6 @@ use std::path::Path; -fn filter_dirs(path: &Path) -> bool { - // FIXME: just use super::filter_dirs after the submodules are updated. - if super::filter_dirs(path) { - return true; - } - let skip = [ - "src/doc/book/second-edition", - "src/doc/book/2018-edition", - "src/doc/book/ci/stable-check", - "src/doc/reference/stable-check", - ]; - skip.iter().any(|p| path.ends_with(p)) -} - fn is_edition_2018(mut line: &str) -> bool { line = line.trim(); line == "edition = \"2018\"" || line == "edition = \'2018\'" @@ -24,7 +10,7 @@ fn is_edition_2018(mut line: &str) -> bool { pub fn check(path: &Path, bad: &mut bool) { super::walk( path, - &mut |path| filter_dirs(path) || path.ends_with("src/test"), + &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), &mut |entry, contents| { let file = entry.path(); let filename = file.file_name().unwrap(); diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index d3a44542759..cb84fd8be6f 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -422,7 +422,7 @@ fn map_lib_features( mf(Err($msg), file, i + 1); continue; }}; - }; + } if let Some((ref name, ref mut f)) = becoming_feature { if f.tracking_issue.is_none() { f.tracking_issue = find_attr_val(line, "issue").and_then(handle_issue_none); diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index d282d240d82..27972c49924 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -40,7 +40,6 @@ macro_rules! tidy_error { } pub mod bins; -pub mod cargo; pub mod debug_artifacts; pub mod deps; pub mod edition; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 080e1631624..2ac96e404ac 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -49,10 +49,6 @@ fn main() { style::check(&compiler_path, &mut bad); style::check(&library_path, &mut bad); - cargo::check(&src_path, &mut bad); - cargo::check(&compiler_path, &mut bad); - cargo::check(&library_path, &mut bad); - edition::check(&src_path, &mut bad); edition::check(&compiler_path, &mut bad); edition::check(&library_path, &mut bad);