From b910e977a3279460fb13e464fa4b5d563645c8cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 4 Nov 2024 18:55:21 +0100 Subject: [PATCH 01/13] CI: increase timeout from 4h to 6h Our CI got a bit slower since the last time we lowered the timeout, and if e.g. Docker build cache is broken, the timeout can be triggered. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2fca71716c18c..6fe257933423c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,7 +65,7 @@ jobs: defaults: run: shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }} - timeout-minutes: 240 + timeout-minutes: 360 env: CI_JOB_NAME: ${{ matrix.image }} CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse From 584ec95972485f4c271760517799f4fba85a10f2 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 14 Nov 2024 09:15:49 -0800 Subject: [PATCH 02/13] btree: add `{Entry,VacantEntry}::insert_entry` This matches the recently-stabilized methods on `HashMap` entries. I've reused tracking issue #65225 for now, but we may want to split it. --- .../alloc/src/collections/btree/map/entry.rs | 105 +++++++++++++----- library/alloc/src/collections/btree/node.rs | 2 +- 2 files changed, 76 insertions(+), 31 deletions(-) diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 75bb86916a887..0da6af54bc22b 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -269,6 +269,31 @@ impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { Vacant(entry) => Vacant(entry), } } + + /// Sets the value of the entry, and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_entry_insert)] + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); + /// let entry = map.entry("poneyland").insert_entry("hoho".to_string()); + /// + /// assert_eq!(entry.key(), &"poneyland"); + /// ``` + #[inline] + #[unstable(feature = "btree_entry_insert", issue = "65225")] + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> { + match self { + Occupied(mut entry) => { + entry.insert(value); + entry + } + Vacant(entry) => entry.insert_entry(value), + } + } } impl<'a, K: Ord, V: Default, A: Allocator + Clone> Entry<'a, K, V, A> { @@ -348,41 +373,61 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push", "put")] - pub fn insert(mut self, value: V) -> &'a mut V { - let out_ptr = match self.handle { + pub fn insert(self, value: V) -> &'a mut V { + self.insert_entry(value).into_mut() + } + + /// Sets the value of the entry with the `VacantEntry`'s key, + /// and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_entry_insert)] + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, u32> = BTreeMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// let entry = o.insert_entry(37); + /// assert_eq!(entry.get(), &37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[unstable(feature = "btree_entry_insert", issue = "65225")] + pub fn insert_entry(mut self, value: V) -> OccupiedEntry<'a, K, V, A> { + let handle = match self.handle { None => { // SAFETY: There is no tree yet so no reference to it exists. - let map = unsafe { self.dormant_map.awaken() }; - let mut root = NodeRef::new_leaf(self.alloc.clone()); - let val_ptr = root.borrow_mut().push(self.key, value); - map.root = Some(root.forget_type()); - map.length = 1; - val_ptr - } - Some(handle) => { - let new_handle = - handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| { - drop(ins.left); - // SAFETY: Pushing a new root node doesn't invalidate - // handles to existing nodes. - let map = unsafe { self.dormant_map.reborrow() }; - let root = map.root.as_mut().unwrap(); // same as ins.left - root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right) - }); - - // Get the pointer to the value - let val_ptr = new_handle.into_val_mut(); - - // SAFETY: We have consumed self.handle. - let map = unsafe { self.dormant_map.awaken() }; - map.length += 1; - val_ptr + let map = unsafe { self.dormant_map.reborrow() }; + let root = map.root.insert(NodeRef::new_leaf(self.alloc.clone()).forget_type()); + // SAFETY: We *just* created the root as a leaf, and we're + // stacking the new handle on the original borrow lifetime. + unsafe { + let mut leaf = root.borrow_mut().cast_to_leaf_unchecked(); + leaf.push_with_handle(self.key, value) + } } + Some(handle) => handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| { + drop(ins.left); + // SAFETY: Pushing a new root node doesn't invalidate + // handles to existing nodes. + let map = unsafe { self.dormant_map.reborrow() }; + let root = map.root.as_mut().unwrap(); // same as ins.left + root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right) + }), }; - // Now that we have finished growing the tree using borrowed references, - // dereference the pointer to a part of it, that we picked up along the way. - unsafe { &mut *out_ptr } + // SAFETY: modifying the length doesn't invalidate handles to existing nodes. + unsafe { self.dormant_map.reborrow().length += 1 }; + + OccupiedEntry { + handle: handle.forget_node_type(), + dormant_map: self.dormant_map, + alloc: self.alloc, + _marker: PhantomData, + } } } diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 2a853ef421629..cec9ca04e9d19 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -739,7 +739,7 @@ impl NodeRef { impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { /// Unsafely asserts to the compiler the static information that this node is a `Leaf`. - unsafe fn cast_to_leaf_unchecked(self) -> NodeRef, K, V, marker::Leaf> { + pub unsafe fn cast_to_leaf_unchecked(self) -> NodeRef, K, V, marker::Leaf> { debug_assert!(self.height == 0); NodeRef { height: self.height, node: self.node, _marker: PhantomData } } From 673b3d380fb2e0607bfdd875eafd0bffa81e0a91 Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Sun, 17 Nov 2024 09:18:42 -0600 Subject: [PATCH 03/13] restrict synthetic types to standard library types --- src/etc/lldb_commands | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands index 4be2dba34f6f8..8a2ed0835b758 100644 --- a/src/etc/lldb_commands +++ b/src/etc/lldb_commands @@ -1,4 +1,23 @@ -type synthetic add -l lldb_lookup.synthetic_lookup -x ".*" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)String$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?str$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?\\[.+\\]$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^core::num::([a-z_]+::)*NonZero.+$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::([a-z_]+::)+)PathBuf$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?str$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?\\[.+\\]$" --category Rust From 6484420e5de69f53c1e48eb19da78f2ebbd56093 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Nov 2024 09:16:59 +0100 Subject: [PATCH 04/13] the emscripten OS no longer exists on non-wasm targets --- compiler/rustc_target/src/spec/tests/tests_impl.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index bd47d12ef9ff7..522b9f837d7cd 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -19,6 +19,9 @@ impl Target { if self.is_like_msvc { assert!(self.is_like_windows); } + if self.os == "emscripten" { + assert!(self.is_like_wasm); + } // Check that default linker flavor is compatible with some other key properties. assert_eq!(self.is_like_osx, matches!(self.linker_flavor, LinkerFlavor::Darwin(..))); @@ -137,7 +140,7 @@ impl Target { assert!(self.dynamic_linking); } // Apparently PIC was slow on wasm at some point, see comments in wasm_base.rs - if self.dynamic_linking && !(self.is_like_wasm && self.os != "emscripten") { + if self.dynamic_linking && !self.is_like_wasm { assert_eq!(self.relocation_model, RelocModel::Pic); } if self.position_independent_executables { From f3ad32b76934fcc8a5119ecf20c7ba9cc7b40ea9 Mon Sep 17 00:00:00 2001 From: "Crom (Thibaut CHARLES)" Date: Sun, 24 Nov 2024 14:36:55 +0100 Subject: [PATCH 05/13] Added a doc test for std::path::strip_prefix --- library/std/src/path.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index b0291e3aa196f..7ffb11b6aedbd 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2504,6 +2504,7 @@ impl Path { /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); /// /// assert!(path.strip_prefix("test").is_err()); + /// assert!(path.strip_prefix("/te").is_err()); /// assert!(path.strip_prefix("/haha").is_err()); /// /// let prefix = PathBuf::from("/test/"); From d26e29ff3a9c3851045b6d7a03e6bd6010267624 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 25 Nov 2024 03:04:07 +0000 Subject: [PATCH 06/13] Tweak parameter mismatch explanation to not say unknown --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 53 +++++++++++-------- tests/ui/async-await/coroutine-desc.stderr | 6 +-- .../coerce-reborrow-multi-arg-fail.stderr | 2 +- tests/ui/fn/fn-item-type.stderr | 10 ++-- tests/ui/fn/param-mismatch-no-names.rs | 8 +++ tests/ui/fn/param-mismatch-no-names.stderr | 23 ++++++++ ...ric-mismatch-reporting-issue-116615.stderr | 10 ++-- 7 files changed, 75 insertions(+), 37 deletions(-) create mode 100644 tests/ui/fn/param-mismatch-no-names.rs create mode 100644 tests/ui/fn/param-mismatch-no-names.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 9c18dbd422d90..f8f6564cf14d9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2347,9 +2347,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let check_for_matched_generics = || { if matched_inputs.iter().any(|x| x.is_some()) - && params_with_generics.iter().any(|x| x.0.is_some()) + && params_with_generics.iter().any(|x| x.1.is_some()) { - for (idx, (generic, _)) in params_with_generics.iter().enumerate() { + for &(idx, generic, _) in ¶ms_with_generics { // Param has to have a generic and be matched to be relevant if matched_inputs[idx.into()].is_none() { continue; @@ -2362,7 +2362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for unmatching_idx in idx + 1..params_with_generics.len() { if matched_inputs[unmatching_idx.into()].is_none() && let Some(unmatched_idx_param_generic) = - params_with_generics[unmatching_idx].0 + params_with_generics[unmatching_idx].1 && unmatched_idx_param_generic.name.ident() == generic.name.ident() { @@ -2377,8 +2377,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let check_for_matched_generics = check_for_matched_generics(); - for (idx, (generic_param, param)) in - params_with_generics.iter().enumerate().filter(|(idx, _)| { + for &(idx, generic_param, param) in + params_with_generics.iter().filter(|&(idx, _, _)| { check_for_matched_generics || expected_idx.is_none_or(|expected_idx| expected_idx == *idx) }) @@ -2390,8 +2390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics .iter() - .enumerate() - .filter(|(other_idx, (other_generic_param, _))| { + .filter(|(other_idx, other_generic_param, _)| { if *other_idx == idx { return false; } @@ -2410,18 +2409,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } other_generic_param.name.ident() == generic_param.name.ident() }) - .map(|(other_idx, (_, other_param))| (other_idx, *other_param)) + .map(|&(other_idx, _, other_param)| (other_idx, other_param)) .collect(); if !other_params_matched.is_empty() { let other_param_matched_names: Vec = other_params_matched .iter() - .map(|(_, other_param)| { + .map(|(idx, other_param)| { if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind { format!("`{ident}`") } else { - "{unknown}".to_string() + format!("parameter #{}", idx + 1) } }) .collect(); @@ -2478,18 +2477,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let param_idents_matching: Vec = params_with_generics .iter() - .filter(|(generic, _)| { + .filter(|(_, generic, _)| { if let Some(generic) = generic { generic.name.ident() == generic_param.name.ident() } else { false } }) - .map(|(_, param)| { + .map(|(idx, _, param)| { if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind { format!("`{ident}`") } else { - "{unknown}".to_string() + format!("parameter #{}", idx + 1) } }) .collect(); @@ -2498,8 +2497,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { spans.push_span_label( generic_param.span, format!( - "{} all reference this parameter {}", + "{} {} reference this parameter `{}`", display_list_with_comma_and(¶m_idents_matching), + if param_idents_matching.len() == 2 { "both" } else { "all" }, generic_param.name.ident().name, ), ); @@ -2580,7 +2580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(params_with_generics) = self.get_hir_params_with_generics(def_id, is_method) { debug_assert_eq!(params_with_generics.len(), matched_inputs.len()); - for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() { + for &(idx, generic_param, _) in ¶ms_with_generics { if matched_inputs[idx.into()].is_none() { continue; } @@ -2594,20 +2594,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut idxs_matched: Vec = vec![]; - for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter( - |(other_idx, (other_generic_param, _))| { - if *other_idx == idx { + for &(other_idx, _, _) in + params_with_generics.iter().filter(|&&(other_idx, other_generic_param, _)| { + if other_idx == idx { return false; } let Some(other_generic_param) = other_generic_param else { return false; }; - if matched_inputs[(*other_idx).into()].is_some() { + if matched_inputs[other_idx.into()].is_some() { return false; } other_generic_param.name.ident() == generic_param.name.ident() - }, - ) { + }) + { idxs_matched.push(other_idx); } @@ -2642,7 +2642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, def_id: DefId, is_method: bool, - ) -> Option>, &hir::Param<'_>)>> { + ) -> Option>, &hir::Param<'_>)>> { let fn_node = self.tcx.hir().get_if_local(def_id)?; let fn_decl = fn_node.fn_decl()?; @@ -2685,7 +2685,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } debug_assert_eq!(params.len(), generic_params.len()); - Some(generic_params.into_iter().zip(params).collect()) + Some( + generic_params + .into_iter() + .zip(params) + .enumerate() + .map(|(a, (b, c))| (a, b, c)) + .collect(), + ) } } diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr index e1d7898478e0a..5434ff3d958f8 100644 --- a/tests/ui/async-await/coroutine-desc.stderr +++ b/tests/ui/async-await/coroutine-desc.stderr @@ -19,7 +19,7 @@ LL | fn fun>(f1: F, f2: F) {} | ^^^ - ----- ----- this parameter needs to match the `async` block type of `f1` | | | | | `f2` needs to match the `async` block type of this parameter - | `f1` and `f2` all reference this parameter F + | `f1` and `f2` both reference this parameter `F` error[E0308]: mismatched types --> $DIR/coroutine-desc.rs:12:16 @@ -39,7 +39,7 @@ LL | fn fun>(f1: F, f2: F) {} | ^^^ - ----- ----- this parameter needs to match the future type of `f1` | | | | | `f2` needs to match the future type of this parameter - | `f1` and `f2` all reference this parameter F + | `f1` and `f2` both reference this parameter `F` error[E0308]: mismatched types --> $DIR/coroutine-desc.rs:14:26 @@ -62,7 +62,7 @@ LL | fn fun>(f1: F, f2: F) {} | ^^^ - ----- ----- this parameter needs to match the `async` closure body type of `f1` | | | | | `f2` needs to match the `async` closure body type of this parameter - | `f1` and `f2` all reference this parameter F + | `f1` and `f2` both reference this parameter `F` error: aborting due to 3 previous errors diff --git a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr index 46723c5a297f7..5dea3f70fdb5f 100644 --- a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr +++ b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr @@ -16,7 +16,7 @@ LL | fn test(_a: T, _b: T) {} | ^^^^ - ----- ----- this parameter needs to match the `&mut {integer}` type of `_a` | | | | | `_b` needs to match the `&mut {integer}` type of this parameter - | `_a` and `_b` all reference this parameter T + | `_a` and `_b` both reference this parameter `T` error: aborting due to 1 previous error diff --git a/tests/ui/fn/fn-item-type.stderr b/tests/ui/fn/fn-item-type.stderr index 76cdbcceac841..5cc529543d2ef 100644 --- a/tests/ui/fn/fn-item-type.stderr +++ b/tests/ui/fn/fn-item-type.stderr @@ -17,7 +17,7 @@ LL | fn eq(x: T, y: T) {} | ^^ - ---- ---- this parameter needs to match the fn item type of `x` | | | | | `y` needs to match the fn item type of this parameter - | `x` and `y` all reference this parameter T + | `x` and `y` both reference this parameter `T` = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` error[E0308]: mismatched types @@ -39,7 +39,7 @@ LL | fn eq(x: T, y: T) {} | ^^ - ---- ---- this parameter needs to match the fn item type of `x` | | | | | `y` needs to match the fn item type of this parameter - | `x` and `y` all reference this parameter T + | `x` and `y` both reference this parameter `T` = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` error[E0308]: mismatched types @@ -61,7 +61,7 @@ LL | fn eq(x: T, y: T) {} | ^^ - ---- ---- this parameter needs to match the fn item type of `x` | | | | | `y` needs to match the fn item type of this parameter - | `x` and `y` all reference this parameter T + | `x` and `y` both reference this parameter `T` = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` error[E0308]: mismatched types @@ -83,7 +83,7 @@ LL | fn eq(x: T, y: T) {} | ^^ - ---- ---- this parameter needs to match the fn item type of `x` | | | | | `y` needs to match the fn item type of this parameter - | `x` and `y` all reference this parameter T + | `x` and `y` both reference this parameter `T` = help: consider casting both fn items to fn pointers using `as fn()` error[E0308]: mismatched types @@ -105,7 +105,7 @@ LL | fn eq(x: T, y: T) {} | ^^ - ---- ---- this parameter needs to match the fn item type of `x` | | | | | `y` needs to match the fn item type of this parameter - | `x` and `y` all reference this parameter T + | `x` and `y` both reference this parameter `T` error: aborting due to 5 previous errors diff --git a/tests/ui/fn/param-mismatch-no-names.rs b/tests/ui/fn/param-mismatch-no-names.rs new file mode 100644 index 0000000000000..05f3de190ea92 --- /dev/null +++ b/tests/ui/fn/param-mismatch-no-names.rs @@ -0,0 +1,8 @@ +fn same_type(_: T, _: T) {} + +fn f(x: X, y: Y) { + same_type([x], Some(y)); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/fn/param-mismatch-no-names.stderr b/tests/ui/fn/param-mismatch-no-names.stderr new file mode 100644 index 0000000000000..d9d360d5ae4f5 --- /dev/null +++ b/tests/ui/fn/param-mismatch-no-names.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/param-mismatch-no-names.rs:4:20 + | +LL | same_type([x], Some(y)); + | --------- --- ^^^^^^^ expected `[X; 1]`, found `Option` + | | | + | | expected all arguments to be this `[X; 1]` type because they need to match the type of this parameter + | arguments to this function are incorrect + | + = note: expected array `[X; 1]` + found enum `Option` +note: function defined here + --> $DIR/param-mismatch-no-names.rs:1:4 + | +LL | fn same_type(_: T, _: T) {} + | ^^^^^^^^^ - ---- ---- this parameter needs to match the `[X; 1]` type of parameter #1 + | | | + | | parameter #2 needs to match the `[X; 1]` type of this parameter + | parameter #1 and parameter #2 both reference this parameter `T` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr index a845dfabe93b7..0a86f884e70db 100644 --- a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr +++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr @@ -14,7 +14,7 @@ LL | fn foo(a: T, b: T) {} | ^^^ - ---- ---- this parameter needs to match the integer type of `a` | | | | | `b` needs to match the integer type of this parameter - | `a` and `b` all reference this parameter T + | `a` and `b` both reference this parameter `T` error[E0308]: arguments to this function are incorrect --> $DIR/generic-mismatch-reporting-issue-116615.rs:8:5 @@ -38,7 +38,7 @@ LL | fn foo_multi_same(a: T, b: T, c: T, d: T, e: T, f: i32) {} | | | | this parameter needs to match the `&str` type of `a` and `b` | | | `c`, `d` and `e` need to match the `&str` type of this parameter | | `c`, `d` and `e` need to match the `&str` type of this parameter - | `a`, `b`, `c`, `d` and `e` all reference this parameter T + | `a`, `b`, `c`, `d` and `e` all reference this parameter `T` error[E0308]: arguments to this function are incorrect --> $DIR/generic-mismatch-reporting-issue-116615.rs:10:5 @@ -65,8 +65,8 @@ LL | fn foo_multi_generics(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {} | | | | | `d` and `e` need to match the `&str` type of this parameter | | | | `d` and `e` need to match the `&str` type of this parameter | | | `d` and `e` need to match the `&str` type of this parameter - | | `a`, `b`, `c`, `d` and `e` all reference this parameter T - | `f` and `g` all reference this parameter S + | | `a`, `b`, `c`, `d` and `e` all reference this parameter `T` + | `f` and `g` both reference this parameter `S` error[E0308]: arguments to this function are incorrect --> $DIR/generic-mismatch-reporting-issue-116615.rs:12:5 @@ -90,7 +90,7 @@ LL | fn foo_multi_same(a: T, b: T, c: T, d: T, e: T, f: i32) {} | | | | this parameter needs to match the `&str` type of `a`, `d` and `e` | | | this parameter needs to match the `&str` type of `a`, `d` and `e` | | `b` and `c` need to match the `&str` type of this parameter - | `a`, `b`, `c`, `d` and `e` all reference this parameter T + | `a`, `b`, `c`, `d` and `e` all reference this parameter `T` error: aborting due to 4 previous errors From 98777b4c490386ab7889718e811d28ce7423f0af Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 14 Nov 2024 16:55:27 +1100 Subject: [PATCH 07/13] Merge `TokenTreesReader` into `StringReader`. There is a not-very-useful layering in the lexer, where `TokenTreesReader` contains a `StringReader`. This commit combines them and names the result `Lexer`, which is a more obvious name for it. The methods of `Lexer` are now split across `mod.rs` and `tokentrees.rs` which isn't ideal, but it doesn't seem worth moving a bunch of code to avoid it. --- compiler/rustc_parse/src/lexer/mod.rs | 21 +++++--- compiler/rustc_parse/src/lexer/tokentrees.rs | 51 +++++-------------- .../rustc_parse/src/lexer/unicode_chars.rs | 8 +-- 3 files changed, 31 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 5023e83bd67c7..0ef5e9ed1d4a3 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -18,6 +18,7 @@ use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Pos, Span}; use tracing::debug; +use crate::lexer::diagnostics::TokenTreeDiagInfo; use crate::lexer::unicode_chars::UNICODE_ARRAY; use crate::{errors, make_unclosed_delims_error}; @@ -56,7 +57,7 @@ pub(crate) fn lex_token_trees<'psess, 'src>( } let cursor = Cursor::new(src); - let string_reader = StringReader { + let mut lexer = Lexer { psess, start_pos, pos: start_pos, @@ -65,9 +66,12 @@ pub(crate) fn lex_token_trees<'psess, 'src>( override_span, nbsp_is_whitespace: false, last_lifetime: None, + token: Token::dummy(), + diag_info: TokenTreeDiagInfo::default(), }; - let (stream, res, unmatched_delims) = - tokentrees::TokenTreesReader::lex_all_token_trees(string_reader); + let (_open_spacing, stream, res) = lexer.lex_token_trees(/* is_delimited */ false); + let unmatched_delims = lexer.diag_info.unmatched_delims; + match res { Ok(()) if unmatched_delims.is_empty() => Ok(stream), _ => { @@ -92,7 +96,7 @@ pub(crate) fn lex_token_trees<'psess, 'src>( } } -struct StringReader<'psess, 'src> { +struct Lexer<'psess, 'src> { psess: &'psess ParseSess, /// Initial position, read-only. start_pos: BytePos, @@ -111,9 +115,14 @@ struct StringReader<'psess, 'src> { /// Track the `Span` for the leading `'` of the last lifetime. Used for /// diagnostics to detect possible typo where `"` was meant. last_lifetime: Option, + + /// The current token. + token: Token, + + diag_info: TokenTreeDiagInfo, } -impl<'psess, 'src> StringReader<'psess, 'src> { +impl<'psess, 'src> Lexer<'psess, 'src> { fn dcx(&self) -> DiagCtxtHandle<'psess> { self.psess.dcx() } @@ -124,7 +133,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { /// Returns the next token, paired with a bool indicating if the token was /// preceded by whitespace. - fn next_token(&mut self) -> (Token, bool) { + fn next_token_from_cursor(&mut self) -> (Token, bool) { let mut preceded_by_whitespace = false; let mut swallow_next_invalid = 0; // Skip trivial (whitespace & comments) tokens diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 7b21ffacc841d..fab92aff74011 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -4,41 +4,19 @@ use rustc_ast_pretty::pprust::token_to_string; use rustc_errors::{Applicability, PErr}; use rustc_span::symbol::kw; -use super::diagnostics::{ - TokenTreeDiagInfo, report_suspicious_mismatch_block, same_indentation_level, -}; -use super::{StringReader, UnmatchedDelim}; +use super::diagnostics::{report_suspicious_mismatch_block, same_indentation_level}; +use super::{Lexer, UnmatchedDelim}; use crate::Parser; -pub(super) struct TokenTreesReader<'psess, 'src> { - string_reader: StringReader<'psess, 'src>, - /// The "next" token, which has been obtained from the `StringReader` but - /// not yet handled by the `TokenTreesReader`. - token: Token, - diag_info: TokenTreeDiagInfo, -} - -impl<'psess, 'src> TokenTreesReader<'psess, 'src> { - pub(super) fn lex_all_token_trees( - string_reader: StringReader<'psess, 'src>, - ) -> (TokenStream, Result<(), Vec>>, Vec) { - let mut tt_reader = TokenTreesReader { - string_reader, - token: Token::dummy(), - diag_info: TokenTreeDiagInfo::default(), - }; - let (_open_spacing, stream, res) = tt_reader.lex_token_trees(/* is_delimited */ false); - (stream, res, tt_reader.diag_info.unmatched_delims) - } - +impl<'psess, 'src> Lexer<'psess, 'src> { // Lex into a token stream. The `Spacing` in the result is that of the // opening delimiter. - fn lex_token_trees( + pub(super) fn lex_token_trees( &mut self, is_delimited: bool, ) -> (Spacing, TokenStream, Result<(), Vec>>) { // Move past the opening delimiter. - let (_, open_spacing) = self.bump(false); + let open_spacing = self.bump(false).1; let mut buf = Vec::new(); loop { @@ -80,7 +58,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { fn eof_err(&mut self) -> PErr<'psess> { let msg = "this file contains an unclosed delimiter"; - let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg); + let mut err = self.dcx().struct_span_err(self.token.span, msg); let unclosed_delimiter_show_limit = 5; let len = usize::min(unclosed_delimiter_show_limit, self.diag_info.open_braces.len()); @@ -110,7 +88,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { report_suspicious_mismatch_block( &mut err, &self.diag_info, - self.string_reader.psess.source_map(), + self.psess.source_map(), *delim, ) } @@ -136,7 +114,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { // Expand to cover the entire delimited token tree. let delim_span = DelimSpan::from_pair(pre_span, self.token.span); - let sm = self.string_reader.psess.source_map(); + let sm = self.psess.source_map(); let close_spacing = match self.token.kind { // Correct delimiter. @@ -228,7 +206,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { // Will glue adjacent single-char tokens together if `glue` is set. fn bump(&mut self, glue: bool) -> (Token, Spacing) { let (this_spacing, next_tok) = loop { - let (next_tok, is_next_tok_preceded_by_whitespace) = self.string_reader.next_token(); + let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor(); if is_next_tok_preceded_by_whitespace { break (Spacing::Alone, next_tok); @@ -256,7 +234,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { ) -> Vec> { // If there are unclosed delims, see if there are diff markers and if so, point them // out instead of complaining about the unclosed delims. - let mut parser = Parser::new(self.string_reader.psess, tts, None); + let mut parser = Parser::new(self.psess, tts, None); let mut diff_errs = vec![]; // Suggest removing a `{` we think appears in an `if`/`while` condition. // We want to suggest removing a `{` only if we think we're in an `if`/`while` condition, @@ -314,14 +292,9 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { // An unexpected closing delimiter (i.e., there is no matching opening delimiter). let token_str = token_to_string(&self.token); let msg = format!("unexpected closing delimiter: `{token_str}`"); - let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg); + let mut err = self.dcx().struct_span_err(self.token.span, msg); - report_suspicious_mismatch_block( - &mut err, - &self.diag_info, - self.string_reader.psess.source_map(), - delim, - ); + report_suspicious_mismatch_block(&mut err, &self.diag_info, self.psess.source_map(), delim); err.span_label(self.token.span, "unexpected closing delimiter"); err } diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index d78b3664b1ee8..42eef27803eb5 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -4,7 +4,7 @@ use rustc_span::symbol::kw; use rustc_span::{BytePos, Pos, Span}; -use super::StringReader; +use super::Lexer; use crate::errors::TokenSubstitution; use crate::token::{self, Delimiter}; @@ -338,7 +338,7 @@ const ASCII_ARRAY: &[(&str, &str, Option)] = &[ ]; pub(super) fn check_for_substitution( - reader: &StringReader<'_, '_>, + lexer: &Lexer<'_, '_>, pos: BytePos, ch: char, count: usize, @@ -351,11 +351,11 @@ pub(super) fn check_for_substitution( let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else { let msg = format!("substitution character not found for '{ch}'"); - reader.dcx().span_bug(span, msg); + lexer.dcx().span_bug(span, msg); }; // special help suggestion for "directed" double quotes - let sugg = if let Some(s) = peek_delimited(&reader.src[reader.src_index(pos)..], '“', '”') { + let sugg = if let Some(s) = peek_delimited(&lexer.src[lexer.src_index(pos)..], '“', '”') { let span = Span::with_root_ctxt( pos, pos + Pos::from_usize('“'.len_utf8() + s.len() + '”'.len_utf8()), From 593cf680aa6578d48998dac05532d76dfcad07ac Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 Nov 2024 10:01:22 +1100 Subject: [PATCH 08/13] Split `Lexer::bump`. It has two different ways of being called. --- compiler/rustc_parse/src/lexer/tokentrees.rs | 34 ++++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index fab92aff74011..c6c9eb3b0b263 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -16,7 +16,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { is_delimited: bool, ) -> (Spacing, TokenStream, Result<(), Vec>>) { // Move past the opening delimiter. - let open_spacing = self.bump(false).1; + let open_spacing = self.bump_minimal(); let mut buf = Vec::new(); loop { @@ -49,7 +49,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { } _ => { // Get the next normal token. - let (this_tok, this_spacing) = self.bump(true); + let (this_tok, this_spacing) = self.bump(); buf.push(TokenTree::Token(this_tok, this_spacing)); } } @@ -138,7 +138,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { } // Move past the closing delimiter. - self.bump(false).1 + self.bump_minimal() } // Incorrect delimiter. token::CloseDelim(close_delim) => { @@ -181,7 +181,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { // bar(baz( // } // Incorrect delimiter but matches the earlier `{` if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) { - self.bump(false).1 + self.bump_minimal() } else { // The choice of value here doesn't matter. Spacing::Alone @@ -203,14 +203,14 @@ impl<'psess, 'src> Lexer<'psess, 'src> { } // Move on to the next token, returning the current token and its spacing. - // Will glue adjacent single-char tokens together if `glue` is set. - fn bump(&mut self, glue: bool) -> (Token, Spacing) { + // Will glue adjacent single-char tokens together. + fn bump(&mut self) -> (Token, Spacing) { let (this_spacing, next_tok) = loop { let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor(); if is_next_tok_preceded_by_whitespace { break (Spacing::Alone, next_tok); - } else if glue && let Some(glued) = self.token.glue(&next_tok) { + } else if let Some(glued) = self.token.glue(&next_tok) { self.token = glued; } else { let this_spacing = if next_tok.is_punct() { @@ -227,6 +227,26 @@ impl<'psess, 'src> Lexer<'psess, 'src> { (this_tok, this_spacing) } + // Cut-down version of `bump` used when the token kind is known in advance. + fn bump_minimal(&mut self) -> Spacing { + let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor(); + + let this_spacing = if is_next_tok_preceded_by_whitespace { + Spacing::Alone + } else { + if next_tok.is_punct() { + Spacing::Joint + } else if next_tok == token::Eof { + Spacing::Alone + } else { + Spacing::JointHidden + } + }; + + self.token = next_tok; + this_spacing + } + fn unclosed_delim_err( &mut self, tts: TokenStream, From ba1a1ddc3f8c8007061c6f915448b22880da61ca Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 Nov 2024 10:05:49 +1100 Subject: [PATCH 09/13] Fix some formatting. Must be one of those cases where the function is too long and rustfmt bails out. --- compiler/rustc_parse/src/lexer/mod.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 0ef5e9ed1d4a3..202a2fbee22aa 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -240,7 +240,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .push(span); token::Ident(sym, IdentIsRaw::No) } - // split up (raw) c string literals to an ident and a string literal when edition < 2021. + // split up (raw) c string literals to an ident and a string literal when edition < + // 2021. rustc_lexer::TokenKind::Literal { kind: kind @ (LiteralKind::CStr { .. } | LiteralKind::RawCStr { .. }), suffix_start: _, @@ -261,7 +262,9 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let prefix_span = self.mk_sp(start, lit_start); return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace); } - rustc_lexer::TokenKind::GuardedStrPrefix => self.maybe_report_guarded_str(start, str_before), + rustc_lexer::TokenKind::GuardedStrPrefix => { + self.maybe_report_guarded_str(start, str_before) + } rustc_lexer::TokenKind::Literal { kind, suffix_start } => { let suffix_start = start + BytePos(suffix_start); let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind); @@ -305,13 +308,20 @@ impl<'psess, 'src> Lexer<'psess, 'src> { if prefix_span.at_least_rust_2021() { let span = self.mk_sp(start, self.pos); - let lifetime_name_without_tick = Symbol::intern(&self.str_from(ident_start)); + let lifetime_name_without_tick = + Symbol::intern(&self.str_from(ident_start)); if !lifetime_name_without_tick.can_be_raw() { - self.dcx().emit_err(errors::CannotBeRawLifetime { span, ident: lifetime_name_without_tick }); + self.dcx().emit_err( + errors::CannotBeRawLifetime { + span, + ident: lifetime_name_without_tick + } + ); } // Put the `'` back onto the lifetime name. - let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.as_str().len() + 1); + let mut lifetime_name = + String::with_capacity(lifetime_name_without_tick.as_str().len() + 1); lifetime_name.push('\''); lifetime_name += lifetime_name_without_tick.as_str(); let sym = Symbol::intern(&lifetime_name); From 11c96cfd94a9b24a11d20c94686929126991f8d9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 Nov 2024 11:00:46 +1100 Subject: [PATCH 10/13] Improve `strip_shebang` testing. It's currently a bit ad hoc. This commit makes it more methodical, with pairs of match/no-match tests for all the relevant cases. --- compiler/rustc_lexer/src/tests.rs | 72 +++++++++++++------------------ 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs index 556bbf1f5182e..db7225fc2a810 100644 --- a/compiler/rustc_lexer/src/tests.rs +++ b/compiler/rustc_lexer/src/tests.rs @@ -77,61 +77,51 @@ fn test_too_many_hashes() { check_raw_str(&s2, Err(RawStrError::TooManyDelimiters { found: u32::from(max_count) + 1 })); } +// https://github.com/rust-lang/rust/issues/70528 #[test] fn test_valid_shebang() { - // https://github.com/rust-lang/rust/issues/70528 - let input = "#!/usr/bin/rustrun\nlet x = 5;"; - assert_eq!(strip_shebang(input), Some(18)); -} + let input = "#!/bin/bash"; + assert_eq!(strip_shebang(input), Some(input.len())); -#[test] -fn test_invalid_shebang_valid_rust_syntax() { - // https://github.com/rust-lang/rust/issues/70528 - let input = "#! [bad_attribute]"; + let input = "#![attribute]"; assert_eq!(strip_shebang(input), None); -} -#[test] -fn test_shebang_second_line() { - // Because shebangs are interpreted by the kernel, they must be on the first line - let input = "\n#!/bin/bash"; + let input = "#! /bin/bash"; + assert_eq!(strip_shebang(input), Some(input.len())); + + let input = "#! [attribute]"; assert_eq!(strip_shebang(input), None); -} -#[test] -fn test_shebang_space() { - let input = "#! /bin/bash"; + let input = "#! /* blah */ /bin/bash"; assert_eq!(strip_shebang(input), Some(input.len())); -} -#[test] -fn test_shebang_empty_shebang() { - let input = "#! \n[attribute(foo)]"; + let input = "#! /* blah */ [attribute]"; assert_eq!(strip_shebang(input), None); -} -#[test] -fn test_invalid_shebang_comment() { - let input = "#!//bin/ami/a/comment\n["; - assert_eq!(strip_shebang(input), None) -} + let input = "#! // blah\n/bin/bash"; + assert_eq!(strip_shebang(input), Some(10)); // strip up to the newline -#[test] -fn test_invalid_shebang_another_comment() { - let input = "#!/*bin/ami/a/comment*/\n[attribute"; - assert_eq!(strip_shebang(input), None) -} + let input = "#! // blah\n[attribute]"; + assert_eq!(strip_shebang(input), None); -#[test] -fn test_shebang_valid_rust_after() { - let input = "#!/*bin/ami/a/comment*/\npub fn main() {}"; - assert_eq!(strip_shebang(input), Some(23)) -} + let input = "#! /* blah\nblah\nblah */ /bin/bash"; + assert_eq!(strip_shebang(input), Some(10)); -#[test] -fn test_shebang_followed_by_attrib() { - let input = "#!/bin/rust-scripts\n#![allow_unused(true)]"; - assert_eq!(strip_shebang(input), Some(19)); + let input = "#! /* blah\nblah\nblah */ [attribute]"; + assert_eq!(strip_shebang(input), None); + + let input = "#!\n/bin/sh"; + assert_eq!(strip_shebang(input), Some(2)); + + let input = "#!\n[attribute]"; + assert_eq!(strip_shebang(input), None); + + // Because shebangs are interpreted by the kernel, they must be on the first line + let input = "\n#!/bin/bash"; + assert_eq!(strip_shebang(input), None); + + let input = "\n#![attribute]"; + assert_eq!(strip_shebang(input), None); } fn check_lexing(src: &str, expect: Expect) { From 4cd2840f003a1aa29da7e688043b954b4659b2ca Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 Nov 2024 14:01:53 +1100 Subject: [PATCH 11/13] Clean up `c_or_byte_string`. - Rename a misleading local `mk_kind` as `single_quoted`. - Use `fn` for all three arguments, for consistency. --- compiler/rustc_lexer/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index bcb103957badf..b584e7afd98fa 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -566,19 +566,19 @@ impl Cursor<'_> { fn c_or_byte_string( &mut self, - mk_kind: impl FnOnce(bool) -> LiteralKind, - mk_kind_raw: impl FnOnce(Option) -> LiteralKind, + mk_kind: fn(bool) -> LiteralKind, + mk_kind_raw: fn(Option) -> LiteralKind, single_quoted: Option LiteralKind>, ) -> TokenKind { match (self.first(), self.second(), single_quoted) { - ('\'', _, Some(mk_kind)) => { + ('\'', _, Some(single_quoted)) => { self.bump(); let terminated = self.single_quoted_string(); let suffix_start = self.pos_within_token(); if terminated { self.eat_literal_suffix(); } - let kind = mk_kind(terminated); + let kind = single_quoted(terminated); Literal { kind, suffix_start } } ('"', _, _) => { From 16a39bb7ca7d2af14069deef36291ca1c41b4bb0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 Nov 2024 14:54:15 +1100 Subject: [PATCH 12/13] Streamline `lex_token_trees` error handling. - Use iterators instead of `for` loops. - Use `if`/`else` instead of `match`. --- compiler/rustc_parse/src/lexer/mod.rs | 34 +++++++++++---------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 202a2fbee22aa..8db3b174a89fc 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -72,27 +72,21 @@ pub(crate) fn lex_token_trees<'psess, 'src>( let (_open_spacing, stream, res) = lexer.lex_token_trees(/* is_delimited */ false); let unmatched_delims = lexer.diag_info.unmatched_delims; - match res { - Ok(()) if unmatched_delims.is_empty() => Ok(stream), - _ => { - // Return error if there are unmatched delimiters or unclosed delimiters. - // We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch - // because the delimiter mismatch is more likely to be the root cause of error - - let mut buffer = Vec::with_capacity(1); - for unmatched in unmatched_delims { - if let Some(err) = make_unclosed_delims_error(unmatched, psess) { - buffer.push(err); - } - } - if let Err(errs) = res { - // Add unclosing delimiter or diff marker errors - for err in errs { - buffer.push(err); - } - } - Err(buffer) + if res.is_ok() && unmatched_delims.is_empty() { + Ok(stream) + } else { + // Return error if there are unmatched delimiters or unclosed delimiters. + // We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch + // because the delimiter mismatch is more likely to be the root cause of error + let mut buffer: Vec<_> = unmatched_delims + .into_iter() + .filter_map(|unmatched_delim| make_unclosed_delims_error(unmatched_delim, psess)) + .collect(); + if let Err(errs) = res { + // Add unclosing delimiter or diff marker errors + buffer.extend(errs); } + Err(buffer) } } From c9b56b9694c57dcf41a148e73384702f103b137f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2024 08:00:22 +0100 Subject: [PATCH 13/13] miri: disable test_downgrade_observe test on macOS --- library/std/src/sync/rwlock/tests.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs index 29cad4400f189..48d442921f7fc 100644 --- a/library/std/src/sync/rwlock/tests.rs +++ b/library/std/src/sync/rwlock/tests.rs @@ -511,12 +511,15 @@ fn test_downgrade_basic() { } #[test] +// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. +// See for details. +#[cfg_attr(all(miri, target_os = "macos"), ignore)] fn test_downgrade_observe() { // Taken from the test `test_rwlock_downgrade` from: // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs const W: usize = 20; - const N: usize = 100; + const N: usize = if cfg!(miri) { 40 } else { 100 }; // This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring // that the value they wrote has not changed after downgrading.