diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 3eee45a9230d1..c9dc5a0f3b5ec 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -3,7 +3,7 @@ use super::{AllocId, InterpResult}; use rustc_macros::HashStable; use rustc_target::abi::{HasDataLayout, Size}; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::fmt; //////////////////////////////////////////////////////////////////////////////// @@ -20,29 +20,27 @@ pub trait PointerArithmetic: HasDataLayout { #[inline] fn machine_usize_max(&self) -> u64 { - let max_usize_plus_1 = 1u128 << self.pointer_size().bits(); - u64::try_from(max_usize_plus_1 - 1).unwrap() + self.pointer_size().unsigned_int_max().try_into().unwrap() } #[inline] fn machine_isize_min(&self) -> i64 { - let max_isize_plus_1 = 1i128 << (self.pointer_size().bits() - 1); - i64::try_from(-max_isize_plus_1).unwrap() + self.pointer_size().signed_int_min().try_into().unwrap() } #[inline] fn machine_isize_max(&self) -> i64 { - let max_isize_plus_1 = 1u128 << (self.pointer_size().bits() - 1); - i64::try_from(max_isize_plus_1 - 1).unwrap() + self.pointer_size().signed_int_max().try_into().unwrap() } #[inline] fn machine_usize_to_isize(&self, val: u64) -> i64 { let val = val as i64; - // Now clamp into the machine_isize range. + // Now wrap-around into the machine_isize range. if val > self.machine_isize_max() { // This can only happen the the ptr size is < 64, so we know max_usize_plus_1 fits into // i64. + debug_assert!(self.pointer_size().bits() < 64); let max_usize_plus_1 = 1u128 << self.pointer_size().bits(); val - i64::try_from(max_usize_plus_1).unwrap() } else { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 10c73fd64bc19..04a7948e8c96e 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -493,7 +493,20 @@ impl<'a> Parser<'a> { let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt) { let span = self.prev_token.span.between(self.token.span); - self.struct_span_err(span, "missing trait in a trait impl").emit(); + self.struct_span_err(span, "missing trait in a trait impl") + .span_suggestion( + span, + "add a trait here", + " Trait ".into(), + Applicability::HasPlaceholders, + ) + .span_suggestion( + span.to(self.token.span), + "for an inherent impl, drop this `for`", + "".into(), + Applicability::MaybeIncorrect, + ) + .emit(); P(Ty { kind: TyKind::Path(None, err_path(span)), span, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index f5be8bf0949e6..8adf9015933c3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1487,10 +1487,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) => false, (ParamCandidate(other), ParamCandidate(victim)) => { - let value_same_except_bound_vars = other.value.skip_binder() + let same_except_bound_vars = other.value.skip_binder() == victim.value.skip_binder() + && other.constness == victim.constness && !other.value.skip_binder().has_escaping_bound_vars(); - if value_same_except_bound_vars { + if same_except_bound_vars { // See issue #84398. In short, we can generate multiple ParamCandidates which are // the same except for unused bound vars. Just pick the one with the fewest bound vars // or the current one if tied (they should both evaluate to the same answer). This is diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 2adf6a549e641..e56b631dbaf8d 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1916,7 +1916,8 @@ impl UnsafeCell { /// ``` #[inline(always)] #[stable(feature = "unsafe_cell_get_mut", since = "1.50.0")] - pub fn get_mut(&mut self) -> &mut T { + #[rustc_const_unstable(feature = "const_unsafecell_get_mut", issue = "88836")] + pub const fn get_mut(&mut self) -> &mut T { &mut self.value } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index d12e86b7c1deb..386ffb384a81e 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -925,6 +925,11 @@ impl Step for RustdocGUI { .env("RUSTDOC", builder.rustdoc(self.compiler)) .env("RUSTC", builder.rustc(self.compiler)) .current_dir(path); + // FIXME: implement a `// compile-flags` command or similar + // instead of hard-coding this test + if entry.file_name() == "link_to_definition" { + cargo.env("RUSTDOCFLAGS", "-Zunstable-options --generate-link-to-definition"); + } builder.run(&mut cargo); } } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index f8fc9243e14b9..ece3ee640e2a6 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -5,6 +5,7 @@ //! //! Use the `render_with_highlighting` to highlight some rust code. +use crate::clean::PrimitiveType; use crate::html::escape::Escape; use crate::html::render::Context; @@ -584,6 +585,13 @@ fn string( .ok() .map(|(url, _, _)| url) } + LinkFromSrc::Primitive(prim) => format::href_with_root_path( + PrimitiveType::primitive_locations(context.tcx())[&prim], + context, + Some(context_info.root_path), + ) + .ok() + .map(|(url, _, _)| url), } }) { diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 54476d9c9a459..d517f3ac0e3a9 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -1,4 +1,4 @@ -use crate::clean; +use crate::clean::{self, PrimitiveType}; use crate::html::sources; use rustc_data_structures::fx::FxHashMap; @@ -22,6 +22,7 @@ use std::path::{Path, PathBuf}; crate enum LinkFromSrc { Local(clean::Span), External(DefId), + Primitive(PrimitiveType), } /// This function will do at most two things: @@ -73,17 +74,20 @@ impl<'tcx> SpanMapVisitor<'tcx> { Some(def_id) } Res::Local(_) => None, + Res::PrimTy(p) => { + // FIXME: Doesn't handle "path-like" primitives like arrays or tuples. + let span = path_span.unwrap_or(path.span); + self.matches.insert(span, LinkFromSrc::Primitive(PrimitiveType::from(p))); + return; + } Res::Err => return, _ => return, }; if let Some(span) = self.tcx.hir().res_span(path.res) { - self.matches.insert( - path_span.unwrap_or_else(|| path.span), - LinkFromSrc::Local(clean::Span::new(span)), - ); - } else if let Some(def_id) = info { self.matches - .insert(path_span.unwrap_or_else(|| path.span), LinkFromSrc::External(def_id)); + .insert(path_span.unwrap_or(path.span), LinkFromSrc::Local(clean::Span::new(span))); + } else if let Some(def_id) = info { + self.matches.insert(path_span.unwrap_or(path.span), LinkFromSrc::External(def_id)); } } } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index f9ddef4120bbe..eada8f4a04dae 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -217,7 +217,7 @@ a { color: #c5c5c5; } body.source .example-wrap pre.rust a { - background: #c5c5c5; + background: #333; } .docblock:not(.type-decl) a:not(.srclink):not(.test-arrow), diff --git a/src/test/rustdoc-gui/code-sidebar-toggle.goml b/src/test/rustdoc-gui/code-sidebar-toggle.goml index 00326e9bbc4cc..6fb92e196602e 100644 --- a/src/test/rustdoc-gui/code-sidebar-toggle.goml +++ b/src/test/rustdoc-gui/code-sidebar-toggle.goml @@ -1,5 +1,6 @@ goto: file://|DOC_PATH|/test_docs/index.html click: ".srclink" +wait-for: "#sidebar-toggle" click: "#sidebar-toggle" wait-for: 500 fail: true diff --git a/src/test/rustdoc-gui/jump-to-def-background.goml b/src/test/rustdoc-gui/jump-to-def-background.goml new file mode 100644 index 0000000000000..3df899e0f2618 --- /dev/null +++ b/src/test/rustdoc-gui/jump-to-def-background.goml @@ -0,0 +1,23 @@ +// We check the background color on the jump to definition links in the source code page. +goto: file://|DOC_PATH|/src/link_to_definition/lib.rs.html + +// Set the theme to dark. +local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: ("body.source .example-wrap pre.rust a", {"background-color": "rgb(51, 51, 51)"}, ALL) + +// Set the theme to ayu. +local-storage: {"rustdoc-theme": "ayu", "rustdoc-preferred-dark-theme": "ayu", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: ("body.source .example-wrap pre.rust a", {"background-color": "rgb(51, 51, 51)"}, ALL) + +// Set the theme to light. +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: ("body.source .example-wrap pre.rust a", {"background-color": "rgb(238, 238, 238)"}, ALL) diff --git a/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock b/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock new file mode 100644 index 0000000000000..e4b4e52d028e5 --- /dev/null +++ b/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "link_to_definition" +version = "0.1.0" diff --git a/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml b/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml new file mode 100644 index 0000000000000..cdd294d74d3ae --- /dev/null +++ b/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "link_to_definition" +version = "0.1.0" +edition = "2018" + +[lib] +path = "lib.rs" diff --git a/src/test/rustdoc-gui/src/link_to_definition/lib.rs b/src/test/rustdoc-gui/src/link_to_definition/lib.rs new file mode 100644 index 0000000000000..de9ee66a2bad0 --- /dev/null +++ b/src/test/rustdoc-gui/src/link_to_definition/lib.rs @@ -0,0 +1,6 @@ +pub struct Bar { + pub a: String, + pub b: u32, +} + +pub fn foo(_b: &Bar) {} diff --git a/src/test/rustdoc/check-source-code-urls-to-def-std.rs b/src/test/rustdoc/check-source-code-urls-to-def-std.rs new file mode 100644 index 0000000000000..b129ceb5b7302 --- /dev/null +++ b/src/test/rustdoc/check-source-code-urls-to-def-std.rs @@ -0,0 +1,17 @@ +// compile-flags: -Zunstable-options --generate-link-to-definition + +#![crate_name = "foo"] + +// @has 'src/foo/check-source-code-urls-to-def-std.rs.html' + +fn babar() {} + +// @has - '//a[@href="{{channel}}/std/primitive.u32.html"]' 'u32' +// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str' +// @has - '//a[@href="{{channel}}/std/primitive.bool.html"]' 'bool' +// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#7"]' 'babar' +pub fn foo(a: u32, b: &str, c: String) { + let x = 12; + let y: bool = true; + babar(); +} diff --git a/src/test/rustdoc/check-source-code-urls-to-def.rs b/src/test/rustdoc/check-source-code-urls-to-def.rs index e3ae79ccdb17a..0cb8e4230166f 100644 --- a/src/test/rustdoc/check-source-code-urls-to-def.rs +++ b/src/test/rustdoc/check-source-code-urls-to-def.rs @@ -27,6 +27,8 @@ impl Foo { fn babar() {} // @has - '//a/@href' '/struct.String.html' +// @has - '//a/@href' '/primitive.u32.html' +// @has - '//a/@href' '/primitive.str.html' // @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#21"]' 5 // @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode' pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) { @@ -40,5 +42,9 @@ pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::Sour // @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'bar::sub::Trait' // @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'Trait' -pub fn foo2(t: &T, v: &V) { +pub fn foo2(t: &T, v: &V, b: bool) { } + +// @has - '//a[@href="../../foo/primitive.bool.html"]' 'bool' +#[doc(primitive = "bool")] +mod whatever {} diff --git a/src/test/ui/issues/issue-56031.stderr b/src/test/ui/issues/issue-56031.stderr index 3d7acee0a56eb..7ee5bc6ec6174 100644 --- a/src/test/ui/issues/issue-56031.stderr +++ b/src/test/ui/issues/issue-56031.stderr @@ -3,6 +3,16 @@ error: missing trait in a trait impl | LL | impl for T {} | ^ + | +help: add a trait here + | +LL | impl Trait for T {} + | +++++ +help: for an inherent impl, drop this `for` + | +LL - impl for T {} +LL + impl T {} + | error: aborting due to previous error diff --git a/src/test/ui/parser/issue-88818.rs b/src/test/ui/parser/issue-88818.rs new file mode 100644 index 0000000000000..b9233ca8339e1 --- /dev/null +++ b/src/test/ui/parser/issue-88818.rs @@ -0,0 +1,10 @@ +// Regression test for #88818 (improve error message for missing trait +// in `impl for X`). + +struct S { } +impl for S { } +//~^ ERROR: missing trait in a trait impl +//~| HELP: add a trait here +//~| HELP: for an inherent impl, drop this `for` + +fn main() {} diff --git a/src/test/ui/parser/issue-88818.stderr b/src/test/ui/parser/issue-88818.stderr new file mode 100644 index 0000000000000..d30990ae5820f --- /dev/null +++ b/src/test/ui/parser/issue-88818.stderr @@ -0,0 +1,18 @@ +error: missing trait in a trait impl + --> $DIR/issue-88818.rs:5:5 + | +LL | impl for S { } + | ^ + | +help: add a trait here + | +LL | impl Trait for S { } + | +++++ +help: for an inherent impl, drop this `for` + | +LL - impl for S { } +LL + impl S { } + | + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs index 7185376b440c8..cc24dbd96d253 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs @@ -16,12 +16,17 @@ impl const PartialEq for S { // This duplicate bound should not result in ambiguities. It should be equivalent to a single ~const // bound. -// const fn equals_self(t: &T) -> bool { -// FIXME(fee1-dead)^ why should the order matter here? -const fn equals_self(t: &T) -> bool { +const fn equals_self(t: &T) -> bool { *t == *t } -pub const EQ: bool = equals_self(&S); +trait A: PartialEq {} +impl A for T {} + +const fn equals_self2(t: &T) -> bool { + *t == *t +} + +pub const EQ: bool = equals_self(&S) && equals_self2(&S); fn main() {}