diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 7ebb1e85cdb23..f942970278399 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -790,6 +790,7 @@ declare_lint! { /// ### Example /// /// ```rust + /// #[warn(unused_macro_rules)] /// macro_rules! unused_empty { /// (hello) => { println!("Hello, world!") }; // This rule is unused /// () => { println!("empty") }; // This rule is used @@ -814,7 +815,7 @@ declare_lint! { /// /// [`macro_export` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope pub UNUSED_MACRO_RULES, - Warn, + Allow, "detects macro rules that were not used" } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 2a49017de3cc8..fa0206c349af6 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -194,10 +194,10 @@ use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; -use crate::marker::Unsize; +use crate::marker::{PhantomData, Unsize}; use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut}; -use crate::ptr; +use crate::ptr::{self, NonNull}; /// A mutable memory location. /// @@ -896,7 +896,8 @@ impl RefCell { // SAFETY: `BorrowRef` ensures that there is only immutable access // to the value while borrowed. - Ok(Ref { value: unsafe { &*self.value.get() }, borrow: b }) + let value = unsafe { NonNull::new_unchecked(self.value.get()) }; + Ok(Ref { value, borrow: b }) } None => Err(BorrowError { // If a borrow occurred, then we must already have an outstanding borrow, @@ -980,8 +981,9 @@ impl RefCell { self.borrowed_at.set(Some(crate::panic::Location::caller())); } - // SAFETY: `BorrowRef` guarantees unique access. - Ok(RefMut { value: unsafe { &mut *self.value.get() }, borrow: b }) + // SAFETY: `BorrowRefMut` guarantees unique access. + let value = unsafe { NonNull::new_unchecked(self.value.get()) }; + Ok(RefMut { value, borrow: b, marker: PhantomData }) } None => Err(BorrowMutError { // If a borrow occurred, then we must already have an outstanding borrow, @@ -1314,7 +1316,9 @@ impl Clone for BorrowRef<'_> { #[stable(feature = "rust1", since = "1.0.0")] #[must_not_suspend = "holding a Ref across suspend points can cause BorrowErrors"] pub struct Ref<'b, T: ?Sized + 'b> { - value: &'b T, + // NB: we use a pointer instead of `&'b T` to avoid `noalias` violations, because a + // `Ref` argument doesn't hold immutability for its whole scope, only until it drops. + value: NonNull, borrow: BorrowRef<'b>, } @@ -1324,7 +1328,8 @@ impl Deref for Ref<'_, T> { #[inline] fn deref(&self) -> &T { - self.value + // SAFETY: the value is accessible as long as we hold our borrow. + unsafe { self.value.as_ref() } } } @@ -1368,7 +1373,7 @@ impl<'b, T: ?Sized> Ref<'b, T> { where F: FnOnce(&T) -> &U, { - Ref { value: f(orig.value), borrow: orig.borrow } + Ref { value: NonNull::from(f(&*orig)), borrow: orig.borrow } } /// Makes a new `Ref` for an optional component of the borrowed data. The @@ -1399,8 +1404,8 @@ impl<'b, T: ?Sized> Ref<'b, T> { where F: FnOnce(&T) -> Option<&U>, { - match f(orig.value) { - Some(value) => Ok(Ref { value, borrow: orig.borrow }), + match f(&*orig) { + Some(value) => Ok(Ref { value: NonNull::from(value), borrow: orig.borrow }), None => Err(orig), } } @@ -1431,9 +1436,12 @@ impl<'b, T: ?Sized> Ref<'b, T> { where F: FnOnce(&T) -> (&U, &V), { - let (a, b) = f(orig.value); + let (a, b) = f(&*orig); let borrow = orig.borrow.clone(); - (Ref { value: a, borrow }, Ref { value: b, borrow: orig.borrow }) + ( + Ref { value: NonNull::from(a), borrow }, + Ref { value: NonNull::from(b), borrow: orig.borrow }, + ) } /// Convert into a reference to the underlying data. @@ -1467,7 +1475,8 @@ impl<'b, T: ?Sized> Ref<'b, T> { // unique reference to the borrowed RefCell. No further mutable references can be created // from the original cell. mem::forget(orig.borrow); - orig.value + // SAFETY: after forgetting, we can form a reference for the rest of lifetime `'b`. + unsafe { orig.value.as_ref() } } } @@ -1507,13 +1516,13 @@ impl<'b, T: ?Sized> RefMut<'b, T> { /// ``` #[stable(feature = "cell_map", since = "1.8.0")] #[inline] - pub fn map(orig: RefMut<'b, T>, f: F) -> RefMut<'b, U> + pub fn map(mut orig: RefMut<'b, T>, f: F) -> RefMut<'b, U> where F: FnOnce(&mut T) -> &mut U, { // FIXME(nll-rfc#40): fix borrow-check - let RefMut { value, borrow } = orig; - RefMut { value: f(value), borrow } + let value = NonNull::from(f(&mut *orig)); + RefMut { value, borrow: orig.borrow, marker: PhantomData } } /// Makes a new `RefMut` for an optional component of the borrowed data. The @@ -1548,23 +1557,20 @@ impl<'b, T: ?Sized> RefMut<'b, T> { /// ``` #[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")] #[inline] - pub fn filter_map(orig: RefMut<'b, T>, f: F) -> Result, Self> + pub fn filter_map(mut orig: RefMut<'b, T>, f: F) -> Result, Self> where F: FnOnce(&mut T) -> Option<&mut U>, { // FIXME(nll-rfc#40): fix borrow-check - let RefMut { value, borrow } = orig; - let value = value as *mut T; // SAFETY: function holds onto an exclusive reference for the duration // of its call through `orig`, and the pointer is only de-referenced // inside of the function call never allowing the exclusive reference to // escape. - match f(unsafe { &mut *value }) { - Some(value) => Ok(RefMut { value, borrow }), - None => { - // SAFETY: same as above. - Err(RefMut { value: unsafe { &mut *value }, borrow }) + match f(&mut *orig) { + Some(value) => { + Ok(RefMut { value: NonNull::from(value), borrow: orig.borrow, marker: PhantomData }) } + None => Err(orig), } } @@ -1596,15 +1602,18 @@ impl<'b, T: ?Sized> RefMut<'b, T> { #[stable(feature = "refcell_map_split", since = "1.35.0")] #[inline] pub fn map_split( - orig: RefMut<'b, T>, + mut orig: RefMut<'b, T>, f: F, ) -> (RefMut<'b, U>, RefMut<'b, V>) where F: FnOnce(&mut T) -> (&mut U, &mut V), { - let (a, b) = f(orig.value); let borrow = orig.borrow.clone(); - (RefMut { value: a, borrow }, RefMut { value: b, borrow: orig.borrow }) + let (a, b) = f(&mut *orig); + ( + RefMut { value: NonNull::from(a), borrow, marker: PhantomData }, + RefMut { value: NonNull::from(b), borrow: orig.borrow, marker: PhantomData }, + ) } /// Convert into a mutable reference to the underlying data. @@ -1630,14 +1639,15 @@ impl<'b, T: ?Sized> RefMut<'b, T> { /// assert!(cell.try_borrow_mut().is_err()); /// ``` #[unstable(feature = "cell_leak", issue = "69099")] - pub fn leak(orig: RefMut<'b, T>) -> &'b mut T { + pub fn leak(mut orig: RefMut<'b, T>) -> &'b mut T { // By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell can't // go back to UNUSED within the lifetime `'b`. Resetting the reference tracking state would // require a unique reference to the borrowed RefCell. No further references can be created // from the original cell within that lifetime, making the current borrow the only // reference for the remaining lifetime. mem::forget(orig.borrow); - orig.value + // SAFETY: after forgetting, we can form a reference for the rest of lifetime `'b`. + unsafe { orig.value.as_mut() } } } @@ -1692,8 +1702,12 @@ impl<'b> BorrowRefMut<'b> { #[stable(feature = "rust1", since = "1.0.0")] #[must_not_suspend = "holding a RefMut across suspend points can cause BorrowErrors"] pub struct RefMut<'b, T: ?Sized + 'b> { - value: &'b mut T, + // NB: we use a pointer instead of `&'b mut T` to avoid `noalias` violations, because a + // `RefMut` argument doesn't hold exclusivity for its whole scope, only until it drops. + value: NonNull, borrow: BorrowRefMut<'b>, + // NonNull is covariant over T, so we need to reintroduce invariance. + marker: PhantomData<&'b mut T>, } #[stable(feature = "rust1", since = "1.0.0")] @@ -1702,7 +1716,8 @@ impl Deref for RefMut<'_, T> { #[inline] fn deref(&self) -> &T { - self.value + // SAFETY: the value is accessible as long as we hold our borrow. + unsafe { self.value.as_ref() } } } @@ -1710,7 +1725,8 @@ impl Deref for RefMut<'_, T> { impl DerefMut for RefMut<'_, T> { #[inline] fn deref_mut(&mut self) -> &mut T { - self.value + // SAFETY: the value is accessible as long as we hold our borrow. + unsafe { self.value.as_mut() } } } diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md index 098bc1879b56f..d666d54b31579 100644 --- a/src/doc/rustdoc/src/how-to-read-rustdoc.md +++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md @@ -59,15 +59,8 @@ or the current item whose documentation is being displayed. ## The Theme Picker and Search Interface When viewing `rustdoc`'s output in a browser with JavaScript enabled, -a dynamic interface appears at the top of the page. -To the left is the theme picker, denoted with a paint-brush icon, -and the search interface, help screen, and options appear to the right of that. - -### The Theme Picker - -Clicking on the theme picker provides a list of themes - -by default `ayu`, `light`, and `dark` - -which are available for viewing. +a dynamic interface appears at the top of the page composed of the search +interface, help screen, and options. ### The Search Interface @@ -91,12 +84,16 @@ When typing in the search bar, you can prefix your search term with a type followed by a colon (such as `mod:`) to restrict the results to just that kind of item. (The available items are listed in the help popup.) +### Changing displayed theme + +You can change the displayed theme by opening the settings menu (the gear +icon in the upper right) and then pick a new one from there. + ### Shortcuts Pressing `S` while focused elsewhere on the page will move focus to the search bar, and pressing `?` shows the help screen, which includes all these shortcuts and more. -Pressing `T` focuses the theme picker. When the search results are focused, the left and right arrows move between tabs and the up and down arrows move diff --git a/src/doc/rustdoc/src/write-documentation/what-to-include.md b/src/doc/rustdoc/src/write-documentation/what-to-include.md index 35e6ccbc38807..e1e09aa4a8ada 100644 --- a/src/doc/rustdoc/src/write-documentation/what-to-include.md +++ b/src/doc/rustdoc/src/write-documentation/what-to-include.md @@ -109,8 +109,9 @@ rustdoc --extend-css custom.css src/lib.rs A good example of using this feature to create a dark theme is documented [on this blog]. Just remember, dark theme is already included in the rustdoc output -by clicking on the paintbrush. Adding additional options to the themes are -as easy as creating a custom theme `.css` file and using the following syntax: +by clicking on the gear icon in the upper right. Adding additional options to the +themes are as easy as creating a custom theme `.css` file and using the following +syntax: ```bash rustdoc --theme awesome.css src/lib.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 56a085c298250..5ba3bdc12eda6 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1448,8 +1448,6 @@ fn init_id_map() -> FxHashMap, usize> { // used in tera template files). map.insert("mainThemeStyle".into(), 1); map.insert("themeStyle".into(), 1); - map.insert("theme-picker".into(), 1); - map.insert("theme-choices".into(), 1); map.insert("settings-menu".into(), 1); map.insert("help-button".into(), 1); map.insert("main-content".into(), 1); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 68f2a54ddeb05..702bccb45cf93 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -238,7 +238,6 @@ pub(super) fn write_shared( write_toolchain("favicon-16x16.png", static_files::RUST_FAVICON_PNG_16)?; write_toolchain("favicon-32x32.png", static_files::RUST_FAVICON_PNG_32)?; } - write_toolchain("brush.svg", static_files::BRUSH_SVG)?; write_toolchain("wheel.svg", static_files::WHEEL_SVG)?; write_toolchain("clipboard.svg", static_files::CLIPBOARD_SVG)?; write_toolchain("down-arrow.svg", static_files::DOWN_ARROW_SVG)?; diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js index 52577b228aa13..7634a15b9bd19 100644 --- a/src/librustdoc/html/static/.eslintrc.js +++ b/src/librustdoc/html/static/.eslintrc.js @@ -29,5 +29,10 @@ module.exports = { "no-var": ["error"], "prefer-const": ["error"], "prefer-arrow-callback": ["error"], + "brace-style": [ + "error", + "1tbs", + { "allowSingleLine": false } + ], } }; diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index e35358c564993..0a19a99abf054 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -18,7 +18,3 @@ rules. /* The search bar and related controls don't work without JS */ display: none; } - -#theme-picker { - display: none; -} diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 0f4d842f4336d..38e67c233d698 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1379,31 +1379,30 @@ pre.rust { margin-bottom: 6px; } -.theme-picker { - position: absolute; - left: -38px; - top: 4px; -} - -.theme-picker button { - outline: none; -} - #settings-menu, #help-button { margin-left: 4px; outline: none; } -#theme-picker, #copy-path { +#copy-path { height: 34px; } -#theme-picker, #settings-menu, #help-button, #copy-path { +#settings-menu > a, #help-button, #copy-path { padding: 5px; width: 33px; border: 1px solid; border-radius: 2px; cursor: pointer; } +#settings-menu { + padding: 0; +} +#settings-menu > a { + padding: 5px; + width: 100%; + height: 100%; + display: block; +} @keyframes rotating { from { @@ -1413,9 +1412,33 @@ pre.rust { transform: rotate(360deg); } } -#settings-menu.rotate img { +#settings-menu.rotate > a img { animation: rotating 2s linear infinite; } +#settings-menu #settings { + position: absolute; + right: 0; + z-index: 1; + display: block; + margin-top: 7px; + border-radius: 3px; + border: 1px solid; +} +#settings-menu #settings .setting-line { + margin: 0.6em; +} +/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */ +#settings-menu #settings::before { + content: ''; + position: absolute; + right: 11px; + border: solid; + border-width: 1px 1px 0 0; + display: inline-block; + padding: 4px; + transform: rotate(-45deg); + top: -5px; +} #help-button { font-family: "Fira Sans", Arial, sans-serif; @@ -1838,12 +1861,6 @@ details.rustdoc-toggle[open] > summary.hideme::after { margin-left: 32px; } - /* Space is at a premium on mobile, so remove the theme-picker icon. */ - #theme-picker { - display: none; - width: 0; - } - .content { margin-left: 0px; } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index b1bf06c1865c7..ea0cb5e072696 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -5,7 +5,7 @@ Original by Dempfi (https://github.com/dempfi/ayu) /* General structure and fonts */ -body { +body, #settings-menu #settings, #settings-menu #settings::before { background-color: #0f1419; color: #c5c5c5; } @@ -531,16 +531,20 @@ kbd { box-shadow: inset 0 -1px 0 #5c6773; } -#theme-picker, #settings-menu, #help-button { +#settings-menu > a, #help-button { border-color: #5c6773; background-color: #0f1419; color: #fff; } -#theme-picker > img, #settings-menu > img { +#settings-menu > a img { filter: invert(100); } +#settings-menu #settings, #settings-menu #settings::before { + border-color: #5c6773; +} + #copy-path { color: #fff; } @@ -551,8 +555,7 @@ kbd { filter: invert(100%); } -#theme-picker:hover, #theme-picker:focus, -#settings-menu:hover, #settings-menu:focus, +#settings-menu > a:hover, #settings-menu > a:focus, #help-button:hover, #help-button:focus { border-color: #e0e0e0; } @@ -570,12 +573,6 @@ kbd { background-color: rgba(110, 110, 110, 0.33); } -@media (max-width: 700px) { - #theme-picker { - background: #0f1419; - } -} - .search-results .result-name span.alias { color: #c5c5c5; } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 236304ccc9f1b..1525163f50281 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -1,4 +1,4 @@ -body { +body, #settings-menu #settings, #settings-menu #settings::before { background-color: #353535; color: #ddd; } @@ -408,18 +408,21 @@ kbd { box-shadow: inset 0 -1px 0 #c6cbd1; } -#theme-picker, #settings-menu, #help-button { +#settings-menu > a, #help-button { border-color: #e0e0e0; background: #f0f0f0; color: #000; } -#theme-picker:hover, #theme-picker:focus, -#settings-menu:hover, #settings-menu:focus, +#settings-menu > a:hover, #settings-menu > a:focus, #help-button:hover, #help-button:focus { border-color: #ffb900; } +#settings-menu #settings, #settings-menu #settings::before { + border-color: #d2d2d2; +} + #copy-path { color: #999; } @@ -443,12 +446,6 @@ kbd { background-color: #4e4e4e; } -@media (max-width: 700px) { - #theme-picker { - background: #f0f0f0; - } -} - .search-results .result-name span.alias { color: #fff; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index c923902aba2d3..d36a088d38e3f 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -1,6 +1,6 @@ /* General structure and fonts */ -body { +body, #settings-menu #settings, #settings-menu #settings::before { background-color: white; color: black; } @@ -394,17 +394,20 @@ kbd { box-shadow: inset 0 -1px 0 #c6cbd1; } -#theme-picker, #settings-menu, #help-button { +#settings-menu > a, #help-button { border-color: #e0e0e0; background-color: #fff; } -#theme-picker:hover, #theme-picker:focus, -#settings-menu:hover, #settings-menu:focus, +#settings-menu > a:hover, #settings-menu > a:focus, #help-button:hover, #help-button:focus { border-color: #717171; } +#settings-menu #settings, #settings-menu #settings::before { + border-color: #DDDDDD; +} + #copy-path { color: #999; } @@ -428,12 +431,6 @@ kbd { background-color: #eee; } -@media (max-width: 700px) { - #theme-picker { - background: #fff; - } -} - .search-results .result-name span.alias { color: #000; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 336223ad28f32..454c7f557b9bc 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1,7 +1,6 @@ // Local js definitions: /* global addClass, getSettingValue, hasClass, searchState */ /* global onEach, onEachLazy, removeClass */ -/* global switchTheme, useSystemTheme */ "use strict"; @@ -109,21 +108,11 @@ function getVirtualKey(ev) { return String.fromCharCode(c); } -const THEME_PICKER_ELEMENT_ID = "theme-picker"; -const THEMES_ELEMENT_ID = "theme-choices"; const MAIN_ID = "main-content"; const SETTINGS_BUTTON_ID = "settings-menu"; const ALTERNATIVE_DISPLAY_ID = "alternative-display"; const NOT_DISPLAYED_ID = "not-displayed"; -function getThemesElement() { - return document.getElementById(THEMES_ELEMENT_ID); -} - -function getThemePickerElement() { - return document.getElementById(THEME_PICKER_ELEMENT_ID); -} - function getSettingsButton() { return document.getElementById(SETTINGS_BUTTON_ID); } @@ -133,74 +122,10 @@ function getNakedUrl() { return window.location.href.split("?")[0].split("#")[0]; } -function showThemeButtonState() { - const themePicker = getThemePickerElement(); - const themeChoices = getThemesElement(); - - themeChoices.style.display = "block"; - themePicker.style.borderBottomRightRadius = "0"; - themePicker.style.borderBottomLeftRadius = "0"; -} - -function hideThemeButtonState() { - const themePicker = getThemePickerElement(); - const themeChoices = getThemesElement(); - - themeChoices.style.display = "none"; - themePicker.style.borderBottomRightRadius = "3px"; - themePicker.style.borderBottomLeftRadius = "3px"; -} - window.hideSettings = () => { // Does nothing by default. }; -// Set up the theme picker list. -(function () { - if (!document.location.href.startsWith("file:///")) { - return; - } - const themeChoices = getThemesElement(); - const themePicker = getThemePickerElement(); - const availableThemes = getVar("themes").split(","); - - removeClass(themeChoices.parentElement, "hidden"); - - function switchThemeButtonState() { - if (themeChoices.style.display === "block") { - hideThemeButtonState(); - } else { - showThemeButtonState(); - } - } - - function handleThemeButtonsBlur(e) { - const active = document.activeElement; - const related = e.relatedTarget; - - if (active.id !== THEME_PICKER_ELEMENT_ID && - (!active.parentNode || active.parentNode.id !== THEMES_ELEMENT_ID) && - (!related || - (related.id !== THEME_PICKER_ELEMENT_ID && - (!related.parentNode || related.parentNode.id !== THEMES_ELEMENT_ID)))) { - hideThemeButtonState(); - } - } - - themePicker.onclick = switchThemeButtonState; - themePicker.onblur = handleThemeButtonsBlur; - availableThemes.forEach(item => { - const but = document.createElement("button"); - but.textContent = item; - but.onclick = () => { - switchTheme(window.currentTheme, window.mainTheme, item, true); - useSystemTheme(false); - }; - but.onblur = handleThemeButtonsBlur; - themeChoices.appendChild(but); - }); -}()); - /** * This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode` * doesn't have a parent node. @@ -512,7 +437,7 @@ function loadCss(cssFileName) { ev.preventDefault(); } searchState.defocus(); - hideThemeButtonState(); + window.hideSettings(); } const disableShortcuts = getSettingValue("disable-shortcuts") === "true"; @@ -522,8 +447,6 @@ function loadCss(cssFileName) { return; } - let themePicker; - if (document.activeElement.tagName === "INPUT") { switch (getVirtualKey(ev)) { case "Escape": @@ -553,64 +476,9 @@ function loadCss(cssFileName) { displayHelp(true, ev); break; - case "t": - case "T": - displayHelp(false, ev); - ev.preventDefault(); - themePicker = getThemePickerElement(); - themePicker.click(); - themePicker.focus(); - break; - default: - if (getThemePickerElement().parentNode.contains(ev.target)) { - handleThemeKeyDown(ev); - } - } - } - } - - function handleThemeKeyDown(ev) { - const active = document.activeElement; - const themes = getThemesElement(); - switch (getVirtualKey(ev)) { - case "ArrowUp": - ev.preventDefault(); - if (active.previousElementSibling && ev.target.id !== THEME_PICKER_ELEMENT_ID) { - active.previousElementSibling.focus(); - } else { - showThemeButtonState(); - themes.lastElementChild.focus(); - } - break; - case "ArrowDown": - ev.preventDefault(); - if (active.nextElementSibling && ev.target.id !== THEME_PICKER_ELEMENT_ID) { - active.nextElementSibling.focus(); - } else { - showThemeButtonState(); - themes.firstElementChild.focus(); - } - break; - case "Enter": - case "Return": - case "Space": - if (ev.target.id === THEME_PICKER_ELEMENT_ID && themes.style.display === "none") { - ev.preventDefault(); - showThemeButtonState(); - themes.firstElementChild.focus(); + break; } - break; - case "Home": - ev.preventDefault(); - themes.firstElementChild.focus(); - break; - case "End": - ev.preventDefault(); - themes.lastElementChild.focus(); - break; - // The escape key is handled in handleEscape, not here, - // so that pressing escape will close the menu even if it isn't focused } } @@ -841,8 +709,8 @@ function loadCss(cssFileName) { onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { if (e.parentNode.id !== "implementations-list" || (!hasClass(e, "implementors-toggle") && - !hasClass(e, "type-contents-toggle"))) - { + !hasClass(e, "type-contents-toggle")) + ) { e.open = false; } }); @@ -1006,7 +874,6 @@ function loadCss(cssFileName) { const shortcuts = [ ["?", "Show this help dialog"], ["S", "Focus the search field"], - ["T", "Focus the theme picker menu"], ["↑", "Move up in search results"], ["↓", "Move down in search results"], ["← / →", "Switch result tab (when results focused)"], diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js index 408b7e19feadd..7b9d86a851b19 100644 --- a/src/librustdoc/html/static/js/scrape-examples.js +++ b/src/librustdoc/html/static/js/scrape-examples.js @@ -98,7 +98,9 @@ // visible. This is necessary since updateScrapedExample calls scrollToLoc which // depends on offsetHeight, a property that requires an element to be visible to // compute correctly. - setTimeout(() => { onEachLazy(moreExamples, updateScrapedExample); }); + setTimeout(() => { + onEachLazy(moreExamples, updateScrapedExample); + }); }, {once: true}); }); })(); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index b596adf32c6fd..0be70d77d06e4 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -320,8 +320,8 @@ window.initSearch = rawSearchIndex => { if (foundExclamation) { throw new Error("Cannot have more than one `!` in an ident"); } else if (parserState.pos + 1 < parserState.length && - isIdentCharacter(parserState.userQuery[parserState.pos + 1])) - { + isIdentCharacter(parserState.userQuery[parserState.pos + 1]) + ) { throw new Error("`!` can only be at the end of an ident"); } foundExclamation = true; @@ -330,12 +330,10 @@ window.initSearch = rawSearchIndex => { } else if ( isStopCharacter(c) || isSpecialStartCharacter(c) || - isSeparatorCharacter(c)) - { + isSeparatorCharacter(c) + ) { break; - } - // If we allow paths ("str::string" for example). - else if (c === ":") { + } else if (c === ":") { // If we allow paths ("str::string" for example). if (!isPathStart(parserState)) { break; } @@ -372,8 +370,8 @@ window.initSearch = rawSearchIndex => { end = getIdentEndPosition(parserState); } if (parserState.pos < parserState.length && - parserState.userQuery[parserState.pos] === "<") - { + parserState.userQuery[parserState.pos] === "<" + ) { if (isInGenerics) { throw new Error("Unexpected `<` after `<`"); } else if (start >= end) { @@ -592,8 +590,8 @@ window.initSearch = rawSearchIndex => { if (elem && elem.value !== "All crates" && - hasOwnPropertyRustdoc(rawSearchIndex, elem.value)) - { + hasOwnPropertyRustdoc(rawSearchIndex, elem.value) + ) { return elem.value; } return null; @@ -786,37 +784,51 @@ window.initSearch = rawSearchIndex => { // sort by exact match with regard to the last word (mismatch goes later) a = (aaa.word !== userQuery); b = (bbb.word !== userQuery); - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // Sort by non levenshtein results and then levenshtein results by the distance // (less changes required to match means higher rankings) a = (aaa.lev); b = (bbb.lev); - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // sort by crate (non-current crate goes later) a = (aaa.item.crate !== window.currentCrate); b = (bbb.item.crate !== window.currentCrate); - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // sort by item name length (longer goes later) a = aaa.word.length; b = bbb.word.length; - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // sort by item name (lexicographically larger goes later) a = aaa.word; b = bbb.word; - if (a !== b) { return (a > b ? +1 : -1); } + if (a !== b) { + return (a > b ? +1 : -1); + } // sort by index of keyword in item name (no literal occurrence goes later) a = (aaa.index < 0); b = (bbb.index < 0); - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // (later literal occurrence, if any, goes later) a = aaa.index; b = bbb.index; - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // special precedence for primitive and keyword pages if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) || @@ -831,17 +843,23 @@ window.initSearch = rawSearchIndex => { // sort by description (no description goes later) a = (aaa.item.desc === ""); b = (bbb.item.desc === ""); - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // sort by type (later occurrence in `itemTypes` goes later) a = aaa.item.ty; b = bbb.item.ty; - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // sort by path (lexicographically larger goes later) a = aaa.item.path; b = bbb.item.path; - if (a !== b) { return (a > b ? +1 : -1); } + if (a !== b) { + return (a > b ? +1 : -1); + } // que sera, sera return 0; @@ -1315,16 +1333,15 @@ window.initSearch = rawSearchIndex => { } if (searchWord.indexOf(elem.pathLast) > -1 || - row.normalizedName.indexOf(elem.pathLast) > -1) - { + row.normalizedName.indexOf(elem.pathLast) > -1 + ) { // filter type: ... queries if (!results_others[fullId] !== undefined) { index = row.normalizedName.indexOf(elem.pathLast); } } lev = levenshtein(searchWord, elem.pathLast); - if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) - { + if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) { if (elem.pathLast.length < 6) { lev = 1; } else { @@ -1670,8 +1687,8 @@ window.initSearch = rawSearchIndex => { // By default, the search DOM element is "empty" (meaning it has no children not // text content). Once a search has been run, it won't be empty, even if you press // ESC or empty the search input (which also "cancels" the search). - && (!search.firstChild || search.firstChild.innerText !== searchState.loadingText))) - { + && (!search.firstChild || search.firstChild.innerText !== searchState.loadingText)) + ) { const elem = document.createElement("a"); elem.href = results.others[0].href; removeClass(elem, "active"); @@ -1766,7 +1783,7 @@ window.initSearch = rawSearchIndex => { let i = 0; for (const elem of elems) { const j = i; - elem.onclick = () => { printTab(j); }; + elem.onclick = () => printTab(j); searchState.focusedByTab.push(null); i += 1; } diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index ad32a19389389..df828b5ce4c3a 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -1,7 +1,7 @@ // Local js definitions: /* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */ -/* global addClass, removeClass, onEach, onEachLazy, NOT_DISPLAYED_ID */ -/* global MAIN_ID, getVar, getSettingsButton, switchDisplayedElement, getNotDisplayedElem */ +/* global addClass, removeClass, onEach, onEachLazy */ +/* global MAIN_ID, getVar, getSettingsButton */ "use strict"; @@ -206,38 +206,60 @@ ]; // Then we build the DOM. - const el = document.createElement("section"); - el.id = "settings"; - let innerHTML = ` -
+ let innerHTML = ""; + let elementKind = "div"; + + if (isSettingsPage) { + elementKind = "section"; + innerHTML = `

Rustdoc settings

- `; - - if (isSettingsPage) { - innerHTML += - "Back"; - } else { - innerHTML += "Back"; + + Back + +
`; } - innerHTML += ` -
-
${buildSettingsPageSections(settings)}
`; + innerHTML += `
${buildSettingsPageSections(settings)}
`; + const el = document.createElement(elementKind); + el.id = "settings"; el.innerHTML = innerHTML; if (isSettingsPage) { document.getElementById(MAIN_ID).appendChild(el); } else { - getNotDisplayedElem().appendChild(el); + el.setAttribute("tabindex", "-1"); + getSettingsButton().appendChild(el); } return el; } const settingsMenu = buildSettingsPage(); + function displaySettings() { + settingsMenu.style.display = ""; + } + + function elemIsInParent(elem, parent) { + while (elem && elem !== document.body) { + if (elem === parent) { + return true; + } + elem = elem.parentElement; + } + return false; + } + + function blurHandler(event) { + const settingsButton = getSettingsButton(); + if (!elemIsInParent(document.activeElement, settingsButton) && + !elemIsInParent(event.relatedTarget, settingsButton)) + { + window.hideSettings(); + } + } + if (isSettingsPage) { // We replace the existing "onclick" callback to do nothing if clicked. getSettingsButton().onclick = function(event) { @@ -246,17 +268,27 @@ } else { // We replace the existing "onclick" callback. const settingsButton = getSettingsButton(); + const settingsMenu = document.getElementById("settings"); + window.hideSettings = function() { + settingsMenu.style.display = "none"; + }; settingsButton.onclick = function(event) { + if (elemIsInParent(event.target, settingsMenu)) { + return; + } event.preventDefault(); - if (settingsMenu.parentElement.id === NOT_DISPLAYED_ID) { - switchDisplayedElement(settingsMenu); - } else { + if (settingsMenu.style.display !== "none") { window.hideSettings(); + } else { + displaySettings(); } }; - window.hideSettings = function() { - switchDisplayedElement(null); - }; + settingsButton.onblur = blurHandler; + settingsButton.querySelector("a").onblur = blurHandler; + onEachLazy(settingsMenu.querySelectorAll("input"), el => { + el.onblur = blurHandler; + }); + settingsMenu.onblur = blurHandler; } // We now wait a bit for the web browser to end re-computing the DOM... @@ -264,7 +296,7 @@ setEvents(settingsMenu); // The setting menu is already displayed if we're on the settings page. if (!isSettingsPage) { - switchDisplayedElement(settingsMenu); + displaySettings(); } removeClass(getSettingsButton(), "rotate"); }, 0); diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index bec5c083fed22..85ca8431d90da 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -41,9 +41,6 @@ crate static SCRAPE_EXAMPLES_JS: &str = include_str!("static/js/scrape-examples. crate static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/scrape-examples-help.md"); -/// The file contents of `brush.svg`, the icon used for the theme-switch button. -crate static BRUSH_SVG: &[u8] = include_bytes!("static/images/brush.svg"); - /// The file contents of `wheel.svg`, the icon used for the settings button. crate static WHEEL_SVG: &[u8] = include_bytes!("static/images/wheel.svg"); diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 470cce93a5020..cd672aadd7e93 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -108,13 +108,6 @@

{%- endif -%} {#- -#} {#- -#} diff --git a/src/test/codegen/noalias-refcell.rs b/src/test/codegen/noalias-refcell.rs new file mode 100644 index 0000000000000..dba73937abf17 --- /dev/null +++ b/src/test/codegen/noalias-refcell.rs @@ -0,0 +1,14 @@ +// compile-flags: -O -C no-prepopulate-passes -Z mutable-noalias=yes + +#![crate_type = "lib"] + +use std::cell::{Ref, RefCell, RefMut}; + +// Make sure that none of the arguments get a `noalias` attribute, because +// the `RefCell` might alias writes after either `Ref`/`RefMut` is dropped. + +// CHECK-LABEL: @maybe_aliased( +// CHECK-NOT: noalias +// CHECK-SAME: %_refcell +#[no_mangle] +pub unsafe fn maybe_aliased(_: Ref<'_, i32>, _: RefMut<'_, i32>, _refcell: &RefCell) {} diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml index 18270264266f4..9a9c45a9b7fe5 100644 --- a/src/test/rustdoc-gui/settings.goml +++ b/src/test/rustdoc-gui/settings.goml @@ -5,36 +5,25 @@ assert-false: "#settings" // We now click on the settings button. click: "#settings-menu" wait-for: "#settings" -assert: "#main-content.hidden" assert-css: ("#settings", {"display": "block"}) // Let's close it by clicking on the same button. click: "#settings-menu" -assert-false: "#alternative-display #settings" -assert: "#not-displayed #settings" -assert: "#main-content:not(.hidden)" - -// Let's open and then close it again with the "close settings" button. -click: "#settings-menu" -wait-for: "#alternative-display #settings" -assert: "#main-content.hidden" -click: "#back" -wait-for: "#not-displayed #settings" -assert: "#main-content:not(.hidden)" +wait-for-css: ("#settings", {"display": "none"}) // Let's check that pressing "ESCAPE" is closing it. click: "#settings-menu" -wait-for: "#alternative-display #settings" +wait-for-css: ("#settings", {"display": "block"}) press-key: "Escape" -wait-for: "#not-displayed #settings" -assert: "#main-content:not(.hidden)" +wait-for-css: ("#settings", {"display": "none"}) // Let's click on it when the search results are displayed. focus: ".search-input" write: "test" wait-for: "#alternative-display #search" click: "#settings-menu" -wait-for: "#alternative-display #settings" -assert: "#not-displayed #search" +wait-for-css: ("#settings", {"display": "block"}) +// Ensure that the search is still displayed. +wait-for: "#alternative-display #search" assert: "#main-content.hidden" // Now let's check the content of the settings menu. diff --git a/src/test/rustdoc-gui/shortcuts.goml b/src/test/rustdoc-gui/shortcuts.goml index 42d945d0eb817..37a7c1662949d 100644 --- a/src/test/rustdoc-gui/shortcuts.goml +++ b/src/test/rustdoc-gui/shortcuts.goml @@ -12,15 +12,3 @@ assert-css: ("#help", {"display": "flex"}) assert-false: "#help.hidden" press-key: "Escape" assert-css: ("#help.hidden", {"display": "none"}) -// Check for the themes list. -assert-css: ("#theme-choices", {"display": "none"}) -press-key: "t" -assert-css: ("#theme-choices", {"display": "block"}) -press-key: "t" -// We ensure that 't' hides back the menu. -assert-css: ("#theme-choices", {"display": "none"}) -press-key: "t" -assert-css: ("#theme-choices", {"display": "block"}) -press-key: "Escape" -// We ensure that 'Escape' hides the menu too. -assert-css: ("#theme-choices", {"display": "none"}) diff --git a/src/test/rustdoc-gui/theme-change.goml b/src/test/rustdoc-gui/theme-change.goml index 9706511ea19c3..fb1c37ae68e74 100644 --- a/src/test/rustdoc-gui/theme-change.goml +++ b/src/test/rustdoc-gui/theme-change.goml @@ -1,12 +1,21 @@ // Ensures that the theme change is working as expected. goto: file://|DOC_PATH|/test_docs/index.html -click: "#theme-picker" -click: "#theme-choices > button:first-child" -// should be the ayu theme so let's check the color +local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} +reload: +click: "#settings-menu" +wait-for: "#theme-ayu" +click: "#theme-ayu" +// should be the ayu theme so let's check the color. wait-for-css: ("body", { "background-color": "rgb(15, 20, 25)" }) -click: "#theme-choices > button:last-child" -// should be the light theme so let's check the color +assert-local-storage: { "rustdoc-theme": "ayu" } +click: "#theme-light" +// should be the light theme so let's check the color. wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +assert-local-storage: { "rustdoc-theme": "light" } +click: "#theme-dark" +// Should be the dark theme so let's check the color. +wait-for-css: ("body", { "background-color": "rgb(53, 53, 53)" }) +assert-local-storage: { "rustdoc-theme": "dark" } goto: file://|DOC_PATH|/settings.html wait-for: "#settings" diff --git a/src/test/ui/issues/issue-63787.rs b/src/test/ui/issues/issue-63787.rs new file mode 100644 index 0000000000000..cba079b231522 --- /dev/null +++ b/src/test/ui/issues/issue-63787.rs @@ -0,0 +1,36 @@ +// run-pass +// compile-flags: -O + +// Make sure that `Ref` and `RefMut` do not make false promises about aliasing, +// because once they drop, their reference/pointer can alias other writes. + +// Adapted from comex's proof of concept: +// https://github.com/rust-lang/rust/issues/63787#issuecomment-523588164 + +use std::cell::RefCell; +use std::ops::Deref; + +pub fn break_if_r_is_noalias(rc: &RefCell, r: impl Deref) -> i32 { + let ptr1 = &*r as *const i32; + let a = *r; + drop(r); + *rc.borrow_mut() = 2; + let r2 = rc.borrow(); + let ptr2 = &*r2 as *const i32; + if ptr2 != ptr1 { + panic!(); + } + // If LLVM knows the pointers are the same, and if `r` was `noalias`, + // then it may replace this with `a + a`, ignoring the earlier write. + a + *r2 +} + +fn main() { + let mut rc = RefCell::new(1); + let res = break_if_r_is_noalias(&rc, rc.borrow()); + assert_eq!(res, 3); + + *rc.get_mut() = 1; + let res = break_if_r_is_noalias(&rc, rc.borrow_mut()); + assert_eq!(res, 3); +}