From 7b557119883685e541d555135fb81c0dc10e2752 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 17 Jan 2019 18:57:46 +0100 Subject: [PATCH 01/14] Make MutexGuard's Debug implementation more useful. Fixes #57702. --- src/libstd/sync/mutex.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 856bb26042490..e4cc29792072f 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -450,9 +450,13 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { #[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("MutexGuard") - .field("lock", &self.__lock) - .finish() + struct MutexFmt<'a, T: ?Sized>(&'a MutexGuard<'a, T>); + impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexFmt<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Mutex").field("data", &&*self.0).finish() + } + } + f.debug_struct("MutexGuard").field("lock", &MutexFmt(self)).finish() } } From 2e9deed9f130d2342bec2a55358305cb7137605e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 17 Jan 2019 20:03:59 +0100 Subject: [PATCH 02/14] Simplify Debug implementation of MutexGuard. Just transparently print the guarded data, instead of wrapping it in `MutexGuard { lock: Mutex { data: ... } }`. --- src/libstd/sync/mutex.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index e4cc29792072f..59829db23cbc2 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -450,13 +450,7 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { #[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - struct MutexFmt<'a, T: ?Sized>(&'a MutexGuard<'a, T>); - impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexFmt<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Mutex").field("data", &&*self.0).finish() - } - } - f.debug_struct("MutexGuard").field("lock", &MutexFmt(self)).finish() + fmt::Debug::fmt(&**self, f) } } From b3690c6d660f8048c7e5e2a74210aa39804d707d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 18 Jan 2019 12:18:57 +0100 Subject: [PATCH 03/14] test that wildcard type `_` is not duplicated by `type Foo = (X, X);` and potentially instantiated at different types. --- ...ssue-55748-pat-types-constrain-bindings.rs | 70 +++++++++++++++++++ ...-55748-pat-types-constrain-bindings.stderr | 29 ++++++++ 2 files changed, 99 insertions(+) create mode 100644 src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs create mode 100644 src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs new file mode 100644 index 0000000000000..4d7ce4587c438 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs @@ -0,0 +1,70 @@ +// This test is ensuring that type ascriptions on let bindings +// constrain both: +// +// 1. the input expression on the right-hand side (after any potential +// coercion, and allowing for covariance), *and* +// +// 2. the bindings (if any) nested within the pattern on the left-hand +// side (and here, the type-constraint is *invariant*). + +#![feature(nll)] + +#![allow(dead_code, unused_mut)] +type PairUncoupled<'a, 'b, T> = (&'a T, &'b T); +type PairCoupledRegions<'a, T> = (&'a T, &'a T); +type PairCoupledTypes = (T, T); + +fn uncoupled_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((mut y, mut _z),): (PairUncoupled,) = ((s, &_x),); // ok + // Above compiling does *not* imply below would compile. + // ::std::mem::swap(&mut y, &mut _z); + y +} + +fn swap_regions((mut y, mut _z): PairCoupledRegions) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledRegions,) = ((s, &_x),); + // If above line compiled, so should line below ... + + // swap_regions((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR unsatisfied lifetime constraints +} + +fn swap_types((mut y, mut _z): PairCoupledTypes<&u32>) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledTypes<&u32>,) = ((s, &_x),); + // If above line compiled, so should line below ... + + // swap_types((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR unsatisfied lifetime constraints +} + +fn swap_wilds((mut y, mut _z): PairCoupledTypes<&u32>) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledTypes<_>,) = ((s, &_x),); + // If above line compiled, so should line below + // swap_wilds((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR unsatisfied lifetime constraints +} + +fn main() { + uncoupled_lhs(&3, &4); + coupled_regions_lhs(&3, &4); + coupled_types_lhs(&3, &4); + coupled_wilds_lhs(&3, &4); +} diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr new file mode 100644 index 0000000000000..25b04464e9bfa --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr @@ -0,0 +1,29 @@ +error: unsatisfied lifetime constraints + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:35:5 + | +LL | fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y //~ ERROR unsatisfied lifetime constraints + | ^ returning this value requires that `'a` must outlive `'static` + +error: unsatisfied lifetime constraints + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:49:5 + | +LL | fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y //~ ERROR unsatisfied lifetime constraints + | ^ returning this value requires that `'a` must outlive `'static` + +error: unsatisfied lifetime constraints + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:62:5 + | +LL | fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y //~ ERROR unsatisfied lifetime constraints + | ^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to 3 previous errors + From c14508fd252742e6f7ad99b1519ef1039b1eb80c Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sun, 20 Jan 2019 00:04:28 +0100 Subject: [PATCH 04/14] Add missing #![feature(rustc_private)] annotation --- src/libfmt_macros/lib.rs | 1 + src/libtest/lib.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 32ae878909f30..5127c76b55c6d 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -11,6 +11,7 @@ test(attr(deny(warnings))))] #![feature(nll)] +#![feature(rustc_private)] pub use self::Piece::*; pub use self::Position::*; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 2cc80ddea2df4..fc03e685b6f54 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -25,7 +25,7 @@ #![feature(asm)] #![cfg_attr(stage0, feature(cfg_target_vendor))] #![feature(fnbox)] -#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))] +#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc, rustc_private))] #![feature(nll)] #![feature(set_stdio)] #![feature(panic_unwind)] From ff41abcf8bbeefae4df033d6a1bac1543d67c388 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sun, 20 Jan 2019 00:05:10 +0100 Subject: [PATCH 05/14] linkchecker: Update deprecated trim_left_matches usage --- src/tools/linkchecker/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 59662be349dcb..2cf0fcfd34cd6 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -78,7 +78,7 @@ impl FileEntry { fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) { if self.ids.is_empty() { with_attrs_in_source(contents, " id", |fragment, i, _| { - let frag = fragment.trim_left_matches("#").to_owned(); + let frag = fragment.trim_start_matches("#").to_owned(); let encoded = small_url_encode(&frag); if !self.ids.insert(frag) { *errors = true; @@ -343,7 +343,7 @@ fn with_attrs_in_source(contents: &str, attr: &str, Some(i) => i, None => continue, }; - if rest[..pos_equals].trim_left_matches(" ") != "" { + if rest[..pos_equals].trim_start_matches(" ") != "" { continue; } @@ -355,7 +355,7 @@ fn with_attrs_in_source(contents: &str, attr: &str, }; let quote_delim = rest.as_bytes()[pos_quote] as char; - if rest[..pos_quote].trim_left_matches(" ") != "" { + if rest[..pos_quote].trim_start_matches(" ") != "" { continue; } let rest = &rest[pos_quote + 1..]; From e7998bf6a6e5cb3c12604d97c72435c1b4cea492 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Jan 2019 22:30:52 +0100 Subject: [PATCH 06/14] un-deprecate mem::zeroed --- src/libcore/mem.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 8fcbb73d9ce46..9e100d0a58d17 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -489,7 +489,6 @@ pub const fn needs_drop() -> bool { /// assert_eq!(0, x); /// ``` #[inline] -#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::zeroed` instead")] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn zeroed() -> T { #[cfg(not(stage0))] From 9aa1ca2f462d16c5f6d49830b72af91888bc8ab4 Mon Sep 17 00:00:00 2001 From: James Duley Date: Thu, 17 Jan 2019 23:17:21 +0000 Subject: [PATCH 07/14] Ignore aarch64 in simd-intrinsic-generic-reduction This fails on AArch64 see https://github.com/rust-lang/rust/issues/54510 --- src/test/run-pass/simd/simd-intrinsic-generic-reduction.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/run-pass/simd/simd-intrinsic-generic-reduction.rs b/src/test/run-pass/simd/simd-intrinsic-generic-reduction.rs index b39f54a5efbb4..e3faa7c625ccc 100644 --- a/src/test/run-pass/simd/simd-intrinsic-generic-reduction.rs +++ b/src/test/run-pass/simd/simd-intrinsic-generic-reduction.rs @@ -2,6 +2,7 @@ #![allow(non_camel_case_types)] // ignore-emscripten +// ignore-aarch64 FIXME: https://github.com/rust-lang/rust/issues/54510 // Test that the simd_reduce_{op} intrinsics produce the correct results. From 22f794b00fa8d84c9e827f8c8af762ee60074a8a Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 23 Jan 2019 02:35:13 +0100 Subject: [PATCH 08/14] Suggest removing leading left angle brackets. This commit adds errors and accompanying suggestions as below: ``` bar::<<<<::Output>(); ^^^ help: remove extra angle brackets ``` --- src/libsyntax/parse/parser.rs | 209 +++++++++++++++++++++++++- src/test/ui/issues/issue-57819.fixed | 47 ++++++ src/test/ui/issues/issue-57819.rs | 47 ++++++ src/test/ui/issues/issue-57819.stderr | 44 ++++++ 4 files changed, 339 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/issues/issue-57819.fixed create mode 100644 src/test/ui/issues/issue-57819.rs create mode 100644 src/test/ui/issues/issue-57819.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 439eec5b0c48d..6ad07a8e2f1d2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -242,6 +242,12 @@ pub struct Parser<'a> { desugar_doc_comments: bool, /// Whether we should configure out of line modules as we parse. pub cfg_mods: bool, + /// This field is used to keep track of how many left angle brackets we have seen. This is + /// required in order to detect extra leading left angle brackets (`<` characters) and error + /// appropriately. + /// + /// See the comments in the `parse_path_segment` function for more details. + crate unmatched_angle_bracket_count: u32, } @@ -563,6 +569,7 @@ impl<'a> Parser<'a> { }, desugar_doc_comments, cfg_mods: true, + unmatched_angle_bracket_count: 0, }; let tok = parser.next_tok(); @@ -1027,7 +1034,7 @@ impl<'a> Parser<'a> { /// starting token. fn eat_lt(&mut self) -> bool { self.expected_tokens.push(TokenType::Token(token::Lt)); - match self.token { + let ate = match self.token { token::Lt => { self.bump(); true @@ -1038,7 +1045,15 @@ impl<'a> Parser<'a> { true } _ => false, + }; + + if ate { + // See doc comment for `unmatched_angle_bracket_count`. + self.unmatched_angle_bracket_count += 1; + debug!("eat_lt: (increment) count={:?}", self.unmatched_angle_bracket_count); } + + ate } fn expect_lt(&mut self) -> PResult<'a, ()> { @@ -1054,24 +1069,35 @@ impl<'a> Parser<'a> { /// signal an error. fn expect_gt(&mut self) -> PResult<'a, ()> { self.expected_tokens.push(TokenType::Token(token::Gt)); - match self.token { + let ate = match self.token { token::Gt => { self.bump(); - Ok(()) + Some(()) } token::BinOp(token::Shr) => { let span = self.span.with_lo(self.span.lo() + BytePos(1)); - Ok(self.bump_with(token::Gt, span)) + Some(self.bump_with(token::Gt, span)) } token::BinOpEq(token::Shr) => { let span = self.span.with_lo(self.span.lo() + BytePos(1)); - Ok(self.bump_with(token::Ge, span)) + Some(self.bump_with(token::Ge, span)) } token::Ge => { let span = self.span.with_lo(self.span.lo() + BytePos(1)); - Ok(self.bump_with(token::Eq, span)) + Some(self.bump_with(token::Eq, span)) } - _ => self.unexpected() + _ => None, + }; + + match ate { + Some(x) => { + // See doc comment for `unmatched_angle_bracket_count`. + self.unmatched_angle_bracket_count -= 1; + debug!("expect_gt: (decrement) count={:?}", self.unmatched_angle_bracket_count); + + Ok(x) + }, + None => self.unexpected(), } } @@ -2079,7 +2105,11 @@ impl<'a> Parser<'a> { path_span = self.span.to(self.span); } + // See doc comment for `unmatched_angle_bracket_count`. self.expect(&token::Gt)?; + self.unmatched_angle_bracket_count -= 1; + debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); + self.expect(&token::ModSep)?; let qself = QSelf { ty, path_span, position: path.segments.len() }; @@ -2182,9 +2212,15 @@ impl<'a> Parser<'a> { } let lo = self.span; + // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If + // it isn't, then we reset the unmatched angle bracket count as we're about to start + // parsing a new path. + if style == PathStyle::Expr { self.unmatched_angle_bracket_count = 0; } + let args = if self.eat_lt() { // `<'a, T, A = U>` - let (args, bindings) = self.parse_generic_args()?; + let (args, bindings) = + self.parse_generic_args_with_leaning_angle_bracket_recovery(style, lo)?; self.expect_gt()?; let span = lo.to(self.prev_span); AngleBracketedArgs { args, bindings, span }.into() @@ -5319,6 +5355,163 @@ impl<'a> Parser<'a> { } } + /// Parse generic args (within a path segment) with recovery for extra leading angle brackets. + /// For the purposes of understanding the parsing logic of generic arguments, this function + /// can be thought of being the same as just calling `self.parse_generic_args()` if the source + /// had the correct amount of leading angle brackets. + /// + /// ```ignore (diagnostics) + /// bar::<<<::Output>(); + /// ^^ help: remove extra angle brackets + /// ``` + fn parse_generic_args_with_leaning_angle_bracket_recovery( + &mut self, + style: PathStyle, + lo: Span, + ) -> PResult<'a, (Vec, Vec)> { + // We need to detect whether there are extra leading left angle brackets and produce an + // appropriate error and suggestion. This cannot be implemented by looking ahead at + // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens + // then there won't be matching `>` tokens to find. + // + // To explain how this detection works, consider the following example: + // + // ```ignore (diagnostics) + // bar::<<<::Output>(); + // ^^ help: remove extra angle brackets + // ``` + // + // Parsing of the left angle brackets starts in this function. We start by parsing the + // `<` token (incrementing the counter of unmatched angle brackets on `Parser` via + // `eat_lt`): + // + // *Upcoming tokens:* `<<<::Output>;` + // *Unmatched count:* 1 + // *`parse_path_segment` calls deep:* 0 + // + // This has the effect of recursing as this function is called if a `<` character + // is found within the expected generic arguments: + // + // *Upcoming tokens:* `<<::Output>;` + // *Unmatched count:* 2 + // *`parse_path_segment` calls deep:* 1 + // + // Eventually we will have recursed until having consumed all of the `<` tokens and + // this will be reflected in the count: + // + // *Upcoming tokens:* `T as Foo>::Output>;` + // *Unmatched count:* 4 + // `parse_path_segment` calls deep:* 3 + // + // The parser will continue until reaching the first `>` - this will decrement the + // unmatched angle bracket count and return to the parent invocation of this function + // having succeeded in parsing: + // + // *Upcoming tokens:* `::Output>;` + // *Unmatched count:* 3 + // *`parse_path_segment` calls deep:* 2 + // + // This will continue until the next `>` character which will also return successfully + // to the parent invocation of this function and decrement the count: + // + // *Upcoming tokens:* `;` + // *Unmatched count:* 2 + // *`parse_path_segment` calls deep:* 1 + // + // At this point, this function will expect to find another matching `>` character but + // won't be able to and will return an error. This will continue all the way up the + // call stack until the first invocation: + // + // *Upcoming tokens:* `;` + // *Unmatched count:* 2 + // *`parse_path_segment` calls deep:* 0 + // + // In doing this, we have managed to work out how many unmatched leading left angle + // brackets there are, but we cannot recover as the unmatched angle brackets have + // already been consumed. To remedy this, whenever `parse_generic_args` is invoked, we + // make a snapshot of the current parser state and invoke it on that and inspect + // the result: + // + // - If success (ie. when it found a matching `>` character) then the snapshot state + // is kept (this is required to propagate the count upwards). + // + // - If error and in was in a recursive call, then the snapshot state is kept (this is + // required to propagate the count upwards). + // + // - If error and this was the first invocation (before any recursion had taken place) + // then we choose not to keep the snapshot state - that way we haven't actually + // consumed any of the `<` characters, but can still inspect the count from the + // snapshot to know how many `<` characters to remove. Using this information, we can + // emit an error and consume the extra `<` characters before attempting to parse + // the generic arguments again (this time hopefullt successfully as the unmatched `<` + // characters are gone). + // + // In practice, the recursion of this function is indirect and there will be other + // locations that consume some `<` characters - as long as we update the count when + // this happens, it isn't an issue. + let mut snapshot = self.clone(); + debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)"); + match snapshot.parse_generic_args() { + Ok(value) => { + debug!( + "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot success) \ + snapshot.count={:?}", + snapshot.unmatched_angle_bracket_count, + ); + mem::replace(self, snapshot); + Ok(value) + }, + Err(mut e) => { + debug!( + "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \ + snapshot.count={:?}", + snapshot.unmatched_angle_bracket_count, + ); + if style == PathStyle::Expr && snapshot.unmatched_angle_bracket_count > 0 { + // Cancel error from being unable to find `>`. We know the error + // must have been this due to a non-zero unmatched angle bracket + // count. + e.cancel(); + + // Eat the unmatched angle brackets. + for _ in 0..snapshot.unmatched_angle_bracket_count { + self.eat_lt(); + } + + // Make a span over ${unmatched angle bracket count} characters. + let span = lo.with_hi( + lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count) + ); + let plural = snapshot.unmatched_angle_bracket_count > 1; + self.diagnostic() + .struct_span_err( + span, + &format!( + "unmatched angle bracket{}", + if plural { "s" } else { "" } + ), + ) + .span_suggestion_with_applicability( + span, + &format!( + "remove extra angle bracket{}", + if plural { "s" } else { "" } + ), + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + + // Try again without unmatched angle bracket characters. + self.parse_generic_args() + } else { + mem::replace(self, snapshot); + Err(e) + } + }, + } + } + /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings, /// possibly including trailing comma. fn parse_generic_args(&mut self) -> PResult<'a, (Vec, Vec)> { diff --git a/src/test/ui/issues/issue-57819.fixed b/src/test/ui/issues/issue-57819.fixed new file mode 100644 index 0000000000000..3fab21db2d06e --- /dev/null +++ b/src/test/ui/issues/issue-57819.fixed @@ -0,0 +1,47 @@ +// run-rustfix + +#![allow(warnings)] + +// This test checks that the following error is emitted and the suggestion works: +// +// ``` +// let _ = vec![1, 2, 3].into_iter().collect::<<>(); +// ^^ help: remove extra angle brackets +// ``` + +trait Foo { + type Output; +} + +fn foo() { + // More complex cases with more than one correct leading `<` character: + + bar::<::Output>(); + //~^ ERROR unmatched angle bracket + + bar::<::Output>(); + //~^ ERROR unmatched angle bracket + + bar::<::Output>(); + //~^ ERROR unmatched angle bracket + + bar::<::Output>(); +} + +fn bar() {} + +fn main() { + let _ = vec![1, 2, 3].into_iter().collect::>(); + //~^ ERROR unmatched angle bracket + + let _ = vec![1, 2, 3].into_iter().collect::>(); + //~^ ERROR unmatched angle bracket + + let _ = vec![1, 2, 3].into_iter().collect::>(); + //~^ ERROR unmatched angle bracket + + let _ = vec![1, 2, 3].into_iter().collect::>(); + //~^ ERROR unmatched angle bracket + + let _ = vec![1, 2, 3].into_iter().collect::>(); +} diff --git a/src/test/ui/issues/issue-57819.rs b/src/test/ui/issues/issue-57819.rs new file mode 100644 index 0000000000000..5cafbf439be2d --- /dev/null +++ b/src/test/ui/issues/issue-57819.rs @@ -0,0 +1,47 @@ +// run-rustfix + +#![allow(warnings)] + +// This test checks that the following error is emitted and the suggestion works: +// +// ``` +// let _ = vec![1, 2, 3].into_iter().collect::<<>(); +// ^^ help: remove extra angle brackets +// ``` + +trait Foo { + type Output; +} + +fn foo() { + // More complex cases with more than one correct leading `<` character: + + bar::<<<<::Output>(); + //~^ ERROR unmatched angle bracket + + bar::<<<::Output>(); + //~^ ERROR unmatched angle bracket + + bar::<<::Output>(); + //~^ ERROR unmatched angle bracket + + bar::<::Output>(); +} + +fn bar() {} + +fn main() { + let _ = vec![1, 2, 3].into_iter().collect::<<<<>(); + //~^ ERROR unmatched angle bracket + + let _ = vec![1, 2, 3].into_iter().collect::<<<>(); + //~^ ERROR unmatched angle bracket + + let _ = vec![1, 2, 3].into_iter().collect::<<>(); + //~^ ERROR unmatched angle bracket + + let _ = vec![1, 2, 3].into_iter().collect::<>(); + //~^ ERROR unmatched angle bracket + + let _ = vec![1, 2, 3].into_iter().collect::>(); +} diff --git a/src/test/ui/issues/issue-57819.stderr b/src/test/ui/issues/issue-57819.stderr new file mode 100644 index 0000000000000..493e9835b1ca9 --- /dev/null +++ b/src/test/ui/issues/issue-57819.stderr @@ -0,0 +1,44 @@ +error: unmatched angle brackets + --> $DIR/issue-57819.rs:19:10 + | +LL | bar::<<<<::Output>(); + | ^^^ help: remove extra angle brackets + +error: unmatched angle brackets + --> $DIR/issue-57819.rs:22:10 + | +LL | bar::<<<::Output>(); + | ^^ help: remove extra angle brackets + +error: unmatched angle bracket + --> $DIR/issue-57819.rs:25:10 + | +LL | bar::<<::Output>(); + | ^ help: remove extra angle bracket + +error: unmatched angle brackets + --> $DIR/issue-57819.rs:34:48 + | +LL | let _ = vec![1, 2, 3].into_iter().collect::<<<<>(); + | ^^^^ help: remove extra angle brackets + +error: unmatched angle brackets + --> $DIR/issue-57819.rs:37:48 + | +LL | let _ = vec![1, 2, 3].into_iter().collect::<<<>(); + | ^^^ help: remove extra angle brackets + +error: unmatched angle brackets + --> $DIR/issue-57819.rs:40:48 + | +LL | let _ = vec![1, 2, 3].into_iter().collect::<<>(); + | ^^ help: remove extra angle brackets + +error: unmatched angle bracket + --> $DIR/issue-57819.rs:43:48 + | +LL | let _ = vec![1, 2, 3].into_iter().collect::<>(); + | ^ help: remove extra angle bracket + +error: aborting due to 7 previous errors + From 8ab12f6cc06033f483d085b37b766d681dcc61ca Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 23 Jan 2019 21:39:15 +0100 Subject: [PATCH 09/14] Optimize snapshot usage. This commit implements a suggestion from @estebank that optimizes the use of snapshots. Instead of creating a snapshot for each recursion in `parse_path_segment` and then replacing `self` with them until the first invocation where if leading angle brackets are detected, `self` is not replaced and instead the snapshot is used to inform how parsing should continue. Now, a snapshot is created in the first invocation that acts as a backup of the parser state before any generic arguments are parsed (and therefore, before recursion starts). This backup replaces `self` if after all parsing of generic arguments has concluded we can determine that there are leading angle brackets. Parsing can then proceed from the backup state making use of the now known number of unmatched leading angle brackets to recover. --- src/libsyntax/parse/parser.rs | 125 ++++++++++++++++------------------ 1 file changed, 57 insertions(+), 68 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6ad07a8e2f1d2..d03a346c3d55b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5428,87 +5428,76 @@ impl<'a> Parser<'a> { // // In doing this, we have managed to work out how many unmatched leading left angle // brackets there are, but we cannot recover as the unmatched angle brackets have - // already been consumed. To remedy this, whenever `parse_generic_args` is invoked, we - // make a snapshot of the current parser state and invoke it on that and inspect - // the result: - // - // - If success (ie. when it found a matching `>` character) then the snapshot state - // is kept (this is required to propagate the count upwards). - // - // - If error and in was in a recursive call, then the snapshot state is kept (this is - // required to propagate the count upwards). - // - // - If error and this was the first invocation (before any recursion had taken place) - // then we choose not to keep the snapshot state - that way we haven't actually - // consumed any of the `<` characters, but can still inspect the count from the - // snapshot to know how many `<` characters to remove. Using this information, we can - // emit an error and consume the extra `<` characters before attempting to parse - // the generic arguments again (this time hopefullt successfully as the unmatched `<` - // characters are gone). + // already been consumed. To remedy this, we keep a snapshot of the parser state + // before we do the above. We can then inspect whether we ended up with a parsing error + // and unmatched left angle brackets and if so, restore the parser state before we + // consumed any `<` characters to emit an error and consume the erroneous tokens to + // recover by attempting to parse again. // // In practice, the recursion of this function is indirect and there will be other // locations that consume some `<` characters - as long as we update the count when // this happens, it isn't an issue. - let mut snapshot = self.clone(); + + let is_first_invocation = style == PathStyle::Expr; + // Take a snapshot before attempting to parse - we can restore this later. + let snapshot = if is_first_invocation { + Some(self.clone()) + } else { + None + }; + debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)"); - match snapshot.parse_generic_args() { - Ok(value) => { - debug!( - "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot success) \ - snapshot.count={:?}", - snapshot.unmatched_angle_bracket_count, - ); - mem::replace(self, snapshot); - Ok(value) - }, - Err(mut e) => { + match self.parse_generic_args() { + Ok(value) => Ok(value), + Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => { + // Cancel error from being unable to find `>`. We know the error + // must have been this due to a non-zero unmatched angle bracket + // count. + e.cancel(); + + // Swap `self` with our backup of the parser state before attempting to parse + // generic arguments. + let snapshot = mem::replace(self, snapshot.unwrap()); + debug!( "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \ snapshot.count={:?}", snapshot.unmatched_angle_bracket_count, ); - if style == PathStyle::Expr && snapshot.unmatched_angle_bracket_count > 0 { - // Cancel error from being unable to find `>`. We know the error - // must have been this due to a non-zero unmatched angle bracket - // count. - e.cancel(); - - // Eat the unmatched angle brackets. - for _ in 0..snapshot.unmatched_angle_bracket_count { - self.eat_lt(); - } - // Make a span over ${unmatched angle bracket count} characters. - let span = lo.with_hi( - lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count) - ); - let plural = snapshot.unmatched_angle_bracket_count > 1; - self.diagnostic() - .struct_span_err( - span, - &format!( - "unmatched angle bracket{}", - if plural { "s" } else { "" } - ), - ) - .span_suggestion_with_applicability( - span, - &format!( - "remove extra angle bracket{}", - if plural { "s" } else { "" } - ), - String::new(), - Applicability::MachineApplicable, - ) - .emit(); - - // Try again without unmatched angle bracket characters. - self.parse_generic_args() - } else { - mem::replace(self, snapshot); - Err(e) + // Eat the unmatched angle brackets. + for _ in 0..snapshot.unmatched_angle_bracket_count { + self.eat_lt(); } + + // Make a span over ${unmatched angle bracket count} characters. + let span = lo.with_hi( + lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count) + ); + let plural = snapshot.unmatched_angle_bracket_count > 1; + self.diagnostic() + .struct_span_err( + span, + &format!( + "unmatched angle bracket{}", + if plural { "s" } else { "" } + ), + ) + .span_suggestion_with_applicability( + span, + &format!( + "remove extra angle bracket{}", + if plural { "s" } else { "" } + ), + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + + // Try again without unmatched angle bracket characters. + self.parse_generic_args() }, + Err(e) => Err(e), } } From 187dab9e96b9a373af7f4e353d08c9e4719956cd Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Wed, 23 Jan 2019 13:44:43 -0500 Subject: [PATCH 10/14] improve unused doc comment diagnostic reporting Report all unused attributes on a given doc comment instead of just the first one, and extend the span of sugared doc comments to encompass the whole comment. --- src/librustc_lint/builtin.rs | 41 +++++++++++++++++++++++------- src/test/ui/useless_comment.rs | 8 +++++- src/test/ui/useless_comment.stderr | 24 +++++++++++++---- 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f6c381ff74cc9..d59242b7e9931 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -753,27 +753,50 @@ impl LintPass for UnusedDocComment { } impl UnusedDocComment { - fn warn_if_doc<'a, 'tcx, - I: Iterator, - C: LintContext<'tcx>>(&self, mut attrs: I, cx: &C) { - if let Some(attr) = attrs.find(|a| a.is_value_str() && a.check_name("doc")) { - cx.struct_span_lint(UNUSED_DOC_COMMENTS, attr.span, "doc comment not used by rustdoc") - .emit(); + fn warn_if_doc(&self, cx: &EarlyContext, attrs: &[ast::Attribute]) { + let mut attrs = attrs.into_iter().peekable(); + + // Accumulate a single span for sugared doc comments. + let mut sugared_span: Option = None; + + while let Some(attr) = attrs.next() { + if attr.is_sugared_doc { + sugared_span = Some( + sugared_span.map_or_else( + || attr.span, + |span| span.with_hi(attr.span.hi()), + ), + ); + } + + if attrs.peek().map(|next_attr| next_attr.is_sugared_doc).unwrap_or_default() { + continue; + } + + let span = sugared_span.take().unwrap_or_else(|| attr.span); + + if attr.name() == "doc" { + cx.struct_span_lint( + UNUSED_DOC_COMMENTS, + span, + "doc comment not used by rustdoc", + ).emit(); + } } } } impl EarlyLintPass for UnusedDocComment { fn check_local(&mut self, cx: &EarlyContext, decl: &ast::Local) { - self.warn_if_doc(decl.attrs.iter(), cx); + self.warn_if_doc(cx, &decl.attrs); } fn check_arm(&mut self, cx: &EarlyContext, arm: &ast::Arm) { - self.warn_if_doc(arm.attrs.iter(), cx); + self.warn_if_doc(cx, &arm.attrs); } fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) { - self.warn_if_doc(expr.attrs.iter(), cx); + self.warn_if_doc(cx, &expr.attrs); } } diff --git a/src/test/ui/useless_comment.rs b/src/test/ui/useless_comment.rs index 531eec007fc48..e8a0e3c10d222 100644 --- a/src/test/ui/useless_comment.rs +++ b/src/test/ui/useless_comment.rs @@ -4,7 +4,9 @@ fn foo() { /// a //~ ERROR doc comment not used by rustdoc let x = 12; - /// b //~ doc comment not used by rustdoc + /// multi-line //~ doc comment not used by rustdoc + /// doc comment + /// that is unused match x { /// c //~ ERROR doc comment not used by rustdoc 1 => {}, @@ -13,6 +15,10 @@ fn foo() { /// foo //~ ERROR doc comment not used by rustdoc unsafe {} + + #[doc = "foo"] //~ ERROR doc comment not used by rustdoc + #[doc = "bar"] //~ ERROR doc comment not used by rustdoc + 3; } fn main() { diff --git a/src/test/ui/useless_comment.stderr b/src/test/ui/useless_comment.stderr index cc818f6ce7c39..a284c08f47ace 100644 --- a/src/test/ui/useless_comment.stderr +++ b/src/test/ui/useless_comment.stderr @@ -13,20 +13,34 @@ LL | #![deny(unused_doc_comments)] error: doc comment not used by rustdoc --> $DIR/useless_comment.rs:7:5 | -LL | /// b //~ doc comment not used by rustdoc - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / /// multi-line //~ doc comment not used by rustdoc +LL | | /// doc comment +LL | | /// that is unused + | |______________________^ error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:9:9 + --> $DIR/useless_comment.rs:11:9 | LL | /// c //~ ERROR doc comment not used by rustdoc | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:14:5 + --> $DIR/useless_comment.rs:16:5 | LL | /// foo //~ ERROR doc comment not used by rustdoc | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: doc comment not used by rustdoc + --> $DIR/useless_comment.rs:19:5 + | +LL | #[doc = "foo"] //~ ERROR doc comment not used by rustdoc + | ^^^^^^^^^^^^^^ + +error: doc comment not used by rustdoc + --> $DIR/useless_comment.rs:20:5 + | +LL | #[doc = "bar"] //~ ERROR doc comment not used by rustdoc + | ^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors From 871e460388c70c3024b0487a708c33e9348f9dca Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Thu, 24 Jan 2019 15:49:03 -0500 Subject: [PATCH 11/14] expand unused doc comment diagnostic Report the diagnostic on macro expansions, and add a label indicating why the comment is unused. --- src/libcore/num/mod.rs | 2 +- src/librustc/hir/mod.rs | 16 +-- src/librustc/middle/region.rs | 35 ++++--- src/librustc/ty/context.rs | 19 ++-- src/librustc/ty/mod.rs | 70 ++++++------- src/librustc/ty/sty.rs | 78 +++++++-------- src/librustc_data_structures/indexed_vec.rs | 30 +++++- src/librustc_lint/builtin.rs | 53 +++++++--- src/librustc_lint/lib.rs | 2 +- .../borrow_check/nll/region_infer/values.rs | 6 +- .../nll/type_check/liveness/liveness_map.rs | 8 +- src/librustc_mir/dataflow/move_paths/mod.rs | 36 ++++--- src/libstd/io/stdio.rs | 2 +- src/test/ui/useless_comment.rs | 31 ++++-- src/test/ui/useless_comment.stderr | 98 ++++++++++++++----- 15 files changed, 313 insertions(+), 173 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 41caa1788fbb8..0bb0336ee1588 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4654,7 +4654,7 @@ macro_rules! rev { )*} } -/// intra-sign conversions +// intra-sign conversions try_from_upper_bounded!(u16, u8); try_from_upper_bounded!(u32, u16, u8); try_from_upper_bounded!(u64, u32, u16, u8); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index b58b1d359f98b..d2fb3640d6ef9 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -115,15 +115,15 @@ impl serialize::UseSpecializedDecodable for HirId { // hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module mod item_local_id_inner { use rustc_data_structures::indexed_vec::Idx; - /// An `ItemLocalId` uniquely identifies something within a given "item-like", - /// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no - /// guarantee that the numerical value of a given `ItemLocalId` corresponds to - /// the node's position within the owning item in any way, but there is a - /// guarantee that the `LocalItemId`s within an owner occupy a dense range of - /// integers starting at zero, so a mapping that maps all or most nodes within - /// an "item-like" to something else can be implement by a `Vec` instead of a - /// tree or hash map. newtype_index! { + /// An `ItemLocalId` uniquely identifies something within a given "item-like", + /// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no + /// guarantee that the numerical value of a given `ItemLocalId` corresponds to + /// the node's position within the owning item in any way, but there is a + /// guarantee that the `LocalItemId`s within an owner occupy a dense range of + /// integers starting at zero, so a mapping that maps all or most nodes within + /// an "item-like" to something else can be implement by a `Vec` instead of a + /// tree or hash map. pub struct ItemLocalId { .. } } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 31f91a1bae57f..280d24ee17576 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -132,25 +132,24 @@ pub enum ScopeData { Remainder(FirstStatementIndex) } -/// Represents a subscope of `block` for a binding that is introduced -/// by `block.stmts[first_statement_index]`. Such subscopes represent -/// a suffix of the block. Note that each subscope does not include -/// the initializer expression, if any, for the statement indexed by -/// `first_statement_index`. -/// -/// For example, given `{ let (a, b) = EXPR_1; let c = EXPR_2; ... }`: -/// -/// * the subscope with `first_statement_index == 0` is scope of both -/// `a` and `b`; it does not include EXPR_1, but does include -/// everything after that first `let`. (If you want a scope that -/// includes EXPR_1 as well, then do not use `Scope::Remainder`, -/// but instead another `Scope` that encompasses the whole block, -/// e.g., `Scope::Node`. -/// -/// * the subscope with `first_statement_index == 1` is scope of `c`, -/// and thus does not include EXPR_2, but covers the `...`. - newtype_index! { + /// Represents a subscope of `block` for a binding that is introduced + /// by `block.stmts[first_statement_index]`. Such subscopes represent + /// a suffix of the block. Note that each subscope does not include + /// the initializer expression, if any, for the statement indexed by + /// `first_statement_index`. + /// + /// For example, given `{ let (a, b) = EXPR_1; let c = EXPR_2; ... }`: + /// + /// * the subscope with `first_statement_index == 0` is scope of both + /// `a` and `b`; it does not include EXPR_1, but does include + /// everything after that first `let`. (If you want a scope that + /// includes EXPR_1 as well, then do not use `Scope::Remainder`, + /// but instead another `Scope` that encompasses the whole block, + /// e.g., `Scope::Node`. + /// + /// * the subscope with `first_statement_index == 1` is scope of `c`, + /// and thus does not include EXPR_2, but covers the `...`. pub struct FirstStatementIndex { .. } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e37eab622df3f..e77535663c60c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1852,9 +1852,11 @@ pub mod tls { rayon_core::tlv::get() } - /// A thread local variable which stores a pointer to the current ImplicitCtxt #[cfg(not(parallel_queries))] - thread_local!(static TLV: Cell = Cell::new(0)); + thread_local! { + /// A thread local variable which stores a pointer to the current ImplicitCtxt. + static TLV: Cell = Cell::new(0); + } /// Sets TLV to `value` during the call to `f`. /// It is restored to its previous value after. @@ -1971,10 +1973,15 @@ pub mod tls { }) } - /// Stores a pointer to the GlobalCtxt if one is available. - /// This is used to access the GlobalCtxt in the deadlock handler - /// given to Rayon. - scoped_thread_local!(pub static GCX_PTR: Lock); + scoped_thread_local! { + // FIXME: This should be a doc comment, but the macro does not allow attributes: + // https://github.com/alexcrichton/scoped-tls/pull/8 + // + // Stores a pointer to the GlobalCtxt if one is available. + // This is used to access the GlobalCtxt in the deadlock handler + // given to Rayon. + pub static GCX_PTR: Lock + } /// Creates a TyCtxt and ImplicitCtxt based on the GCX_PTR thread local. /// This is used in the deadlock handler. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index dd315cf42ce7e..c2f9e4a74fdb0 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1489,42 +1489,42 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } } -/// "Universes" are used during type- and trait-checking in the -/// presence of `for<..>` binders to control what sets of names are -/// visible. Universes are arranged into a tree: the root universe -/// contains names that are always visible. Each child then adds a new -/// set of names that are visible, in addition to those of its parent. -/// We say that the child universe "extends" the parent universe with -/// new names. -/// -/// To make this more concrete, consider this program: -/// -/// ``` -/// struct Foo { } -/// fn bar(x: T) { -/// let y: for<'a> fn(&'a u8, Foo) = ...; -/// } -/// ``` -/// -/// The struct name `Foo` is in the root universe U0. But the type -/// parameter `T`, introduced on `bar`, is in an extended universe U1 -/// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside -/// of `bar`, we cannot name `T`. Then, within the type of `y`, the -/// region `'a` is in a universe U2 that extends U1, because we can -/// name it inside the fn type but not outside. -/// -/// Universes are used to do type- and trait-checking around these -/// "forall" binders (also called **universal quantification**). The -/// idea is that when, in the body of `bar`, we refer to `T` as a -/// type, we aren't referring to any type in particular, but rather a -/// kind of "fresh" type that is distinct from all other types we have -/// actually declared. This is called a **placeholder** type, and we -/// use universes to talk about this. In other words, a type name in -/// universe 0 always corresponds to some "ground" type that the user -/// declared, but a type name in a non-zero universe is a placeholder -/// type -- an idealized representative of "types in general" that we -/// use for checking generic functions. newtype_index! { + /// "Universes" are used during type- and trait-checking in the + /// presence of `for<..>` binders to control what sets of names are + /// visible. Universes are arranged into a tree: the root universe + /// contains names that are always visible. Each child then adds a new + /// set of names that are visible, in addition to those of its parent. + /// We say that the child universe "extends" the parent universe with + /// new names. + /// + /// To make this more concrete, consider this program: + /// + /// ``` + /// struct Foo { } + /// fn bar(x: T) { + /// let y: for<'a> fn(&'a u8, Foo) = ...; + /// } + /// ``` + /// + /// The struct name `Foo` is in the root universe U0. But the type + /// parameter `T`, introduced on `bar`, is in an extended universe U1 + /// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside + /// of `bar`, we cannot name `T`. Then, within the type of `y`, the + /// region `'a` is in a universe U2 that extends U1, because we can + /// name it inside the fn type but not outside. + /// + /// Universes are used to do type- and trait-checking around these + /// "forall" binders (also called **universal quantification**). The + /// idea is that when, in the body of `bar`, we refer to `T` as a + /// type, we aren't referring to any type in particular, but rather a + /// kind of "fresh" type that is distinct from all other types we have + /// actually declared. This is called a **placeholder** type, and we + /// use universes to talk about this. In other words, a type name in + /// universe 0 always corresponds to some "ground" type that the user + /// declared, but a type name in a non-zero universe is a placeholder + /// type -- an idealized representative of "types in general" that we + /// use for checking generic functions. pub struct UniverseIndex { DEBUG_FORMAT = "U{}", } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index b98369b62ea37..b7b79f9c9cf77 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1060,46 +1060,46 @@ impl<'a, 'gcx, 'tcx> ParamTy { } } -/// A [De Bruijn index][dbi] is a standard means of representing -/// regions (and perhaps later types) in a higher-ranked setting. In -/// particular, imagine a type like this: -/// -/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) -/// ^ ^ | | | -/// | | | | | -/// | +------------+ 0 | | -/// | | | -/// +--------------------------------+ 1 | -/// | | -/// +------------------------------------------+ 0 -/// -/// In this type, there are two binders (the outer fn and the inner -/// fn). We need to be able to determine, for any given region, which -/// fn type it is bound by, the inner or the outer one. There are -/// various ways you can do this, but a De Bruijn index is one of the -/// more convenient and has some nice properties. The basic idea is to -/// count the number of binders, inside out. Some examples should help -/// clarify what I mean. -/// -/// Let's start with the reference type `&'b isize` that is the first -/// argument to the inner function. This region `'b` is assigned a De -/// Bruijn index of 0, meaning "the innermost binder" (in this case, a -/// fn). The region `'a` that appears in the second argument type (`&'a -/// isize`) would then be assigned a De Bruijn index of 1, meaning "the -/// second-innermost binder". (These indices are written on the arrays -/// in the diagram). -/// -/// What is interesting is that De Bruijn index attached to a particular -/// variable will vary depending on where it appears. For example, -/// the final type `&'a char` also refers to the region `'a` declared on -/// the outermost fn. But this time, this reference is not nested within -/// any other binders (i.e., it is not an argument to the inner fn, but -/// rather the outer one). Therefore, in this case, it is assigned a -/// De Bruijn index of 0, because the innermost binder in that location -/// is the outer fn. -/// -/// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index newtype_index! { + /// A [De Bruijn index][dbi] is a standard means of representing + /// regions (and perhaps later types) in a higher-ranked setting. In + /// particular, imagine a type like this: + /// + /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) + /// ^ ^ | | | + /// | | | | | + /// | +------------+ 0 | | + /// | | | + /// +--------------------------------+ 1 | + /// | | + /// +------------------------------------------+ 0 + /// + /// In this type, there are two binders (the outer fn and the inner + /// fn). We need to be able to determine, for any given region, which + /// fn type it is bound by, the inner or the outer one. There are + /// various ways you can do this, but a De Bruijn index is one of the + /// more convenient and has some nice properties. The basic idea is to + /// count the number of binders, inside out. Some examples should help + /// clarify what I mean. + /// + /// Let's start with the reference type `&'b isize` that is the first + /// argument to the inner function. This region `'b` is assigned a De + /// Bruijn index of 0, meaning "the innermost binder" (in this case, a + /// fn). The region `'a` that appears in the second argument type (`&'a + /// isize`) would then be assigned a De Bruijn index of 1, meaning "the + /// second-innermost binder". (These indices are written on the arrays + /// in the diagram). + /// + /// What is interesting is that De Bruijn index attached to a particular + /// variable will vary depending on where it appears. For example, + /// the final type `&'a char` also refers to the region `'a` declared on + /// the outermost fn. But this time, this reference is not nested within + /// any other binders (i.e., it is not an argument to the inner fn, but + /// rather the outer one). Therefore, in this case, it is assigned a + /// De Bruijn index of 0, because the innermost binder in that location + /// is the outer fn. + /// + /// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index pub struct DebruijnIndex { DEBUG_FORMAT = "DebruijnIndex({})", const INNERMOST = 0, diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 8d8fbe588a021..13e6baa4d9d4e 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -58,9 +58,10 @@ macro_rules! newtype_index { // ---- public rules ---- // Use default constants - ($v:vis struct $name:ident { .. }) => ( + ($(#[$attrs:meta])* $v:vis struct $name:ident { .. }) => ( newtype_index!( // Leave out derives marker so we can use its absence to ensure it comes first + @attrs [$(#[$attrs])*] @type [$name] // shave off 256 indices at the end to allow space for packing these indices into enums @max [0xFFFF_FF00] @@ -69,9 +70,10 @@ macro_rules! newtype_index { ); // Define any constants - ($v:vis struct $name:ident { $($tokens:tt)+ }) => ( + ($(#[$attrs:meta])* $v:vis struct $name:ident { $($tokens:tt)+ }) => ( newtype_index!( // Leave out derives marker so we can use its absence to ensure it comes first + @attrs [$(#[$attrs])*] @type [$name] // shave off 256 indices at the end to allow space for packing these indices into enums @max [0xFFFF_FF00] @@ -84,10 +86,12 @@ macro_rules! newtype_index { // Base case, user-defined constants (if any) have already been defined (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt]) => ( + $(#[$attrs])* #[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)] #[rustc_layout_scalar_valid_range_end($max)] $v struct $type { @@ -317,7 +321,8 @@ macro_rules! newtype_index { // By not including the @derives marker in this list nor in the default args, we can force it // to come first if it exists. When encodable isn't custom, add serialization traits by default. - (@type [$type:ident] + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt] @@ -325,6 +330,7 @@ macro_rules! newtype_index { $($tokens:tt)*) => ( newtype_index!( @derives [$($derives,)+ RustcEncodable,] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -335,7 +341,8 @@ macro_rules! newtype_index { // The case where no derives are added, but encodable is overridden. Don't // derive serialization traits - (@type [$type:ident] + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt] @@ -343,6 +350,7 @@ macro_rules! newtype_index { $($tokens:tt)*) => ( newtype_index!( @derives [] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -351,13 +359,15 @@ macro_rules! newtype_index { ); // The case where no derives are added, add serialization derives by default - (@type [$type:ident] + (@attrs [$(#[$attrs:meta])*] + @type [$type:ident] @max [$max:expr] @vis [$v:vis] @debug_format [$debug_format:tt] $($tokens:tt)*) => ( newtype_index!( @derives [RustcEncodable,] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -384,6 +394,7 @@ macro_rules! newtype_index { // Rewrite final without comma to one that includes comma (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] @max [$max:expr] @vis [$v:vis] @@ -391,6 +402,7 @@ macro_rules! newtype_index { $name:ident = $constant:expr) => ( newtype_index!( @derives [$($derives,)*] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -400,6 +412,7 @@ macro_rules! newtype_index { // Rewrite final const without comma to one that includes comma (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] @max [$_max:expr] @vis [$v:vis] @@ -408,6 +421,7 @@ macro_rules! newtype_index { const $name:ident = $constant:expr) => ( newtype_index!( @derives [$($derives,)*] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -417,6 +431,7 @@ macro_rules! newtype_index { // Replace existing default for max (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] @max [$_max:expr] @vis [$v:vis] @@ -425,6 +440,7 @@ macro_rules! newtype_index { $($tokens:tt)*) => ( newtype_index!( @derives [$($derives,)*] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -434,6 +450,7 @@ macro_rules! newtype_index { // Replace existing default for debug_format (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] @max [$max:expr] @vis [$v:vis] @@ -442,6 +459,7 @@ macro_rules! newtype_index { $($tokens:tt)*) => ( newtype_index!( @derives [$($derives,)*] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] @@ -451,6 +469,7 @@ macro_rules! newtype_index { // Assign a user-defined constant (@derives [$($derives:ident,)*] + @attrs [$(#[$attrs:meta])*] @type [$type:ident] @max [$max:expr] @vis [$v:vis] @@ -462,6 +481,7 @@ macro_rules! newtype_index { pub const $name: $type = $type::from_u32_const($constant); newtype_index!( @derives [$($derives,)*] + @attrs [$(#[$attrs])*] @type [$type] @max [$max] @vis [$v] diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index d59242b7e9931..df0ff6be75e55 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -32,7 +32,7 @@ use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ast; use syntax::ptr::P; use syntax::ast::Expr; -use syntax::attr; +use syntax::attr::{self, HasAttrs}; use syntax::source_map::Spanned; use syntax::edition::Edition; use syntax::feature_gate::{AttributeGate, AttributeTemplate, AttributeType}; @@ -753,7 +753,14 @@ impl LintPass for UnusedDocComment { } impl UnusedDocComment { - fn warn_if_doc(&self, cx: &EarlyContext, attrs: &[ast::Attribute]) { + fn warn_if_doc( + &self, + cx: &EarlyContext, + node_span: Span, + node_kind: &str, + is_macro_expansion: bool, + attrs: &[ast::Attribute] + ) { let mut attrs = attrs.into_iter().peekable(); // Accumulate a single span for sugared doc comments. @@ -776,27 +783,51 @@ impl UnusedDocComment { let span = sugared_span.take().unwrap_or_else(|| attr.span); if attr.name() == "doc" { - cx.struct_span_lint( - UNUSED_DOC_COMMENTS, - span, - "doc comment not used by rustdoc", - ).emit(); + let mut err = cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, "unused doc comment"); + + err.span_label( + node_span, + format!("rustdoc does not generate documentation for {}", node_kind) + ); + + if is_macro_expansion { + err.help("to document an item produced by a macro, \ + the macro must produce the documentation as part of its expansion"); + } + + err.emit(); } } } } impl EarlyLintPass for UnusedDocComment { - fn check_local(&mut self, cx: &EarlyContext, decl: &ast::Local) { - self.warn_if_doc(cx, &decl.attrs); + fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { + if let ast::ItemKind::Mac(..) = item.node { + self.warn_if_doc(cx, item.span, "macro expansions", true, &item.attrs); + } + } + + fn check_stmt(&mut self, cx: &EarlyContext, stmt: &ast::Stmt) { + let (kind, is_macro_expansion) = match stmt.node { + ast::StmtKind::Local(..) => ("statements", false), + ast::StmtKind::Item(..) => ("inner items", false), + ast::StmtKind::Mac(..) => ("macro expansions", true), + // expressions will be reported by `check_expr`. + ast::StmtKind::Semi(..) | + ast::StmtKind::Expr(..) => return, + }; + + self.warn_if_doc(cx, stmt.span, kind, is_macro_expansion, stmt.node.attrs()); } fn check_arm(&mut self, cx: &EarlyContext, arm: &ast::Arm) { - self.warn_if_doc(cx, &arm.attrs); + let arm_span = arm.pats[0].span.with_hi(arm.body.span.hi()); + self.warn_if_doc(cx, arm_span, "match arms", false, &arm.attrs); } fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) { - self.warn_if_doc(cx, &expr.attrs); + self.warn_if_doc(cx, expr.span, "expressions", false, &expr.attrs); } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 71c859d8dbea7..7bb9b0fbc0b81 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -107,6 +107,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { add_pre_expansion_builtin!(sess, KeywordIdents, + UnusedDocComment, ); add_early_builtin!(sess, @@ -114,7 +115,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UnusedImportBraces, UnsafeCode, AnonymousParameters, - UnusedDocComment, EllipsisInclusiveRangePatterns, NonCamelCaseTypes, ); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 88e8310db6893..b560b946fb4b7 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -116,14 +116,14 @@ impl RegionValueElements { } } -/// A single integer representing a `Location` in the MIR control-flow -/// graph. Constructed efficiently from `RegionValueElements`. newtype_index! { + /// A single integer representing a `Location` in the MIR control-flow + /// graph. Constructed efficiently from `RegionValueElements`. pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" } } -/// A single integer representing a `ty::Placeholder`. newtype_index! { + /// A single integer representing a `ty::Placeholder`. pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs index dda74e6a6a688..77aea996074bb 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs @@ -85,10 +85,10 @@ impl NllLivenessMap { } } -/// Index given to each local variable for which we need to -/// compute liveness information. For many locals, we are able to -/// skip liveness information: for example, those variables whose -/// types contain no regions. newtype_index! { + /// Index given to each local variable for which we need to + /// compute liveness information. For many locals, we are able to + /// skip liveness information: for example, those variables whose + /// types contain no regions. pub struct LiveVar { .. } } diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index d77216220ac2b..17ea382029f0a 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -23,7 +23,7 @@ pub(crate) mod indexes { use rustc_data_structures::indexed_vec::Idx; macro_rules! new_index { - ($Index:ident, $debug_name:expr) => { + ($(#[$attrs:meta])* $Index:ident, $debug_name:expr) => { #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct $Index(NonZeroUsize); @@ -44,17 +44,29 @@ pub(crate) mod indexes { } } - /// Index into MovePathData.move_paths - new_index!(MovePathIndex, "mp"); - - /// Index into MoveData.moves. - new_index!(MoveOutIndex, "mo"); - - /// Index into MoveData.inits. - new_index!(InitIndex, "in"); - - /// Index into Borrows.locations - new_index!(BorrowIndex, "bw"); + new_index!( + /// Index into MovePathData.move_paths + MovePathIndex, + "mp" + ); + + new_index!( + /// Index into MoveData.moves. + MoveOutIndex, + "mo" + ); + + new_index!( + /// Index into MoveData.inits. + InitIndex, + "in" + ); + + new_index!( + /// Index into Borrows.locations + BorrowIndex, + "bw" + ); } pub use self::indexes::MovePathIndex; diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index d249469323063..4eabbef2c4f22 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -9,8 +9,8 @@ use sys::stdio; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use thread::LocalKey; -/// Stdout used by print! and println! macros thread_local! { + /// Stdout used by print! and println! macros static LOCAL_STDOUT: RefCell>> = { RefCell::new(None) } diff --git a/src/test/ui/useless_comment.rs b/src/test/ui/useless_comment.rs index e8a0e3c10d222..7d2e5ab6f2b7f 100644 --- a/src/test/ui/useless_comment.rs +++ b/src/test/ui/useless_comment.rs @@ -1,24 +1,43 @@ +#![feature(stmt_expr_attributes)] + #![deny(unused_doc_comments)] +macro_rules! mac { + () => {} +} + +/// foo //~ ERROR unused doc comment +mac!(); + fn foo() { - /// a //~ ERROR doc comment not used by rustdoc + /// a //~ ERROR unused doc comment let x = 12; - /// multi-line //~ doc comment not used by rustdoc + /// multi-line //~ unused doc comment /// doc comment /// that is unused match x { - /// c //~ ERROR doc comment not used by rustdoc + /// c //~ ERROR unused doc comment 1 => {}, _ => {} } - /// foo //~ ERROR doc comment not used by rustdoc + /// foo //~ ERROR unused doc comment unsafe {} - #[doc = "foo"] //~ ERROR doc comment not used by rustdoc - #[doc = "bar"] //~ ERROR doc comment not used by rustdoc + #[doc = "foo"] //~ ERROR unused doc comment + #[doc = "bar"] //~ ERROR unused doc comment 3; + + /// bar //~ ERROR unused doc comment + mac!(); + + let x = /** comment */ 47; //~ ERROR unused doc comment + + /// dox //~ ERROR unused doc comment + { + + } } fn main() { diff --git a/src/test/ui/useless_comment.stderr b/src/test/ui/useless_comment.stderr index a284c08f47ace..0742a844b7f40 100644 --- a/src/test/ui/useless_comment.stderr +++ b/src/test/ui/useless_comment.stderr @@ -1,46 +1,98 @@ -error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:4:5 +error: unused doc comment + --> $DIR/useless_comment.rs:9:1 | -LL | /// a //~ ERROR doc comment not used by rustdoc - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | /// foo //~ ERROR unused doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | mac!(); + | ------- rustdoc does not generate documentation for macro expansions | note: lint level defined here - --> $DIR/useless_comment.rs:1:9 + --> $DIR/useless_comment.rs:3:9 | LL | #![deny(unused_doc_comments)] | ^^^^^^^^^^^^^^^^^^^ + = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion -error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:7:5 +error: unused doc comment + --> $DIR/useless_comment.rs:13:5 | -LL | / /// multi-line //~ doc comment not used by rustdoc +LL | /// a //~ ERROR unused doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = 12; + | ----------- rustdoc does not generate documentation for statements + +error: unused doc comment + --> $DIR/useless_comment.rs:16:5 + | +LL | / /// multi-line //~ unused doc comment LL | | /// doc comment LL | | /// that is unused | |______________________^ +LL | / match x { +LL | | /// c //~ ERROR unused doc comment +LL | | 1 => {}, +LL | | _ => {} +LL | | } + | |_____- rustdoc does not generate documentation for expressions -error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:11:9 +error: unused doc comment + --> $DIR/useless_comment.rs:20:9 | -LL | /// c //~ ERROR doc comment not used by rustdoc - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | /// c //~ ERROR unused doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | 1 => {}, + | ------- rustdoc does not generate documentation for match arms -error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:16:5 +error: unused doc comment + --> $DIR/useless_comment.rs:25:5 | -LL | /// foo //~ ERROR doc comment not used by rustdoc - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | /// foo //~ ERROR unused doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe {} + | --------- rustdoc does not generate documentation for expressions -error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:19:5 +error: unused doc comment + --> $DIR/useless_comment.rs:28:5 | -LL | #[doc = "foo"] //~ ERROR doc comment not used by rustdoc +LL | #[doc = "foo"] //~ ERROR unused doc comment | ^^^^^^^^^^^^^^ +LL | #[doc = "bar"] //~ ERROR unused doc comment +LL | 3; + | - rustdoc does not generate documentation for expressions -error: doc comment not used by rustdoc - --> $DIR/useless_comment.rs:20:5 +error: unused doc comment + --> $DIR/useless_comment.rs:29:5 | -LL | #[doc = "bar"] //~ ERROR doc comment not used by rustdoc +LL | #[doc = "bar"] //~ ERROR unused doc comment | ^^^^^^^^^^^^^^ +LL | 3; + | - rustdoc does not generate documentation for expressions + +error: unused doc comment + --> $DIR/useless_comment.rs:32:5 + | +LL | /// bar //~ ERROR unused doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | mac!(); + | ------- rustdoc does not generate documentation for macro expansions + | + = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion + +error: unused doc comment + --> $DIR/useless_comment.rs:35:13 + | +LL | let x = /** comment */ 47; //~ ERROR unused doc comment + | ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions + +error: unused doc comment + --> $DIR/useless_comment.rs:37:5 + | +LL | /// dox //~ ERROR unused doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / { +LL | | +LL | | } + | |_____- rustdoc does not generate documentation for expressions -error: aborting due to 6 previous errors +error: aborting due to 10 previous errors From ac4b685650d1ba0a38806ce8f7cbf12e7a00f573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Tue, 18 Dec 2018 02:22:08 +0100 Subject: [PATCH 12/14] #56411 do not suggest a fix for a import conflict in a macro --- src/librustc_resolve/lib.rs | 4 +++- src/test/ui/issues/issue-56411.rs | 17 +++++++++++++++ src/test/ui/issues/issue-56411.stderr | 31 +++++++++++++++++++++++++++ src/test/ui/issues/issue_56411.rs | 5 +++++ 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-56411.rs create mode 100644 src/test/ui/issues/issue-56411.stderr create mode 100644 src/test/ui/issues/issue_56411.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 4c9347afa611d..8dd09076a00ac 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -5147,11 +5147,13 @@ impl<'a> Resolver<'a> { if let ( Ok(snippet), NameBindingKind::Import { directive, ..}, - _dummy @ false, + false, + false, ) = ( cm.span_to_snippet(binding.span), binding.kind.clone(), binding.span.is_dummy(), + binding.span.ctxt().outer().expn_info().is_some(), ) { let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { format!("Other{}", name) diff --git a/src/test/ui/issues/issue-56411.rs b/src/test/ui/issues/issue-56411.rs new file mode 100644 index 0000000000000..599f277123cc8 --- /dev/null +++ b/src/test/ui/issues/issue-56411.rs @@ -0,0 +1,17 @@ +macro_rules! import { + ( $($name:ident),* ) => { + $( + mod $name; + pub use self::$name; + //~^ ERROR the name `issue_56411` is defined multiple times + //~| ERROR `issue_56411` is private, and cannot be re-exported + + )* + } +} + +import!(issue_56411); + +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/ui/issues/issue-56411.stderr b/src/test/ui/issues/issue-56411.stderr new file mode 100644 index 0000000000000..842d86f4a3a9c --- /dev/null +++ b/src/test/ui/issues/issue-56411.stderr @@ -0,0 +1,31 @@ +error[E0255]: the name `issue_56411` is defined multiple times + --> $DIR/issue-56411.rs:5:21 + | +LL | mod $name; + | ---------- previous definition of the module `issue_56411` here +LL | pub use self::$name; + | ^^^^^^^^^^^ + | | + | `issue_56411` reimported here + | you can use `as` to change the binding name of the import +... +LL | import!(issue_56411); + | --------------------- in this macro invocation + | + = note: `issue_56411` must be defined only once in the type namespace of this module + +error[E0365]: `issue_56411` is private, and cannot be re-exported + --> $DIR/issue-56411.rs:5:21 + | +LL | pub use self::$name; + | ^^^^^^^^^^^ re-export of private `issue_56411` +... +LL | import!(issue_56411); + | --------------------- in this macro invocation + | + = note: consider declaring type or module `issue_56411` with `pub` + +error: aborting due to 2 previous errors + +Some errors occurred: E0255, E0365. +For more information about an error, try `rustc --explain E0255`. diff --git a/src/test/ui/issues/issue_56411.rs b/src/test/ui/issues/issue_56411.rs new file mode 100644 index 0000000000000..bd689e913aba6 --- /dev/null +++ b/src/test/ui/issues/issue_56411.rs @@ -0,0 +1,5 @@ +// compile-pass + +struct T {} + +fn main() {} From 14b36fb15a49bc2d38964ec5bd93ca26adda0486 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 7 Jan 2019 12:41:55 -0800 Subject: [PATCH 13/14] std: Stabilize fixed-width integer atomics This commit stabilizes the `Atomic{I,U}{8,16,32,64}` APIs in the `std::sync::atomic` and `core::sync::atomic` modules. Proposed in #56753 and tracked in #32976 this feature has been unstable for quite some time and is hopefully ready to go over the finish line now! The API is being stabilized as-is. The API of `AtomicU8` and friends mirrors that of `AtomicUsize`. A list of changes made here are: * A portability documentation section has been added to describe the current state of affairs. * Emulation of smaller-size atomics with larger-size atomics has been documented. * As an added bonus, `ATOMIC_*_INIT` is now scheduled for deprecation across the board in 1.34.0 now that `const` functions can be invoked in statics. Note that the 128-bit atomic types are omitted from this stabilization explicitly. They have far less platform support than the other atomic types, and will likely require further discussion about their best location. Closes #32976 Closes #56753 --- src/libcore/sync/atomic.rs | 151 +++++++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 55 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 8992e513e83a4..b9ebf19b23cab 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -5,13 +5,16 @@ //! types. //! //! This module defines atomic versions of a select number of primitive -//! types, including [`AtomicBool`], [`AtomicIsize`], and [`AtomicUsize`]. +//! types, including [`AtomicBool`], [`AtomicIsize`], [`AtomicUsize`], +//! [`AtomicI8`], [`AtomicU16`], etc. //! Atomic types present operations that, when used correctly, synchronize //! updates between threads. //! //! [`AtomicBool`]: struct.AtomicBool.html //! [`AtomicIsize`]: struct.AtomicIsize.html //! [`AtomicUsize`]: struct.AtomicUsize.html +//! [`AtomicI8`]: struct.AtomicI8.html +//! [`AtomicU16`]: struct.AtomicU16.html //! //! Each method takes an [`Ordering`] which represents the strength of //! the memory barrier for that operation. These orderings are the @@ -31,11 +34,46 @@ //! [`Sync`]: ../../marker/trait.Sync.html //! [arc]: ../../../std/sync/struct.Arc.html //! -//! Most atomic types may be stored in static variables, initialized using -//! the provided static initializers like [`ATOMIC_BOOL_INIT`]. Atomic statics +//! Atomic types may be stored in static variables, initialized using +//! the constant initializers like [`AtomicBool::new`]. Atomic statics //! are often used for lazy global initialization. //! -//! [`ATOMIC_BOOL_INIT`]: constant.ATOMIC_BOOL_INIT.html +//! [`AtomicBool::new`]: struct.AtomicBool.html#method.new +//! +//! # Portability +//! +//! All atomic types in this module are guaranteed to be [lock-free] if they're +//! available. This means they don't internally acquire a global mutex. Atomic +//! types and operations are not guaranteed to be wait-free. This means that +//! operations like `fetch_or` may be implemented with a compare-and-swap loop. +//! +//! Atomic operations may be implemented at the instruction layer with +//! larger-size atomics. For example some platforms use 4-byte atomic +//! instructions to implement `AtomicI8`. Note that this emulation should not +//! have an impact on correctness of code, it's just something to be aware of. +//! +//! The atomic types in this module may not be available on all platforms. The +//! atomic types here are all widely available, however, and can generally be +//! relied upon existing. Some notable exceptions are: +//! +//! * PowerPC and MIPS platforms with 32-bit pointers do not have `AtomicU64` or +//! `AtomicI64` types. +//! * ARM platforms like `armv5te` that aren't for Linux do not have any atomics +//! at all. +//! * ARM targets with `thumbv6m` do not have atomic operations at all. +//! +//! Note that future platforms may be added that also do not have support for +//! some atomic operations. Maximally portable code will want to be careful +//! about which atomic types are used. `AtomicUsize` and `AtomicIsize` are +//! generally the most portable, but even then they're not available everywhere. +//! For reference, the `std` library requires pointer-sized atomics, although +//! `core` does not. +//! +//! Currently you'll need to use `#[cfg(target_arch)]` primarily to +//! conditionally compile in code with atomics. There is an unstable +//! `#[cfg(target_has_atomic)]` as well which may be stabilized in the future. +//! +//! [lock-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm //! //! # Examples //! @@ -66,9 +104,9 @@ //! Keep a global count of live threads: //! //! ``` -//! use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; +//! use std::sync::atomic::{AtomicUsize, Ordering}; //! -//! static GLOBAL_THREAD_COUNT: AtomicUsize = ATOMIC_USIZE_INIT; +//! static GLOBAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0); //! //! let old_thread_count = GLOBAL_THREAD_COUNT.fetch_add(1, Ordering::SeqCst); //! println!("live threads: {}", old_thread_count + 1); @@ -252,6 +290,7 @@ pub enum Ordering { /// [`AtomicBool`]: struct.AtomicBool.html #[cfg(target_has_atomic = "8")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(since = "1.34.0", reason = "the `new` function is now preferred")] pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false); #[cfg(target_has_atomic = "8")] @@ -1097,7 +1136,8 @@ macro_rules! atomic_int { /// `]( #[doc = $int_ref] /// ). For more about the differences between atomic types and - /// non-atomic types, please see the [module-level documentation]. + /// non-atomic types as well as information about the portability of + /// this type, please see the [module-level documentation]. /// /// [module-level documentation]: index.html #[$stable] @@ -1108,6 +1148,7 @@ macro_rules! atomic_int { /// An atomic integer initialized to `0`. #[$stable] + #[rustc_deprecated(since = "1.34.0", reason = "the `new` function is now preferred")] pub const $atomic_init: $atomic_type = $atomic_type::new(0); #[$stable] @@ -1827,12 +1868,12 @@ assert_eq!(min_foo, 12); #[cfg(target_has_atomic = "8")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), "i8", "../../../std/primitive.i8.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -1841,12 +1882,12 @@ atomic_int! { } #[cfg(target_has_atomic = "8")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), "u8", "../../../std/primitive.u8.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, @@ -1855,12 +1896,12 @@ atomic_int! { } #[cfg(target_has_atomic = "16")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), "i16", "../../../std/primitive.i16.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -1869,12 +1910,12 @@ atomic_int! { } #[cfg(target_has_atomic = "16")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), "u16", "../../../std/primitive.u16.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, @@ -1883,12 +1924,12 @@ atomic_int! { } #[cfg(target_has_atomic = "32")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), "i32", "../../../std/primitive.i32.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -1897,12 +1938,12 @@ atomic_int! { } #[cfg(target_has_atomic = "32")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), "u32", "../../../std/primitive.u32.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, @@ -1911,12 +1952,12 @@ atomic_int! { } #[cfg(target_has_atomic = "64")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), "i64", "../../../std/primitive.i64.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -1925,12 +1966,12 @@ atomic_int! { } #[cfg(target_has_atomic = "64")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), "u64", "../../../std/primitive.u64.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, From 1b659d69bc0ba7fe534cc26bda8544a558a7d2b2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 26 Jan 2019 00:36:50 +0300 Subject: [PATCH 14/14] Address review comments and cleanup code --- src/librustc_resolve/lib.rs | 93 +++++++++---------- src/test/ui/issues/issue-56411.rs | 6 +- src/test/ui/issues/issue-56411.stderr | 22 ++--- .../{issue_56411.rs => issue_56411_aux.rs} | 0 4 files changed, 59 insertions(+), 62 deletions(-) rename src/test/ui/issues/{issue_56411.rs => issue_56411_aux.rs} (100%) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8dd09076a00ac..873ace9017260 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -5134,62 +5134,59 @@ impl<'a> Resolver<'a> { ); // See https://github.com/rust-lang/rust/issues/32354 - if old_binding.is_import() || new_binding.is_import() { - let binding = if new_binding.is_import() && !new_binding.span.is_dummy() { - new_binding + let directive = match (&new_binding.kind, &old_binding.kind) { + (NameBindingKind::Import { directive, .. }, _) if !new_binding.span.is_dummy() => + Some((directive, new_binding.span)), + (_, NameBindingKind::Import { directive, .. }) if !old_binding.span.is_dummy() => + Some((directive, old_binding.span)), + _ => None, + }; + if let Some((directive, binding_span)) = directive { + let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { + format!("Other{}", name) } else { - old_binding + format!("other_{}", name) }; - let cm = self.session.source_map(); - let rename_msg = "you can use `as` to change the binding name of the import"; - - if let ( - Ok(snippet), - NameBindingKind::Import { directive, ..}, - false, - false, - ) = ( - cm.span_to_snippet(binding.span), - binding.kind.clone(), - binding.span.is_dummy(), - binding.span.ctxt().outer().expn_info().is_some(), - ) { - let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { - format!("Other{}", name) - } else { - format!("other_{}", name) - }; + let mut suggestion = None; + match directive.subclass { + ImportDirectiveSubclass::SingleImport { type_ns_only: true, .. } => + suggestion = Some(format!("self as {}", suggested_name)), + ImportDirectiveSubclass::SingleImport { source, .. } => { + if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0) + .map(|pos| pos as usize) { + if let Ok(snippet) = self.session.source_map() + .span_to_snippet(binding_span) { + if pos <= snippet.len() { + suggestion = Some(format!( + "{} as {}{}", + &snippet[..pos], + suggested_name, + if snippet.ends_with(";") { ";" } else { "" } + )) + } + } + } + } + ImportDirectiveSubclass::ExternCrate { source, target, .. } => + suggestion = Some(format!( + "extern crate {} as {};", + source.unwrap_or(target.name), + suggested_name, + )), + _ => unreachable!(), + } + let rename_msg = "you can use `as` to change the binding name of the import"; + if let Some(suggestion) = suggestion { err.span_suggestion_with_applicability( - binding.span, - &rename_msg, - match directive.subclass { - ImportDirectiveSubclass::SingleImport { type_ns_only: true, .. } => - format!("self as {}", suggested_name), - ImportDirectiveSubclass::SingleImport { source, .. } => - format!( - "{} as {}{}", - &snippet[..((source.span.hi().0 - binding.span.lo().0) as usize)], - suggested_name, - if snippet.ends_with(";") { - ";" - } else { - "" - } - ), - ImportDirectiveSubclass::ExternCrate { source, target, .. } => - format!( - "extern crate {} as {};", - source.unwrap_or(target.name), - suggested_name, - ), - _ => unreachable!(), - }, + binding_span, + rename_msg, + suggestion, Applicability::MaybeIncorrect, ); } else { - err.span_label(binding.span, rename_msg); + err.span_label(binding_span, rename_msg); } } diff --git a/src/test/ui/issues/issue-56411.rs b/src/test/ui/issues/issue-56411.rs index 599f277123cc8..3561c21cc7ee3 100644 --- a/src/test/ui/issues/issue-56411.rs +++ b/src/test/ui/issues/issue-56411.rs @@ -3,14 +3,14 @@ macro_rules! import { $( mod $name; pub use self::$name; - //~^ ERROR the name `issue_56411` is defined multiple times - //~| ERROR `issue_56411` is private, and cannot be re-exported + //~^ ERROR the name `issue_56411_aux` is defined multiple times + //~| ERROR `issue_56411_aux` is private, and cannot be re-exported )* } } -import!(issue_56411); +import!(issue_56411_aux); fn main() { println!("Hello, world!"); diff --git a/src/test/ui/issues/issue-56411.stderr b/src/test/ui/issues/issue-56411.stderr index 842d86f4a3a9c..dd05852c09159 100644 --- a/src/test/ui/issues/issue-56411.stderr +++ b/src/test/ui/issues/issue-56411.stderr @@ -1,29 +1,29 @@ -error[E0255]: the name `issue_56411` is defined multiple times +error[E0255]: the name `issue_56411_aux` is defined multiple times --> $DIR/issue-56411.rs:5:21 | LL | mod $name; - | ---------- previous definition of the module `issue_56411` here + | ---------- previous definition of the module `issue_56411_aux` here LL | pub use self::$name; | ^^^^^^^^^^^ | | - | `issue_56411` reimported here + | `issue_56411_aux` reimported here | you can use `as` to change the binding name of the import ... -LL | import!(issue_56411); - | --------------------- in this macro invocation +LL | import!(issue_56411_aux); + | ------------------------- in this macro invocation | - = note: `issue_56411` must be defined only once in the type namespace of this module + = note: `issue_56411_aux` must be defined only once in the type namespace of this module -error[E0365]: `issue_56411` is private, and cannot be re-exported +error[E0365]: `issue_56411_aux` is private, and cannot be re-exported --> $DIR/issue-56411.rs:5:21 | LL | pub use self::$name; - | ^^^^^^^^^^^ re-export of private `issue_56411` + | ^^^^^^^^^^^ re-export of private `issue_56411_aux` ... -LL | import!(issue_56411); - | --------------------- in this macro invocation +LL | import!(issue_56411_aux); + | ------------------------- in this macro invocation | - = note: consider declaring type or module `issue_56411` with `pub` + = note: consider declaring type or module `issue_56411_aux` with `pub` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue_56411.rs b/src/test/ui/issues/issue_56411_aux.rs similarity index 100% rename from src/test/ui/issues/issue_56411.rs rename to src/test/ui/issues/issue_56411_aux.rs