From ce6cfc37d033eb1fb1f2e3af1c17c218917b54ec Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 13 May 2023 18:06:16 +0800 Subject: [PATCH 1/9] Fix ice caused by shorthand fields in NoFieldsForFnCall --- compiler/rustc_parse/src/parser/expr.rs | 7 +++++++ tests/ui/parser/issues/issue-111416.rs | 4 ++++ tests/ui/parser/issues/issue-111416.stderr | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 tests/ui/parser/issues/issue-111416.rs create mode 100644 tests/ui/parser/issues/issue-111416.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 887e155426fa1..808bbbdada66f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1180,6 +1180,13 @@ impl<'a> Parser<'a> { self.restore_snapshot(snapshot); let close_paren = self.prev_token.span; let span = lo.to(close_paren); + // filter shorthand fields + let fields: Vec<_> = fields + .into_iter() + .filter_map( + |field| if !field.is_shorthand { Some(field) } else { None }, + ) + .collect(); if !fields.is_empty() && // `token.kind` should not be compared here. // This is because the `snapshot.token.kind` is treated as the same as diff --git a/tests/ui/parser/issues/issue-111416.rs b/tests/ui/parser/issues/issue-111416.rs new file mode 100644 index 0000000000000..deba8679b1a8e --- /dev/null +++ b/tests/ui/parser/issues/issue-111416.rs @@ -0,0 +1,4 @@ + +fn main() { + let my = monad_bind(mx, T: Try); //~ ERROR invalid `struct` delimiters or `fn` call arguments +} diff --git a/tests/ui/parser/issues/issue-111416.stderr b/tests/ui/parser/issues/issue-111416.stderr new file mode 100644 index 0000000000000..b9e61d70e8167 --- /dev/null +++ b/tests/ui/parser/issues/issue-111416.stderr @@ -0,0 +1,18 @@ +error: invalid `struct` delimiters or `fn` call arguments + --> $DIR/issue-111416.rs:3:14 + | +LL | let my = monad_bind(mx, T: Try); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: if `monad_bind` is a struct, use braces as delimiters + | +LL | let my = monad_bind { mx, T: Try }; + | ~ ~ +help: if `monad_bind` is a function, use the arguments directly + | +LL - let my = monad_bind(mx, T: Try); +LL + let my = monad_bind(mx, Try); + | + +error: aborting due to previous error + From 83789b8b068ad38c6a3c937d0a2c6ca64e588c85 Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 13 May 2023 18:06:58 +0800 Subject: [PATCH 2/9] fmt --- compiler/rustc_parse/src/parser/expr.rs | 9 +++------ tests/ui/parser/issues/issue-111416.rs | 1 - tests/ui/parser/issues/issue-111416.stderr | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 808bbbdada66f..ee712a8e1b5db 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1181,12 +1181,9 @@ impl<'a> Parser<'a> { let close_paren = self.prev_token.span; let span = lo.to(close_paren); // filter shorthand fields - let fields: Vec<_> = fields - .into_iter() - .filter_map( - |field| if !field.is_shorthand { Some(field) } else { None }, - ) - .collect(); + let fields: Vec<_> = + fields.into_iter().filter(|field| !field.is_shorthand).collect(); + if !fields.is_empty() && // `token.kind` should not be compared here. // This is because the `snapshot.token.kind` is treated as the same as diff --git a/tests/ui/parser/issues/issue-111416.rs b/tests/ui/parser/issues/issue-111416.rs index deba8679b1a8e..cfd1b6b99ba76 100644 --- a/tests/ui/parser/issues/issue-111416.rs +++ b/tests/ui/parser/issues/issue-111416.rs @@ -1,4 +1,3 @@ - fn main() { let my = monad_bind(mx, T: Try); //~ ERROR invalid `struct` delimiters or `fn` call arguments } diff --git a/tests/ui/parser/issues/issue-111416.stderr b/tests/ui/parser/issues/issue-111416.stderr index b9e61d70e8167..ddacf4d6dfc31 100644 --- a/tests/ui/parser/issues/issue-111416.stderr +++ b/tests/ui/parser/issues/issue-111416.stderr @@ -1,5 +1,5 @@ error: invalid `struct` delimiters or `fn` call arguments - --> $DIR/issue-111416.rs:3:14 + --> $DIR/issue-111416.rs:2:14 | LL | let my = monad_bind(mx, T: Try); | ^^^^^^^^^^^^^^^^^^^^^^ From 00c3f7552ebaef26165da93ef2c88a09ba70d5c2 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Fri, 12 May 2023 16:57:29 -0500 Subject: [PATCH 3/9] refactor: add chunks method to TokenStream to obviate rustdoc clones --- compiler/rustc_ast/src/tokenstream.rs | 4 ++++ src/librustdoc/clean/utils.rs | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 3f0b1627afa56..db296aa44db2b 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -551,6 +551,10 @@ impl TokenStream { vec_mut.extend(stream_iter); } } + + pub fn chunks(&self, chunk_size: usize) -> core::slice::Chunks<'_, TokenTree> { + self.0.chunks(chunk_size) + } } /// By-reference iterator over a [`TokenStream`], that produces `&TokenTree` diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index b802fd065fe54..17aa6b38e389c 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -594,9 +594,8 @@ pub(super) fn display_macro_source( def_id: DefId, vis: ty::Visibility, ) -> String { - let tts: Vec<_> = def.body.tokens.clone().into_trees().collect(); // Extract the spans of all matchers. They represent the "interface" of the macro. - let matchers = tts.chunks(4).map(|arm| &arm[0]); + let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]); if def.macro_rules { format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx.tcx, matchers, ";")) From f16d2b1629d62db306bd9d03676524dc848c94b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 14 May 2023 00:00:00 +0000 Subject: [PATCH 4/9] Start node has no immediate dominator Change the immediate_dominator return type to Option, and use None to indicate that node has no immediate dominator. Also fix the issue where the start node would be returned as its own immediate dominator. --- .../src/transform/validate.rs | 2 +- .../src/graph/dominators/mod.rs | 22 +++++++++---------- .../src/graph/dominators/tests.rs | 14 ++++++++++-- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index c50e937d84fed..3c350e25ba6ec 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -164,7 +164,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(root) = post_contract_node.get(&bb) { break *root; } - let parent = doms.immediate_dominator(bb); + let parent = doms.immediate_dominator(bb).unwrap(); dom_path.push(bb); if !self.body.basic_blocks[parent].is_cleanup { break bb; diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index e76bdac286411..a7de709ba72bf 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -242,7 +242,9 @@ pub fn dominators(graph: G) -> Dominators { immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]); } - Dominators { post_order_rank, immediate_dominators } + let start_node = graph.start_node(); + immediate_dominators[start_node] = None; + Dominators { start_node, post_order_rank, immediate_dominators } } /// Evaluate the link-eval virtual forest, providing the currently minimum semi @@ -308,6 +310,7 @@ fn compress( /// Tracks the list of dominators for each node. #[derive(Clone, Debug)] pub struct Dominators { + start_node: N, post_order_rank: IndexVec, // Even though we track only the immediate dominator of each node, it's // possible to get its full list of dominators by looking up the dominator @@ -316,14 +319,14 @@ pub struct Dominators { } impl Dominators { - /// Whether the given Node has an immediate dominator. + /// Returns true if node is reachable from the start node. pub fn is_reachable(&self, node: Node) -> bool { - self.immediate_dominators[node].is_some() + node == self.start_node || self.immediate_dominators[node].is_some() } - pub fn immediate_dominator(&self, node: Node) -> Node { - assert!(self.is_reachable(node), "node {node:?} is not reachable"); - self.immediate_dominators[node].unwrap() + /// Returns the immediate dominator of node, if any. + pub fn immediate_dominator(&self, node: Node) -> Option { + self.immediate_dominators[node] } /// Provides an iterator over each dominator up the CFG, for the given Node. @@ -357,12 +360,7 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { fn next(&mut self) -> Option { if let Some(node) = self.node { - let dom = self.dominators.immediate_dominator(node); - if dom == node { - self.node = None; // reached the root - } else { - self.node = Some(dom); - } + self.node = self.dominators.immediate_dominator(node); Some(node) } else { None diff --git a/compiler/rustc_data_structures/src/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs index ff31d8f7fdcf6..8b124516623d6 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/tests.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/tests.rs @@ -8,7 +8,7 @@ fn diamond() { let dominators = dominators(&graph); let immediate_dominators = &dominators.immediate_dominators; - assert_eq!(immediate_dominators[0], Some(0)); + assert_eq!(immediate_dominators[0], None); assert_eq!(immediate_dominators[1], Some(0)); assert_eq!(immediate_dominators[2], Some(0)); assert_eq!(immediate_dominators[3], Some(0)); @@ -30,7 +30,7 @@ fn paper() { assert_eq!(immediate_dominators[3], Some(6)); assert_eq!(immediate_dominators[4], Some(6)); assert_eq!(immediate_dominators[5], Some(6)); - assert_eq!(immediate_dominators[6], Some(6)); + assert_eq!(immediate_dominators[6], None); } #[test] @@ -43,3 +43,13 @@ fn paper_slt() { dominators(&graph); } + +#[test] +fn immediate_dominator() { + let graph = TestGraph::new(1, &[(1, 2), (2, 3)]); + let dominators = dominators(&graph); + assert_eq!(dominators.immediate_dominator(0), None); + assert_eq!(dominators.immediate_dominator(1), None); + assert_eq!(dominators.immediate_dominator(2), Some(1)); + assert_eq!(dominators.immediate_dominator(3), Some(2)); +} From 6289c57dc0ee8ebbe9e20fad808f85aed0afeceb Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 14 May 2023 16:24:11 +0200 Subject: [PATCH 5/9] Simplify find_width_of_character_at_span. --- compiler/rustc_span/src/lib.rs | 1 + compiler/rustc_span/src/source_map.rs | 31 ++++++--------------------- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 7bbab34c69a38..97cb734619e3c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -20,6 +20,7 @@ #![feature(min_specialization)] #![feature(rustc_attrs)] #![feature(let_chains)] +#![feature(round_char_boundary)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 8238a16969d9b..11ea5fe4ddf9f 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -1019,36 +1019,19 @@ impl SourceMap { let src = local_begin.sf.external_src.borrow(); - // We need to extend the snippet to the end of the src rather than to end_index so when - // searching forwards for boundaries we've got somewhere to search. - let snippet = if let Some(ref src) = local_begin.sf.src { - &src[start_index..] + let snippet = if let Some(src) = &local_begin.sf.src { + src } else if let Some(src) = src.get_source() { - &src[start_index..] + src } else { return 1; }; - debug!("snippet=`{:?}`", snippet); - let mut target = if forwards { end_index + 1 } else { end_index - 1 }; - debug!("initial target=`{:?}`", target); - - while !snippet.is_char_boundary(target - start_index) && target < source_len { - target = if forwards { - target + 1 - } else { - match target.checked_sub(1) { - Some(target) => target, - None => { - break; - } - } - }; - debug!("target=`{:?}`", target); + if forwards { + (snippet.ceil_char_boundary(end_index + 1) - end_index) as u32 + } else { + (end_index - snippet.floor_char_boundary(end_index - 1)) as u32 } - debug!("final target=`{:?}`", target); - - if forwards { (target - end_index) as u32 } else { (end_index - target) as u32 } } pub fn get_source_file(&self, filename: &FileName) -> Option> { From 3d02aa850bdb4c475a6dcbdebf879fdd625cdab9 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Tue, 4 Oct 2022 20:27:28 +0200 Subject: [PATCH 6/9] explain that `PhantomData<&'a T>` infers `T: 'a` --- library/core/src/marker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 01606086fca68..47a3e78b4d5c7 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -695,7 +695,7 @@ impl !Sync for *mut T {} /// } /// ``` /// -/// This also in turn requires the annotation `T: 'a`, indicating +/// This also in turn infers the lifetime bound `T: 'a`, indicating /// that any references in `T` are valid over the lifetime `'a`. /// /// When initializing a `Slice` you simply provide the value From 044bf9d7d9f59a2917b34ff260a7bf8671506cb3 Mon Sep 17 00:00:00 2001 From: LucasFA <23667494+LucasFA@users.noreply.github.com> Date: Sun, 14 May 2023 22:00:23 +0200 Subject: [PATCH 7/9] Appease lints A warning about an unnecessary drop used to appear when running the linkchecker. Also some clippy warnings --- src/tools/linkchecker/main.rs | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 4170c32f1fe25..c8a370085a045 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -139,18 +139,18 @@ enum FileEntry { type Cache = HashMap; fn small_url_encode(s: &str) -> String { - s.replace("<", "%3C") - .replace(">", "%3E") - .replace(" ", "%20") - .replace("?", "%3F") - .replace("'", "%27") - .replace("&", "%26") - .replace(",", "%2C") - .replace(":", "%3A") - .replace(";", "%3B") - .replace("[", "%5B") - .replace("]", "%5D") - .replace("\"", "%22") + s.replace('<', "%3C") + .replace('>', "%3E") + .replace(' ', "%20") + .replace('?', "%3F") + .replace('\'', "%27") + .replace('&', "%26") + .replace(',', "%2C") + .replace(':', "%3A") + .replace(';', "%3B") + .replace('[', "%5B") + .replace(']', "%5D") + .replace('\"', "%22") } impl Checker { @@ -267,7 +267,6 @@ impl Checker { FileEntry::OtherFile => return, FileEntry::Redirect { target } => { let t = target.clone(); - drop(target); let (target, redir_entry) = self.load_file(&t, report); match redir_entry { FileEntry::Missing => { @@ -391,7 +390,7 @@ impl Checker { const ERROR_INVALID_NAME: i32 = 123; let pretty_path = - file.strip_prefix(&self.root).unwrap_or(&file).to_str().unwrap().to_string(); + file.strip_prefix(&self.root).unwrap_or(file).to_str().unwrap().to_string(); let entry = self.cache.entry(pretty_path.clone()).or_insert_with(|| match fs::metadata(file) { @@ -470,10 +469,8 @@ fn is_exception(file: &Path, link: &str) -> bool { // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path // calculated in `check` function is outside `build//doc` dir. // So the `strip_prefix` method just returns the old absolute broken path. - if file.ends_with("std/primitive.slice.html") { - if link.ends_with("primitive.slice.html") { - return true; - } + if file.ends_with("std/primitive.slice.html") && link.ends_with("primitive.slice.html") { + return true; } false } @@ -545,7 +542,7 @@ fn with_attrs_in_source(source: &str, attr: &str, m fn parse_ids(ids: &mut HashSet, file: &str, source: &str, report: &mut Report) { if ids.is_empty() { with_attrs_in_source(source, " id", |fragment, i, _| { - let frag = fragment.trim_start_matches("#").to_owned(); + let frag = fragment.trim_start_matches('#').to_owned(); let encoded = small_url_encode(&frag); if !ids.insert(frag) { report.errors += 1; From 47232ade6151a8e7d2112e2dda0c7c5c930b0a31 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 14 May 2023 23:03:50 -0700 Subject: [PATCH 8/9] Fix some misleading and copy-pasted `Pattern` examples These examples were listed twice and also were confusable with doing a substring match instead of a any-of-set match. --- library/core/src/str/pattern.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index e3a464a1c51a9..91ee2903aab43 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -791,8 +791,8 @@ pub struct CharArrayRefSearcher<'a, 'b, const N: usize>( /// # Examples /// /// ``` -/// assert_eq!("Hello world".find(['l', 'l']), Some(2)); -/// assert_eq!("Hello world".find(['l', 'l']), Some(2)); +/// assert_eq!("Hello world".find(['o', 'l']), Some(2)); +/// assert_eq!("Hello world".find(['h', 'w']), Some(6)); /// ``` impl<'a, const N: usize> Pattern<'a> for [char; N] { pattern_methods!(CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher); @@ -811,8 +811,8 @@ unsafe impl<'a, const N: usize> ReverseSearcher<'a> for CharArraySearcher<'a, N> /// # Examples /// /// ``` -/// assert_eq!("Hello world".find(&['l', 'l']), Some(2)); -/// assert_eq!("Hello world".find(&['l', 'l']), Some(2)); +/// assert_eq!("Hello world".find(&['o', 'l']), Some(2)); +/// assert_eq!("Hello world".find(&['h', 'w']), Some(6)); /// ``` impl<'a, 'b, const N: usize> Pattern<'a> for &'b [char; N] { pattern_methods!(CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher); From 5fa8c4aced01e9bcbeaba418c5397883c94484da Mon Sep 17 00:00:00 2001 From: Vagelis Prokopiou Date: Mon, 15 May 2023 10:13:08 +0300 Subject: [PATCH 9/9] wanting => want --- library/std/src/fs.rs | 2 +- library/std/src/io/copy.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 6640c7fb16214..2a6b1a5ec73e4 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1946,7 +1946,7 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> /// On success, the total number of bytes copied is returned and it is equal to /// the length of the `to` file as reported by `metadata`. /// -/// If you’re wanting to copy the contents of one file to another and you’re +/// If you want to copy the contents of one file to another and you’re /// working with [`File`]s, see the [`io::copy()`] function. /// /// # Platform-specific behavior diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index 38b98afffa168..1d9d93f5b64ec 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -10,7 +10,7 @@ use crate::mem::MaybeUninit; /// On success, the total number of bytes that were copied from /// `reader` to `writer` is returned. /// -/// If you’re wanting to copy the contents of one file to another and you’re +/// If you want to copy the contents of one file to another and you’re /// working with filesystem paths, see the [`fs::copy`] function. /// /// [`fs::copy`]: crate::fs::copy