From 5f6cfd211a82313ad1d638f7f2a68a3a70a7d97b Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Mon, 1 Nov 2021 18:52:26 +0100 Subject: [PATCH 1/7] mention `remove` in `swap_remove` --- library/alloc/src/vec/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index d52c78eedf3fa..a72769f780727 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1272,6 +1272,9 @@ impl Vec { /// The removed element is replaced by the last element of the vector. /// /// This does not preserve ordering, but is *O*(1). + /// If you need to preserve the element order, use [`remove`] instead. + /// + /// [`remove`]: Vec::remove /// /// # Panics /// @@ -1368,7 +1371,7 @@ impl Vec { /// shifting all elements after it to the left. /// /// Note: Because this shifts over the remaining elements, it has a - /// worst-case performance of O(n). If you don't need the order of elements + /// worst-case performance of *O*(*n*). If you don't need the order of elements /// to be preserved, use [`swap_remove`] instead. /// /// [`swap_remove`]: Vec::swap_remove From 084b23247e61ba6965922da5acac4df8288a059a Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 4 Nov 2021 20:21:36 +0100 Subject: [PATCH 2/7] add const generics test --- src/test/ui/const-generics/invariant.rs | 33 +++++++++++++++++++++ src/test/ui/const-generics/invariant.stderr | 26 ++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/test/ui/const-generics/invariant.rs create mode 100644 src/test/ui/const-generics/invariant.stderr diff --git a/src/test/ui/const-generics/invariant.rs b/src/test/ui/const-generics/invariant.rs new file mode 100644 index 0000000000000..ee191b65c2c76 --- /dev/null +++ b/src/test/ui/const-generics/invariant.rs @@ -0,0 +1,33 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] +use std::marker::PhantomData; + +trait SadBee { + const ASSOC: usize; +} +// fn(&'static ())` is a supertype of `for<'a> fn(&'a ())` while +// we allow two different impls for these types, leading +// to different const eval results. +impl SadBee for for<'a> fn(&'a ()) { + const ASSOC: usize = 0; +} +impl SadBee for fn(&'static ()) { + //~^ WARNING conflicting implementations of trait + //~| WARNING this was previously accepted + const ASSOC: usize = 100; +} + +struct Foo([u8; ::ASSOC], PhantomData) +where + [(); ::ASSOC]: ; + +fn covariant( + v: &'static Foo fn(&'a ())> +) -> &'static Foo { + v //~ ERROR mismatched types +} + +fn main() { + let y = covariant(&Foo([], PhantomData)); + println!("{:?}", y.0); +} diff --git a/src/test/ui/const-generics/invariant.stderr b/src/test/ui/const-generics/invariant.stderr new file mode 100644 index 0000000000000..318c885e6a6bb --- /dev/null +++ b/src/test/ui/const-generics/invariant.stderr @@ -0,0 +1,26 @@ +warning: conflicting implementations of trait `SadBee` for type `for<'a> fn(&'a ())` + --> $DIR/invariant.rs:14:1 + | +LL | impl SadBee for for<'a> fn(&'a ()) { + | ---------------------------------- first implementation here +... +LL | impl SadBee for fn(&'static ()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a> fn(&'a ())` + | + = note: `#[warn(coherence_leak_check)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56105 + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + +error[E0308]: mismatched types + --> $DIR/invariant.rs:27:5 + | +LL | v + | ^ one type is more general than the other + | + = note: expected reference `&'static Foo` + found reference `&'static Foo fn(&'a ())>` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. From 1642fdfea0ba60f4e142e5d767491ab7686cd13b Mon Sep 17 00:00:00 2001 From: pierwill Date: Sun, 31 Oct 2021 17:05:48 -0500 Subject: [PATCH 3/7] Add `-Zassert-incr-state` to assert state of incremental cache --- .../rustc_incremental/src/persist/load.rs | 24 +++++++++++++- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/config.rs | 32 +++++++++++++++++++ compiler/rustc_session/src/options.rs | 5 ++- .../link_order/auxiliary/my_lib.rs | 4 +-- .../incremental/struct_change_field_name.rs | 1 + 6 files changed, 63 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 5f5e83774dad8..9c6e2aeb50a76 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -6,6 +6,7 @@ use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId}; use rustc_middle::ty::OnDiskCache; use rustc_serialize::opaque::Decoder; use rustc_serialize::Decodable; +use rustc_session::config::IncrementalStateAssertion; use rustc_session::Session; use std::path::Path; @@ -16,6 +17,7 @@ use super::work_product; type WorkProductMap = FxHashMap; +#[derive(Debug)] pub enum LoadResult { Ok { data: T }, DataOutOfDate, @@ -24,6 +26,26 @@ pub enum LoadResult { impl LoadResult { pub fn open(self, sess: &Session) -> T { + // Check for errors when using `-Zassert-incremental-state` + match (sess.opts.assert_incr_state, &self) { + (Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => { + sess.fatal( + "We asserted that the incremental cache should not be loaded, \ + but it was loaded.", + ); + } + ( + Some(IncrementalStateAssertion::Loaded), + LoadResult::Error { .. } | LoadResult::DataOutOfDate, + ) => { + sess.fatal( + "We asserted that an existing incremental cache directory should \ + be successfully loaded, but it was not.", + ); + } + _ => {} + }; + match self { LoadResult::Error { message } => { sess.warn(&message); @@ -33,7 +55,7 @@ impl LoadResult { if let Err(err) = delete_all_session_dir_contents(sess) { sess.err(&format!( "Failed to delete invalidated or incompatible \ - incremental compilation session directory contents `{}`: {}.", + incremental compilation session directory contents `{}`: {}.", dep_graph_path(sess).display(), err )); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index eed2e07e890e7..10c049f01263b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -635,6 +635,7 @@ fn test_debugging_options_tracking_hash() { // Make sure that changing an [UNTRACKED] option leaves the hash unchanged. // This list is in alphabetical order. + untracked!(assert_incr_state, Some(String::from("loaded"))); untracked!(ast_json, true); untracked!(ast_json_noexpand, true); untracked!(borrowck, String::from("other")); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 3afe094733928..f6f1d0e4b3678 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -165,6 +165,18 @@ pub enum LinkerPluginLto { Disabled, } +/// Used with `-Z assert-incr-state`. +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum IncrementalStateAssertion { + /// Found and loaded an existing session directory. + /// + /// Note that this says nothing about whether any particular query + /// will be found to be red or green. + Loaded, + /// Did not load an existing session directory. + NotLoaded, +} + impl LinkerPluginLto { pub fn enabled(&self) -> bool { match *self { @@ -704,6 +716,7 @@ pub fn host_triple() -> &'static str { impl Default for Options { fn default() -> Options { Options { + assert_incr_state: None, crate_types: Vec::new(), optimize: OptLevel::No, debuginfo: DebugInfo::None, @@ -1626,6 +1639,21 @@ fn select_debuginfo( } } +crate fn parse_assert_incr_state( + opt_assertion: &Option, + error_format: ErrorOutputType, +) -> Option { + match opt_assertion { + Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded), + Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded), + Some(s) => early_error( + error_format, + &format!("unexpected incremental state assertion value: {}", s), + ), + None => None, + } +} + fn parse_native_lib_kind( matches: &getopts::Matches, kind: &str, @@ -2015,6 +2043,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let incremental = cg.incremental.as_ref().map(PathBuf::from); + let assert_incr_state = + parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format); + if debugging_opts.profile && incremental.is_some() { early_error( error_format, @@ -2179,6 +2210,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { }; Options { + assert_incr_state, crate_types, optimize: opt_level, debuginfo, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index d1d8606a75a45..c85ea9e812efe 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -4,7 +4,6 @@ use crate::early_error; use crate::lint; use crate::search_paths::SearchPath; use crate::utils::NativeLib; - use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet}; use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel}; @@ -150,6 +149,7 @@ top_level_options!( /// If `Some`, enable incremental compilation, using the given /// directory to store intermediate results. incremental: Option [UNTRACKED], + assert_incr_state: Option [UNTRACKED], debugging_opts: DebuggingOptions [SUBSTRUCT], prints: Vec [UNTRACKED], @@ -1042,6 +1042,9 @@ options! { "make cfg(version) treat the current version as incomplete (default: no)"), asm_comments: bool = (false, parse_bool, [TRACKED], "generate comments into the assembly (may change behavior) (default: no)"), + assert_incr_state: Option = (None, parse_opt_string, [UNTRACKED], + "assert that the incremental cache is in given state: \ + either `loaded` or `not-loaded`."), ast_json: bool = (false, parse_bool, [UNTRACKED], "print the AST as JSON and halt (default: no)"), ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/test/incremental/link_order/auxiliary/my_lib.rs b/src/test/incremental/link_order/auxiliary/my_lib.rs index 57cde5f7c6e48..1e7d823050c3d 100644 --- a/src/test/incremental/link_order/auxiliary/my_lib.rs +++ b/src/test/incremental/link_order/auxiliary/my_lib.rs @@ -1,3 +1,3 @@ // no-prefer-dynamic -//[cfail1] compile-flags: -lbar -lfoo --crate-type lib -//[cfail2] compile-flags: -lfoo -lbar --crate-type lib +//[cfail1] compile-flags: -lbar -lfoo --crate-type lib -Zassert-incr-state=not-loaded +//[cfail2] compile-flags: -lfoo -lbar --crate-type lib -Zassert-incr-state=not-loaded diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs index 7498d0305e0b1..a7c79e9d751e0 100644 --- a/src/test/incremental/struct_change_field_name.rs +++ b/src/test/incremental/struct_change_field_name.rs @@ -3,6 +3,7 @@ // revisions:rpass1 cfail2 // compile-flags: -Z query-dep-graph +// [cfail2] compile-flags: -Z query-dep-graph -Z assert-incr-state=loaded #![feature(rustc_attrs)] From cf6f64a963f3cf630ca4bc3688cf461a98d2c9ce Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 5 Nov 2021 15:39:01 +0300 Subject: [PATCH 4/7] Make slice->str conversion and related functions const This commit makes the following functions from `core::str` `const fn`: - `from_utf8[_mut]` (`feature(const_str_from_utf8)`) - `from_utf8_unchecked_mut` (`feature(const_str_from_utf8_unchecked_mut)`) - `Utf8Error::{valid_up_to,error_len}` (`feature(const_str_from_utf8)`) --- library/alloc/tests/lib.rs | 1 + library/alloc/tests/str.rs | 64 +++++++++++++++++++++++++++-- library/core/src/lib.rs | 3 ++ library/core/src/str/converts.rs | 31 ++++++++++---- library/core/src/str/error.rs | 12 ++++-- library/core/src/str/validations.rs | 19 +++++---- 6 files changed, 106 insertions(+), 24 deletions(-) diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 8c57c804ad2dc..68e48348b076e 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -25,6 +25,7 @@ #![feature(const_btree_new)] #![feature(const_default_impls)] #![feature(const_trait_impl)] +#![feature(const_str_from_utf8)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index dc7d0bff9a404..1b741f174fb12 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1,3 +1,4 @@ +use std::assert_matches::assert_matches; use std::borrow::Cow; use std::cmp::Ordering::{Equal, Greater, Less}; use std::str::{from_utf8, from_utf8_unchecked}; @@ -883,6 +884,33 @@ fn test_is_utf8() { assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok()); } +#[test] +fn test_const_is_utf8() { + const _: () = { + // deny overlong encodings + assert!(from_utf8(&[0xc0, 0x80]).is_err()); + assert!(from_utf8(&[0xc0, 0xae]).is_err()); + assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err()); + assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err()); + assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err()); + assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err()); + assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err()); + + // deny surrogates + assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err()); + assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err()); + + assert!(from_utf8(&[0xC2, 0x80]).is_ok()); + assert!(from_utf8(&[0xDF, 0xBF]).is_ok()); + assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok()); + assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok()); + assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok()); + assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok()); + assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok()); + assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok()); + }; +} + #[test] fn from_utf8_mostly_ascii() { // deny invalid bytes embedded in long stretches of ascii @@ -895,13 +923,43 @@ fn from_utf8_mostly_ascii() { } } +#[test] +fn const_from_utf8_mostly_ascii() { + const _: () = { + // deny invalid bytes embedded in long stretches of ascii + let mut i = 32; + while i < 64 { + let mut data = [0; 128]; + data[i] = 0xC0; + assert!(from_utf8(&data).is_err()); + data[i] = 0xC2; + assert!(from_utf8(&data).is_err()); + + i = i + 1; + } + }; +} + #[test] fn from_utf8_error() { macro_rules! test { - ($input: expr, $expected_valid_up_to: expr, $expected_error_len: expr) => { + ($input: expr, $expected_valid_up_to:pat, $expected_error_len:pat) => { let error = from_utf8($input).unwrap_err(); - assert_eq!(error.valid_up_to(), $expected_valid_up_to); - assert_eq!(error.error_len(), $expected_error_len); + assert_matches!(error.valid_up_to(), $expected_valid_up_to); + assert_matches!(error.error_len(), $expected_error_len); + + const _: () = { + match from_utf8($input) { + Err(error) => { + let valid_up_to = error.valid_up_to(); + let error_len = error.error_len(); + + assert!(matches!(valid_up_to, $expected_valid_up_to)); + assert!(matches!(error_len, $expected_error_len)); + } + Ok(_) => unreachable!(), + } + }; }; } test!(b"A\xC3\xA9 \xFF ", 4, Some(1)); diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e4a566f589582..3b0872378c6e9 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -97,6 +97,7 @@ #![allow(explicit_outlives_requirements)] // // Library features for const fns: +#![feature(const_align_offset)] #![feature(const_align_of_val)] #![feature(const_alloc_layout)] #![feature(const_arguments_as_str)] @@ -130,6 +131,7 @@ #![feature(const_size_of_val)] #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] +#![feature(const_str_from_utf8_unchecked_mut)] #![feature(const_swap)] #![feature(const_trait_impl)] #![feature(const_type_id)] @@ -138,6 +140,7 @@ #![feature(duration_consts_2)] #![feature(ptr_metadata)] #![feature(slice_ptr_get)] +#![feature(str_internals)] #![feature(variant_count)] #![feature(const_array_from_ref)] #![feature(const_slice_from_ref)] diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index ed9f49f159611..8ac28669b3080 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -82,10 +82,16 @@ use super::Utf8Error; /// assert_eq!("💖", sparkle_heart); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { - run_utf8_validation(v)?; - // SAFETY: Just ran validation. - Ok(unsafe { from_utf8_unchecked(v) }) +#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "none")] +pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { + // This should use `?` again, once it's `const` + match run_utf8_validation(v) { + Ok(_) => { + // SAFETY: validation succeeded. + Ok(unsafe { from_utf8_unchecked(v) }) + } + Err(err) => Err(err), + } } /// Converts a mutable slice of bytes to a mutable string slice. @@ -119,10 +125,16 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] -pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { - run_utf8_validation(v)?; - // SAFETY: Just ran validation. - Ok(unsafe { from_utf8_unchecked_mut(v) }) +#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "none")] +pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { + // This should use `?` again, once it's `const` + match run_utf8_validation(v) { + Ok(_) => { + // SAFETY: validation succeeded. + Ok(unsafe { from_utf8_unchecked_mut(v) }) + } + Err(err) => Err(err), + } } /// Converts a slice of bytes to a string slice without checking @@ -184,7 +196,8 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[inline] #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] -pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { +#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "none")] +pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` // are valid UTF-8, thus the cast to `*mut str` is safe. // Also, the pointer dereference is safe because that pointer diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs index b6460d72fef32..3d0aeb52016e9 100644 --- a/library/core/src/str/error.rs +++ b/library/core/src/str/error.rs @@ -72,9 +72,10 @@ impl Utf8Error { /// assert_eq!(1, error.valid_up_to()); /// ``` #[stable(feature = "utf8_error", since = "1.5.0")] + #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "none")] #[must_use] #[inline] - pub fn valid_up_to(&self) -> usize { + pub const fn valid_up_to(&self) -> usize { self.valid_up_to } @@ -94,10 +95,15 @@ impl Utf8Error { /// /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html #[stable(feature = "utf8_error_error_len", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "none")] #[must_use] #[inline] - pub fn error_len(&self) -> Option { - self.error_len.map(|len| len as usize) + pub const fn error_len(&self) -> Option { + // This should become `map` again, once it's `const` + match self.error_len { + Some(len) => Some(len as usize), + None => None, + } } } diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs index 9a1cf905e3b02..e362d5c05c1b4 100644 --- a/library/core/src/str/validations.rs +++ b/library/core/src/str/validations.rs @@ -8,25 +8,25 @@ use super::Utf8Error; /// The first byte is special, only want bottom 5 bits for width 2, 4 bits /// for width 3, and 3 bits for width 4. #[inline] -fn utf8_first_byte(byte: u8, width: u32) -> u32 { +const fn utf8_first_byte(byte: u8, width: u32) -> u32 { (byte & (0x7F >> width)) as u32 } /// Returns the value of `ch` updated with continuation byte `byte`. #[inline] -fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 { +const fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 { (ch << 6) | (byte & CONT_MASK) as u32 } /// Checks whether the byte is a UTF-8 continuation byte (i.e., starts with the /// bits `10`). #[inline] -pub(super) fn utf8_is_cont_byte(byte: u8) -> bool { +pub(super) const fn utf8_is_cont_byte(byte: u8) -> bool { (byte as i8) < -64 } #[inline] -fn unwrap_or_0(opt: Option<&u8>) -> u8 { +const fn unwrap_or_0(opt: Option<&u8>) -> u8 { match opt { Some(&byte) => byte, None => 0, @@ -105,14 +105,15 @@ const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; /// Returns `true` if any byte in the word `x` is nonascii (>= 128). #[inline] -fn contains_nonascii(x: usize) -> bool { +const fn contains_nonascii(x: usize) -> bool { (x & NONASCII_MASK) != 0 } /// Walks through `v` checking that it's a valid UTF-8 sequence, /// returning `Ok(())` in that case, or, if it is invalid, `Err(err)`. #[inline(always)] -pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { +#[rustc_const_unstable(feature = "str_internals", issue = "none")] +pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { let mut index = 0; let len = v.len(); @@ -142,7 +143,7 @@ pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { let first = v[index]; if first >= 128 { - let w = UTF8_CHAR_WIDTH[first as usize]; + let w = utf8_char_width(first); // 2-byte encoding is for codepoints \u{0080} to \u{07ff} // first C2 80 last DF BF // 3-byte encoding is for codepoints \u{0800} to \u{ffff} @@ -230,7 +231,7 @@ pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { } // https://tools.ietf.org/html/rfc3629 -static UTF8_CHAR_WIDTH: [u8; 256] = [ +const UTF8_CHAR_WIDTH: &[u8; 256] = &[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x1F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -253,7 +254,7 @@ static UTF8_CHAR_WIDTH: [u8; 256] = [ #[unstable(feature = "str_internals", issue = "none")] #[must_use] #[inline] -pub fn utf8_char_width(b: u8) -> usize { +pub const fn utf8_char_width(b: u8) -> usize { UTF8_CHAR_WIDTH[b as usize] as usize } From a7261c32f485872756b8dc1544963a59e86c6449 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 17 Nov 2021 13:28:54 -0700 Subject: [PATCH 5/7] Avoid suggesting literal formatting that turns into member access Fixes #90974 --- compiler/rustc_typeck/src/check/method/suggest.rs | 6 +++++- src/test/ui/suggestions/issue-90974.rs | 3 +++ src/test/ui/suggestions/issue-90974.stderr | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/suggestions/issue-90974.rs create mode 100644 src/test/ui/suggestions/issue-90974.stderr diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 71cd8a43329c5..aceeb924ac4ad 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -317,6 +317,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .span_to_snippet(lit.span) .unwrap_or_else(|_| "".to_owned()); + // If this is a floating point literal that ends with '.', + // get rid of it to stop this from becoming a member access. + let snippet = snippet.strip_suffix('.').unwrap_or(&snippet); + err.span_suggestion( lit.span, &format!( @@ -324,7 +328,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { like `{}`", concrete_type ), - format!("{}_{}", snippet, concrete_type), + format!("{snippet}_{concrete_type}"), Applicability::MaybeIncorrect, ); } diff --git a/src/test/ui/suggestions/issue-90974.rs b/src/test/ui/suggestions/issue-90974.rs new file mode 100644 index 0000000000000..83590dbf7ace7 --- /dev/null +++ b/src/test/ui/suggestions/issue-90974.rs @@ -0,0 +1,3 @@ +fn main() { + println!("{}", (3.).recip()); //~ERROR +} diff --git a/src/test/ui/suggestions/issue-90974.stderr b/src/test/ui/suggestions/issue-90974.stderr new file mode 100644 index 0000000000000..e1fb479a3a7a0 --- /dev/null +++ b/src/test/ui/suggestions/issue-90974.stderr @@ -0,0 +1,14 @@ +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` + --> $DIR/issue-90974.rs:2:25 + | +LL | println!("{}", (3.).recip()); + | ^^^^^ + | +help: you must specify a concrete type for this numeric value, like `f32` + | +LL | println!("{}", (3_f32).recip()); + | ~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0689`. From 530eaa8b255250bef00f75c51175887cfbe09e13 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 8 Nov 2021 15:21:13 +0100 Subject: [PATCH 6/7] Clean up mess for --show-coverage documentation --- src/doc/rustdoc/src/unstable-features.md | 73 +++++++++++------------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index b3b6422afab42..16532215c6f33 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -348,6 +348,18 @@ Using this flag looks like this: $ rustdoc src/lib.rs -Z unstable-options --show-coverage ``` +It generates something like this: + +```bash ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| lib.rs | 4 | 100.0% | 1 | 25.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 4 | 100.0% | 1 | 25.0% | ++-------------------------------------+------------+------------+------------+------------+ +``` + If you want to determine how many items in your crate are documented, pass this flag to rustdoc. When it receives this flag, it will count the public items in your crate that have documentation, and print out the counts and a percentage instead of generating docs. @@ -367,17 +379,25 @@ Some methodology notes about what rustdoc counts in this metric: Public items that are not documented can be seen with the built-in `missing_docs` lint. Private items that are not documented can be seen with Clippy's `missing_docs_in_private_items` lint. -### `-w`/`--output-format`: output format +Calculating code examples follows these rules: -When using -[`--show-coverage`](https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#--show-coverage-get-statistics-about-code-documentation-coverage), -passing `--output-format json` will display the coverage information in JSON format. For example, -here is the JSON for a file with one documented item and one undocumented item: +1. These items aren't accounted by default: + * struct/union field + * enum variant + * constant + * static + * typedef +2. If one of the previously listed items has a code example, then it'll be counted. + +#### JSON output + +When using `--output-format json` with this option, it will display the coverage information in +JSON format. For example, here is the JSON for a file with one documented item and one +undocumented item: ```rust /// This item has documentation pub fn foo() {} - pub fn no_documentation() {} ``` @@ -387,10 +407,16 @@ pub fn no_documentation() {} Note that the third item is the crate root, which in this case is undocumented. -When not using `--show-coverage`, `--output-format json` emits documentation in the experimental +### `-w`/`--output-format`: output format + +`--output-format json` emits documentation in the experimental [JSON format](https://github.com/rust-lang/rfcs/pull/2963). `--output-format html` has no effect, and is also accepted on stable toolchains. +It can also be used with `--show-coverage`. Take a look at its +[documentation](#--show-coverage-get-statistics-about-code-documentation-coverage) for more +information. + ### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests Using this flag looks like this: @@ -441,39 +467,6 @@ $ rustdoc src/lib.rs -Z unstable-options --runtool valgrind Another use case would be to run a test inside an emulator, or through a Virtual Machine. -### `--show-coverage`: get statistics about code documentation coverage - -This option allows you to get a nice overview over your code documentation coverage, including both -doc-comments and code examples in the doc-comments. Example: - -```bash -$ rustdoc src/lib.rs -Z unstable-options --show-coverage -+-------------------------------------+------------+------------+------------+------------+ -| File | Documented | Percentage | Examples | Percentage | -+-------------------------------------+------------+------------+------------+------------+ -| lib.rs | 4 | 100.0% | 1 | 25.0% | -+-------------------------------------+------------+------------+------------+------------+ -| Total | 4 | 100.0% | 1 | 25.0% | -+-------------------------------------+------------+------------+------------+------------+ -``` - -You can also use this option with the `--output-format` one: - -```bash -$ rustdoc src/lib.rs -Z unstable-options --show-coverage --output-format json -{"lib.rs":{"total":4,"with_docs":4,"total_examples":4,"with_examples":1}} -``` - -Calculating code examples follows these rules: - -1. These items aren't accounted by default: - * struct/union field - * enum variant - * constant - * static - * typedef -2. If one of the previously listed items has a code example, then it'll be counted. - ### `--with-examples`: include examples of uses of items as documentation This option, combined with `--scrape-examples-target-crate` and From 573a00e3f9207a3be67921e1046cab95150b4ab4 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 18 Nov 2021 14:04:01 +0300 Subject: [PATCH 7/7] Fill in tracking issues for `const_str_from_utf8` and `const_str_from_utf8_unchecked_mut` features --- library/core/src/str/converts.rs | 6 +++--- library/core/src/str/error.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 8ac28669b3080..ef26cbfb640bf 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -82,7 +82,7 @@ use super::Utf8Error; /// assert_eq!("💖", sparkle_heart); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "none")] +#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { // This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -125,7 +125,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] -#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "none")] +#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -196,7 +196,7 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[inline] #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] -#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "none")] +#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` // are valid UTF-8, thus the cast to `*mut str` is safe. diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs index 3d0aeb52016e9..a127dd57eee0e 100644 --- a/library/core/src/str/error.rs +++ b/library/core/src/str/error.rs @@ -72,7 +72,7 @@ impl Utf8Error { /// assert_eq!(1, error.valid_up_to()); /// ``` #[stable(feature = "utf8_error", since = "1.5.0")] - #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "none")] + #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] #[must_use] #[inline] pub const fn valid_up_to(&self) -> usize { @@ -95,7 +95,7 @@ impl Utf8Error { /// /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html #[stable(feature = "utf8_error_error_len", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "none")] + #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] #[must_use] #[inline] pub const fn error_len(&self) -> Option {