From 69446e301cc271fca77b4d4f119540d6b82f1677 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 30 Jun 2024 13:33:33 -0400 Subject: [PATCH 01/18] Print `TypeId` as hex for debugging In , the `Debug` impl for `TypeId` was changed to print a single integer rather than a tuple. Change this again to print as hex for more concise and consistent formatting, as was suggested. Result: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7) --- library/core/src/any.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/any.rs b/library/core/src/any.rs index eab11ae288a95..59f3b6841d531 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -673,7 +673,7 @@ impl hash::Hash for TypeId { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for TypeId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.debug_tuple("TypeId").field(&self.as_u128()).finish() + write!(f, "TypeId({:#034x})", self.as_u128()) } } From 23e5468a09b7cfcb62f69dc18bb1f49c5e69b2b5 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Mon, 1 Jul 2024 00:08:42 +0300 Subject: [PATCH 02/18] LinkedList's Cursor: method to get a ref to the cursor's list --- library/alloc/src/collections/linked_list.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 01510a6140512..077483a174b10 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1495,6 +1495,14 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> { pub fn back(&self) -> Option<&'a T> { self.list.back() } + + /// Provides a reference to the cursor's parent list. + #[must_use] + #[inline(always)] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn as_list(&self) -> &'a LinkedList { + self.list + } } impl<'a, T, A: Allocator> CursorMut<'a, T, A> { @@ -1605,6 +1613,18 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { pub fn as_cursor(&self) -> Cursor<'_, T, A> { Cursor { list: self.list, current: self.current, index: self.index } } + + /// Provides a read-only reference to the cursor's parent list. + /// + /// The lifetime of the returned reference is bound to that of the + /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the + /// `CursorMut` is frozen for the lifetime of the reference. + #[must_use] + #[inline(always)] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn as_list(&self) -> &LinkedList { + self.list + } } // Now the list editing operations From ba1ebc266b253a2eb001f88b351e8862095c4a06 Mon Sep 17 00:00:00 2001 From: Xinzhao Xu Date: Tue, 2 Jul 2024 17:30:36 +0800 Subject: [PATCH 03/18] doc: update config file path in platform-support/wasm32-wasip1-threads.md --- src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md index 2b3d15e93c8cb..c3eda26ca8ef9 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md @@ -107,7 +107,7 @@ flag, for example: Users need to install or built wasi-sdk since release 20.0 https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-20 -and specify path to *wasi-root* `.cargo/config.toml` +and specify path to *wasi-root* `config.toml` ```toml [target.wasm32-wasip1-threads] From a7372372f6c3b81804c2b83f2a0e9c0bc7d08e13 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Tue, 2 Jul 2024 19:50:39 -0500 Subject: [PATCH 04/18] Add test case demonstrating equality of paths "foo/bar" and "foobar" --- library/std/src/path/tests.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 92702b395dfe1..53a65c60b580c 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1566,6 +1566,13 @@ pub fn test_compare() { relative_from: Some("bar") ); + tc!("foo/bar", "foobar", + eq: false, + starts_with: false, + ends_with: false, + relative_from: None + ); + tc!("foo/bar/baz", "foo/bar", eq: false, starts_with: true, From dd509c7a6399f2784fa940d27a9f463da7e81d58 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Tue, 2 Jul 2024 23:12:06 -0500 Subject: [PATCH 05/18] Add more test cases for path comparisons --- library/std/src/path/tests.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 53a65c60b580c..87a06a9ea9153 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1545,6 +1545,20 @@ pub fn test_compare() { relative_from: Some("") ); + tc!("foo//", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo///", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + tc!("foo/.", "foo", eq: true, starts_with: true, @@ -1559,6 +1573,20 @@ pub fn test_compare() { relative_from: Some("") ); + tc!("foo/.//bar", "foo/bar", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo//./bar", "foo/bar", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + tc!("foo/bar", "foo", eq: false, starts_with: true, From f21683432b72694b4558d779d6b5e5d49102ad7e Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 3 Jul 2024 22:54:15 +0200 Subject: [PATCH 06/18] stir the hash state a little to avoid prefix collisions --- library/std/src/path.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index caae8f924d2b1..e8f0b41f1f4c3 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3098,15 +3098,19 @@ impl Hash for Path { let bytes = &bytes[prefix_len..]; let mut component_start = 0; - let mut bytes_hashed = 0; + // track some extra state to avoid prefix collisions. + // ["foo", "bar"] and ["foobar"], will have the same payload bytes + // but result in different chunk_bits + let mut chunk_bits: usize = 0; for i in 0..bytes.len() { let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) }; if is_sep { if i > component_start { let to_hash = &bytes[component_start..i]; + chunk_bits = chunk_bits.wrapping_add(to_hash.len()); + chunk_bits = chunk_bits.rotate_right(2); h.write(to_hash); - bytes_hashed += to_hash.len(); } // skip over separator and optionally a following CurDir item @@ -3127,11 +3131,12 @@ impl Hash for Path { if component_start < bytes.len() { let to_hash = &bytes[component_start..]; + chunk_bits = chunk_bits.wrapping_add(to_hash.len()); + chunk_bits = chunk_bits.rotate_right(2); h.write(to_hash); - bytes_hashed += to_hash.len(); } - h.write_usize(bytes_hashed); + h.write_usize(chunk_bits); } } From dd790ab8ef8cc2a89f04f2be73c86230595a48a3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 4 Jul 2024 17:50:53 +1000 Subject: [PATCH 07/18] Remove some unnecessary integer conversions. These should have been removed in #127233 when the positions were changed from `usize` to `u32`. --- compiler/rustc_parse/src/parser/attr.rs | 4 ++-- compiler/rustc_parse/src/parser/attr_wrapper.rs | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 58fef9b6c4562..1d31669d2074e 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -282,7 +282,7 @@ impl<'a> Parser<'a> { pub fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> { let mut attrs = ast::AttrVec::new(); loop { - let start_pos: u32 = self.num_bump_calls.try_into().unwrap(); + let start_pos = self.num_bump_calls; // Only try to parse if it is an inner attribute (has `!`). let attr = if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) { Some(self.parse_attribute(InnerAttrPolicy::Permitted)?) @@ -303,7 +303,7 @@ impl<'a> Parser<'a> { None }; if let Some(attr) = attr { - let end_pos: u32 = self.num_bump_calls.try_into().unwrap(); + let end_pos = self.num_bump_calls; // If we are currently capturing tokens, mark the location of this inner attribute. // If capturing ends up creating a `LazyAttrTokenStream`, we will include // this replace range with it, removing the inner attribute from the final diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 13a647adfe3b5..53565ffe2c903 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -8,7 +8,6 @@ use rustc_errors::PResult; use rustc_session::parse::ParseSess; use rustc_span::{sym, Span, DUMMY_SP}; -use std::ops::Range; use std::{iter, mem}; /// A wrapper type to ensure that the parser handles outer attributes correctly. @@ -356,8 +355,7 @@ impl<'a> Parser<'a> { let new_tokens = vec![(FlatToken::AttrTarget(attr_data), Spacing::Alone)]; assert!(!self.break_last_token, "Should not have unglued last token with cfg attr"); - let range: Range = (start_pos.try_into().unwrap())..(end_pos.try_into().unwrap()); - self.capture_state.replace_ranges.push((range, new_tokens)); + self.capture_state.replace_ranges.push((start_pos..end_pos, new_tokens)); self.capture_state.replace_ranges.extend(inner_attr_replace_ranges); } From ccd8dccfc6c19329e9c82e727a877113b8af9860 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Fri, 5 Jul 2024 01:55:01 -0400 Subject: [PATCH 08/18] Describe Sized requirements for mem::offset_of The container doesn't have to be sized, but the field must be sized (at least until https://github.com/rust-lang/rust/issues/126151 is stable). --- library/core/src/mem/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 9054ade2d7968..dd4b6e823434e 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1266,6 +1266,20 @@ impl SizedTypeProperties for T {} /// // ^^^ error[E0616]: field `private` of struct `Struct` is private /// ``` /// +/// Only [`Sized`] fields are supported, but the container may be unsized: +/// ``` +/// # use core::mem; +/// #[repr(C)] +/// pub struct Struct { +/// a: u8, +/// b: [u8], +/// } +/// +/// assert_eq!(mem::offset_of!(Struct, a), 0); // OK +/// // assert_eq!(mem::offset_of!(Struct, b), 1); +/// // ^^^ error[E0277]: doesn't have a size known at compile-time +/// ``` +/// /// Note that type layout is, in general, [subject to change and /// platform-specific](https://doc.rust-lang.org/reference/type-layout.html). If /// layout stability is required, consider using an [explicit `repr` attribute]. From 14b859fa3be22289d810df1cc8bd2aaf6fc299be Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 4 Jul 2024 09:04:51 +1000 Subject: [PATCH 09/18] Rename `Attribute::tokens` (the inherent method). To distinguish it from the `HasTokens` method. --- compiler/rustc_ast/src/attr/mod.rs | 3 ++- compiler/rustc_ast/src/tokenstream.rs | 4 ++-- compiler/rustc_expand/src/config.rs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 65f1b5dbaf5b7..088ae9ba44102 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -202,7 +202,8 @@ impl Attribute { } } - pub fn tokens(&self) -> TokenStream { + // Named `get_tokens` to distinguish it from the `::tokens` method. + pub fn get_tokens(&self) -> TokenStream { match &self.kind { AttrKind::Normal(normal) => TokenStream::new( normal diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 655c18e45597a..06a669e795754 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -227,7 +227,7 @@ impl AttrTokenStream { let mut stream = TokenStream::default(); for inner_attr in inner_attrs { - stream.push_stream(inner_attr.tokens()); + stream.push_stream(inner_attr.get_tokens()); } stream.push_stream(delim_tokens.clone()); *tree = TokenTree::Delimited(*span, *spacing, *delim, stream); @@ -242,7 +242,7 @@ impl AttrTokenStream { ); } for attr in outer_attrs { - res.extend(attr.tokens().0.iter().cloned()); + res.extend(attr.get_tokens().0.iter().cloned()); } res.extend(target_tokens); } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 56cbb54fcecf7..561ac6bdd513b 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -294,7 +294,7 @@ impl<'a> StripUnconfigured<'a> { attr: &Attribute, (item, item_span): (ast::AttrItem, Span), ) -> Attribute { - let orig_tokens = attr.tokens(); + let orig_tokens = attr.get_tokens(); // We are taking an attribute of the form `#[cfg_attr(pred, attr)]` // and producing an attribute of the form `#[attr]`. We From 88373e9f0c81dd55dd3a663bcfbaa27052c53beb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 4 Jul 2024 09:30:03 +1000 Subject: [PATCH 10/18] Remove an unnecessary local variable. --- compiler/rustc_expand/src/config.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 561ac6bdd513b..21ff56febb378 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -310,12 +310,11 @@ impl<'a> StripUnconfigured<'a> { else { panic!("Bad tokens for attribute {attr:?}"); }; - let pound_span = pound_token.span; // We don't really have a good span to use for the synthesized `[]` // in `#[attr]`, so just use the span of the `#` token. let bracket_group = AttrTokenTree::Delimited( - DelimSpan::from_single(pound_span), + DelimSpan::from_single(pound_token.span), DelimSpacing::new(Spacing::JointHidden, Spacing::Alone), Delimiter::Bracket, item.tokens From b261501b71c64ede374f71abae914a71dd723072 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 4 Jul 2024 11:27:39 +1000 Subject: [PATCH 11/18] Remove `HasSpan` trait. The only place it is meaningfully used is in a panic message in `TokenStream::from_ast`. But `node.span()` doesn't need to be printed because `node` is also printed and it must contain the span. --- compiler/rustc_ast/src/ast_traits.rs | 33 --------------------------- compiler/rustc_ast/src/lib.rs | 2 +- compiler/rustc_ast/src/tokenstream.rs | 6 ++--- compiler/rustc_resolve/src/late.rs | 2 +- 4 files changed, 5 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 2cf811e9122f6..7754ca0a0f503 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -10,8 +10,6 @@ use crate::{AssocItem, Expr, ForeignItem, Item, NodeId}; use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; use crate::{AttrVec, Attribute, Stmt, StmtKind}; -use rustc_span::Span; - use std::fmt; use std::marker::PhantomData; @@ -91,37 +89,6 @@ impl> HasNodeId for T { } } -/// A trait for AST nodes having a span. -pub trait HasSpan { - fn span(&self) -> Span; -} - -macro_rules! impl_has_span { - ($($T:ty),+ $(,)?) => { - $( - impl HasSpan for $T { - fn span(&self) -> Span { - self.span - } - } - )+ - }; -} - -impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility); - -impl> HasSpan for T { - fn span(&self) -> Span { - self.ast_deref().span() - } -} - -impl HasSpan for AttrItem { - fn span(&self) -> Span { - self.span() - } -} - /// A trait for AST nodes having (or not having) collected tokens. pub trait HasTokens { fn tokens(&self) -> Option<&LazyAttrTokenStream>; diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 7ca950e50e610..846a108091fcc 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -44,7 +44,7 @@ pub mod tokenstream; pub mod visit; pub use self::ast::*; -pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens}; +pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasTokens}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 06a669e795754..a84e33e5f92af 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -14,7 +14,7 @@ //! ownership of the original. use crate::ast::{AttrStyle, StmtKind}; -use crate::ast_traits::{HasAttrs, HasSpan, HasTokens}; +use crate::ast_traits::{HasAttrs, HasTokens}; use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind}; use crate::AttrVec; @@ -436,9 +436,9 @@ impl TokenStream { TokenStream::new(vec![TokenTree::token_alone(kind, span)]) } - pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream { + pub fn from_ast(node: &(impl HasAttrs + HasTokens + fmt::Debug)) -> TokenStream { let Some(tokens) = node.tokens() else { - panic!("missing tokens for node at {:?}: {:?}", node.span(), node); + panic!("missing tokens for node: {:?}", node); }; let attrs = node.attrs(); let attr_stream = if attrs.is_empty() { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ad4e222f4deda..1d37264f96a3c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1744,7 +1744,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ) { self.r.dcx().emit_err(errors::LendingIteratorReportError { lifetime: lifetime.ident.span, - ty: ty.span(), + ty: ty.span, }); } else { self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError { From 9d33a8fe513fa237d5c008317e6a268143071597 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 4 Jul 2024 17:51:16 +1000 Subject: [PATCH 12/18] Simplify `ReplaceRange`. Currently the second element is a `Vec<(FlatToken, Spacing)>`. But the vector always has zero or one elements, and the `FlatToken` is always `FlatToken::AttrTarget` (which contains an `AttributesData`), and the spacing is always `Alone`. So we can simplify it to `Option`. An assertion in `to_attr_token_stream` can can also be removed, because `new_tokens.len()` was always 0 or 1, which means than `range.len()` is always greater than or equal to it, because `range.is_empty()` is always false (as per the earlier assertion). --- compiler/rustc_parse/src/parser/attr.rs | 2 +- .../rustc_parse/src/parser/attr_wrapper.rs | 39 +++++++++---------- compiler/rustc_parse/src/parser/mod.rs | 4 +- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 1d31669d2074e..a8fe35f45b31e 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -313,7 +313,7 @@ impl<'a> Parser<'a> { // corresponding macro). let range = start_pos..end_pos; if let Capturing::Yes = self.capture_state.capturing { - self.capture_state.inner_attr_ranges.insert(attr.id, (range, vec![])); + self.capture_state.inner_attr_ranges.insert(attr.id, (range, None)); } attrs.push(attr); } else { diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 53565ffe2c903..1aebbbe3559b9 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -145,24 +145,23 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // start position, we ensure that any replace range which encloses // another replace range will capture the *replaced* tokens for the inner // range, not the original tokens. - for (range, new_tokens) in replace_ranges.into_iter().rev() { + for (range, attr_data) in replace_ranges.into_iter().rev() { assert!(!range.is_empty(), "Cannot replace an empty range: {range:?}"); - // Replace ranges are only allowed to decrease the number of tokens. - assert!( - range.len() >= new_tokens.len(), - "Range {range:?} has greater len than {new_tokens:?}" - ); - - // Replace any removed tokens with `FlatToken::Empty`. - // This keeps the total length of `tokens` constant throughout the - // replacement process, allowing us to use all of the `ReplaceRanges` entries - // without adjusting indices. - let filler = iter::repeat((FlatToken::Empty, Spacing::Alone)) - .take(range.len() - new_tokens.len()); + // Replace the tokens in range with zero or one `FlatToken::AttrTarget`s, plus + // enough `FlatToken::Empty`s to fill up the rest of the range. This keeps the + // total length of `tokens` constant throughout the replacement process, allowing + // us to use all of the `ReplaceRanges` entries without adjusting indices. + let attr_data_len = attr_data.is_some() as usize; tokens.splice( (range.start as usize)..(range.end as usize), - new_tokens.into_iter().chain(filler), + attr_data + .into_iter() + .map(|attr_data| (FlatToken::AttrTarget(attr_data), Spacing::Alone)) + .chain( + iter::repeat((FlatToken::Empty, Spacing::Alone)) + .take(range.len() - attr_data_len), + ), ); } make_attr_token_stream(tokens.into_iter(), self.break_last_token) @@ -315,7 +314,7 @@ impl<'a> Parser<'a> { .iter() .cloned() .chain(inner_attr_replace_ranges.iter().cloned()) - .map(|(range, tokens)| ((range.start - start_pos)..(range.end - start_pos), tokens)) + .map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data)) .collect() }; @@ -345,17 +344,15 @@ impl<'a> Parser<'a> { && matches!(self.capture_state.capturing, Capturing::Yes) && has_cfg_or_cfg_attr(final_attrs) { - let attr_data = AttributesData { attrs: final_attrs.iter().cloned().collect(), tokens }; + assert!(!self.break_last_token, "Should not have unglued last token with cfg attr"); // Replace the entire AST node that we just parsed, including attributes, - // with a `FlatToken::AttrTarget`. If this AST node is inside an item + // with `attr_data`. If this AST node is inside an item // that has `#[derive]`, then this will allow us to cfg-expand this // AST node. let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos }; - let new_tokens = vec![(FlatToken::AttrTarget(attr_data), Spacing::Alone)]; - - assert!(!self.break_last_token, "Should not have unglued last token with cfg attr"); - self.capture_state.replace_ranges.push((start_pos..end_pos, new_tokens)); + let attr_data = AttributesData { attrs: final_attrs.iter().cloned().collect(), tokens }; + self.capture_state.replace_ranges.push((start_pos..end_pos, Some(attr_data))); self.capture_state.replace_ranges.extend(inner_attr_replace_ranges); } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 5f16a3e1f3784..1072e6392921d 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -203,7 +203,7 @@ struct ClosureSpans { } /// Indicates a range of tokens that should be replaced by -/// the tokens in the provided vector. This is used in two +/// the tokens in the provided `AttributesData`. This is used in two /// places during token collection: /// /// 1. During the parsing of an AST node that may have a `#[derive]` @@ -219,7 +219,7 @@ struct ClosureSpans { /// the first macro inner attribute to invoke a proc-macro). /// When create a `TokenStream`, the inner attributes get inserted /// into the proper place in the token stream. -type ReplaceRange = (Range, Vec<(FlatToken, Spacing)>); +type ReplaceRange = (Range, Option); /// Controls how we capture tokens. Capturing can be expensive, /// so we try to avoid performing capturing in cases where From 3a5c4b6e4e4c99f9d2d10cb64a0eb591c08322e4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 7 Jul 2024 16:14:30 +1000 Subject: [PATCH 13/18] Rename some attribute types for consistency. - `AttributesData` -> `AttrsTarget` - `AttrTokenTree::Attributes` -> `AttrTokenTree::AttrsTarget` - `FlatToken::AttrTarget` -> `FlatToken::AttrsTarget` --- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/tokenstream.rs | 22 +++++++------- compiler/rustc_builtin_macros/src/cfg_eval.rs | 2 +- compiler/rustc_expand/src/config.rs | 14 ++++----- .../rustc_parse/src/parser/attr_wrapper.rs | 29 +++++++++---------- compiler/rustc_parse/src/parser/mod.rs | 17 +++++------ 6 files changed, 42 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index f816375b912d6..cbf21317f1a77 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -704,7 +704,7 @@ fn visit_attr_tt(tt: &mut AttrTokenTree, vis: &mut T) { visit_attr_tts(tts, vis); visit_delim_span(dspan, vis); } - AttrTokenTree::Attributes(AttributesData { attrs, tokens }) => { + AttrTokenTree::AttrsTarget(AttrsTarget { attrs, tokens }) => { visit_attrs(attrs, vis); visit_lazy_tts_opt_mut(Some(tokens), vis); } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index a84e33e5f92af..f3b6dc2cfa198 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -170,8 +170,8 @@ pub enum AttrTokenTree { Delimited(DelimSpan, DelimSpacing, Delimiter, AttrTokenStream), /// Stores the attributes for an attribute target, /// along with the tokens for that attribute target. - /// See `AttributesData` for more information - Attributes(AttributesData), + /// See `AttrsTarget` for more information + AttrsTarget(AttrsTarget), } impl AttrTokenStream { @@ -180,7 +180,7 @@ impl AttrTokenStream { } /// Converts this `AttrTokenStream` to a plain `Vec`. - /// During conversion, `AttrTokenTree::Attributes` get 'flattened' + /// During conversion, `AttrTokenTree::AttrsTarget` get 'flattened' /// back to a `TokenStream` of the form `outer_attr attr_target`. /// If there are inner attributes, they are inserted into the proper /// place in the attribute target tokens. @@ -199,13 +199,13 @@ impl AttrTokenStream { TokenStream::new(stream.to_token_trees()), )) } - AttrTokenTree::Attributes(data) => { - let idx = data + AttrTokenTree::AttrsTarget(target) => { + let idx = target .attrs .partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer)); - let (outer_attrs, inner_attrs) = data.attrs.split_at(idx); + let (outer_attrs, inner_attrs) = target.attrs.split_at(idx); - let mut target_tokens = data.tokens.to_attr_token_stream().to_token_trees(); + let mut target_tokens = target.tokens.to_attr_token_stream().to_token_trees(); if !inner_attrs.is_empty() { let mut found = false; // Check the last two trees (to account for a trailing semi) @@ -262,7 +262,7 @@ impl AttrTokenStream { /// have an `attrs` field containing the `#[cfg(FALSE)]` attr, /// and a `tokens` field storing the (unparsed) tokens `struct Foo {}` #[derive(Clone, Debug, Encodable, Decodable)] -pub struct AttributesData { +pub struct AttrsTarget { /// Attributes, both outer and inner. /// These are stored in the original order that they were parsed in. pub attrs: AttrVec, @@ -444,9 +444,9 @@ impl TokenStream { let attr_stream = if attrs.is_empty() { tokens.to_attr_token_stream() } else { - let attr_data = - AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() }; - AttrTokenStream::new(vec![AttrTokenTree::Attributes(attr_data)]) + let target = + AttrsTarget { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() }; + AttrTokenStream::new(vec![AttrTokenTree::AttrsTarget(target)]) }; TokenStream::new(attr_stream.to_token_trees()) } diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 884cebf1939e4..b09975c0ba79e 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -193,7 +193,7 @@ impl CfgEval<'_> { // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture - // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`) + // `AttrTokenTree::AttrsTarget` for all occurrences of `#[cfg]` and `#[cfg_attr]`) let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None); parser.capture_cfg = true; match parse_annotatable_with(&mut parser) { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 21ff56febb378..be46b2af6cae9 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -172,7 +172,7 @@ impl<'a> StripUnconfigured<'a> { fn configure_tokens(&self, stream: &AttrTokenStream) -> AttrTokenStream { fn can_skip(stream: &AttrTokenStream) -> bool { stream.0.iter().all(|tree| match tree { - AttrTokenTree::Attributes(_) => false, + AttrTokenTree::AttrsTarget(_) => false, AttrTokenTree::Token(..) => true, AttrTokenTree::Delimited(.., inner) => can_skip(inner), }) @@ -186,14 +186,14 @@ impl<'a> StripUnconfigured<'a> { .0 .iter() .flat_map(|tree| match tree.clone() { - AttrTokenTree::Attributes(mut data) => { - data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); + AttrTokenTree::AttrsTarget(mut target) => { + target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); - if self.in_cfg(&data.attrs) { - data.tokens = LazyAttrTokenStream::new( - self.configure_tokens(&data.tokens.to_attr_token_stream()), + if self.in_cfg(&target.attrs) { + target.tokens = LazyAttrTokenStream::new( + self.configure_tokens(&target.tokens.to_attr_token_stream()), ); - Some(AttrTokenTree::Attributes(data)).into_iter() + Some(AttrTokenTree::AttrsTarget(target)).into_iter() } else { None.into_iter() } diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 1aebbbe3559b9..2e421a7f19306 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -1,6 +1,6 @@ use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken}; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; -use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, AttributesData, DelimSpacing}; +use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing}; use rustc_ast::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, ToAttrTokenStream}; use rustc_ast::{self as ast}; use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens}; @@ -145,22 +145,22 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // start position, we ensure that any replace range which encloses // another replace range will capture the *replaced* tokens for the inner // range, not the original tokens. - for (range, attr_data) in replace_ranges.into_iter().rev() { + for (range, target) in replace_ranges.into_iter().rev() { assert!(!range.is_empty(), "Cannot replace an empty range: {range:?}"); - // Replace the tokens in range with zero or one `FlatToken::AttrTarget`s, plus + // Replace the tokens in range with zero or one `FlatToken::AttrsTarget`s, plus // enough `FlatToken::Empty`s to fill up the rest of the range. This keeps the // total length of `tokens` constant throughout the replacement process, allowing // us to use all of the `ReplaceRanges` entries without adjusting indices. - let attr_data_len = attr_data.is_some() as usize; + let target_len = target.is_some() as usize; tokens.splice( (range.start as usize)..(range.end as usize), - attr_data + target .into_iter() - .map(|attr_data| (FlatToken::AttrTarget(attr_data), Spacing::Alone)) + .map(|target| (FlatToken::AttrsTarget(target), Spacing::Alone)) .chain( iter::repeat((FlatToken::Empty, Spacing::Alone)) - .take(range.len() - attr_data_len), + .take(range.len() - target_len), ), ); } @@ -346,13 +346,12 @@ impl<'a> Parser<'a> { { assert!(!self.break_last_token, "Should not have unglued last token with cfg attr"); - // Replace the entire AST node that we just parsed, including attributes, - // with `attr_data`. If this AST node is inside an item - // that has `#[derive]`, then this will allow us to cfg-expand this - // AST node. + // Replace the entire AST node that we just parsed, including attributes, with + // `target`. If this AST node is inside an item that has `#[derive]`, then this will + // allow us to cfg-expand this AST node. let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos }; - let attr_data = AttributesData { attrs: final_attrs.iter().cloned().collect(), tokens }; - self.capture_state.replace_ranges.push((start_pos..end_pos, Some(attr_data))); + let target = AttrsTarget { attrs: final_attrs.iter().cloned().collect(), tokens }; + self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target))); self.capture_state.replace_ranges.extend(inner_attr_replace_ranges); } @@ -414,11 +413,11 @@ fn make_attr_token_stream( .expect("Bottom token frame is missing!") .inner .push(AttrTokenTree::Token(token, spacing)), - FlatToken::AttrTarget(data) => stack + FlatToken::AttrsTarget(target) => stack .last_mut() .expect("Bottom token frame is missing!") .inner - .push(AttrTokenTree::Attributes(data)), + .push(AttrTokenTree::AttrsTarget(target)), FlatToken::Empty => {} } token_and_spacing = iter.next(); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 1072e6392921d..45ca267fe5d1e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -20,7 +20,7 @@ use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing}; +use rustc_ast::tokenstream::{AttrsTarget, DelimSpacing, DelimSpan, Spacing}; use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::util::case::Case; use rustc_ast::{ @@ -203,13 +203,13 @@ struct ClosureSpans { } /// Indicates a range of tokens that should be replaced by -/// the tokens in the provided `AttributesData`. This is used in two +/// the tokens in the provided `AttrsTarget`. This is used in two /// places during token collection: /// /// 1. During the parsing of an AST node that may have a `#[derive]` /// attribute, we parse a nested AST node that has `#[cfg]` or `#[cfg_attr]` /// In this case, we use a `ReplaceRange` to replace the entire inner AST node -/// with `FlatToken::AttrTarget`, allowing us to perform eager cfg-expansion +/// with `FlatToken::AttrsTarget`, allowing us to perform eager cfg-expansion /// on an `AttrTokenStream`. /// /// 2. When we parse an inner attribute while collecting tokens. We @@ -219,7 +219,7 @@ struct ClosureSpans { /// the first macro inner attribute to invoke a proc-macro). /// When create a `TokenStream`, the inner attributes get inserted /// into the proper place in the token stream. -type ReplaceRange = (Range, Option); +type ReplaceRange = (Range, Option); /// Controls how we capture tokens. Capturing can be expensive, /// so we try to avoid performing capturing in cases where @@ -1608,11 +1608,10 @@ enum FlatToken { /// A token - this holds both delimiter (e.g. '{' and '}') /// and non-delimiter tokens Token(Token), - /// Holds the `AttributesData` for an AST node. The - /// `AttributesData` is inserted directly into the - /// constructed `AttrTokenStream` as - /// an `AttrTokenTree::Attributes`. - AttrTarget(AttributesData), + /// Holds the `AttrsTarget` for an AST node. The `AttrsTarget` is inserted + /// directly into the constructed `AttrTokenStream` as an + /// `AttrTokenTree::AttrsTarget`. + AttrsTarget(AttrsTarget), /// A special 'empty' token that is ignored during the conversion /// to an `AttrTokenStream`. This is used to simplify the /// handling of replace ranges. From 022582ca46d9bedecf0b434b6a4130c9a2a4657d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 7 Jul 2024 16:24:51 +1000 Subject: [PATCH 14/18] Remove `Clone` derive from `LazyAttrTokenStreamImpl`. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 2e421a7f19306..38f18022e3c58 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -87,7 +87,6 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool { // // This also makes `Parser` very cheap to clone, since // there is no intermediate collection buffer to clone. -#[derive(Clone)] struct LazyAttrTokenStreamImpl { start_token: (Token, Spacing), cursor_snapshot: TokenCursor, From 9f16f1f6f637d729c92789cae26a1adb7eee40cd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 7 Jul 2024 16:25:22 +1000 Subject: [PATCH 15/18] Add an size assertion. `Option` is the type that's actually used in all the aST nodes. --- compiler/rustc_ast/src/tokenstream.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index f3b6dc2cfa198..ee068f19332a5 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -765,6 +765,7 @@ mod size_asserts { static_assert_size!(AttrTokenStream, 8); static_assert_size!(AttrTokenTree, 32); static_assert_size!(LazyAttrTokenStream, 8); + static_assert_size!(Option, 8); // must be small, used in many AST nodes static_assert_size!(TokenStream, 8); static_assert_size!(TokenTree, 32); // tidy-alphabetical-end From 9e0aab71a46692e4ddd455d7931cbb7336b9d732 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 7 Jul 2024 16:29:07 +1000 Subject: [PATCH 16/18] Use `filter_map` instead of `flat_map` in `configure_tokens`. All the branches produce either zero or one elements. --- compiler/rustc_expand/src/config.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index be46b2af6cae9..40e16b4511575 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -185,7 +185,7 @@ impl<'a> StripUnconfigured<'a> { let trees: Vec<_> = stream .0 .iter() - .flat_map(|tree| match tree.clone() { + .filter_map(|tree| match tree.clone() { AttrTokenTree::AttrsTarget(mut target) => { target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); @@ -193,14 +193,14 @@ impl<'a> StripUnconfigured<'a> { target.tokens = LazyAttrTokenStream::new( self.configure_tokens(&target.tokens.to_attr_token_stream()), ); - Some(AttrTokenTree::AttrsTarget(target)).into_iter() + Some(AttrTokenTree::AttrsTarget(target)) } else { - None.into_iter() + None } } AttrTokenTree::Delimited(sp, spacing, delim, mut inner) => { inner = self.configure_tokens(&inner); - Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)).into_iter() + Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)) } AttrTokenTree::Token( Token { @@ -220,9 +220,7 @@ impl<'a> StripUnconfigured<'a> { ) => { panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tree); } - AttrTokenTree::Token(token, spacing) => { - Some(AttrTokenTree::Token(token, spacing)).into_iter() - } + AttrTokenTree::Token(token, spacing) => Some(AttrTokenTree::Token(token, spacing)), }) .collect(); AttrTokenStream::new(trees) From bee9120458dd3eb2c1486dd6c2344ec2c582f1b8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Jul 2024 09:19:32 +0200 Subject: [PATCH 17/18] once_lock: make test not take as long in Miri --- library/std/src/sync/once_lock.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index f52b9e52c54de..fe243550606f3 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -80,14 +80,21 @@ use crate::sync::Once; /// static LIST: OnceList = OnceList::new(); /// static COUNTER: AtomicU32 = AtomicU32::new(0); /// -/// let vec = (0..thread::available_parallelism().unwrap().get()).map(|_| thread::spawn(|| { -/// while let i @ 0..=1000 = COUNTER.fetch_add(1, Ordering::Relaxed) { -/// LIST.push(i); +/// # const LEN: u32 = if cfg!(miri) { 50 } else { 1000 }; +/// # /* +/// const LEN: u32 = 1000; +/// # */ +/// thread::scope(|s| { +/// for _ in 0..thread::available_parallelism().unwrap().get() { +/// s.spawn(|| { +/// while let i @ 0..LEN = COUNTER.fetch_add(1, Ordering::Relaxed) { +/// LIST.push(i); +/// } +/// }); /// } -/// })).collect::>>(); -/// vec.into_iter().for_each(|handle| handle.join().unwrap()); +/// }); /// -/// for i in 0..=1000 { +/// for i in 0..LEN { /// assert!(LIST.contains(&i)); /// } /// From 9da3638c6a90748cc913a3e2e02a74eb851ec48a Mon Sep 17 00:00:00 2001 From: Gurinder Singh Date: Sun, 7 Jul 2024 15:44:55 +0530 Subject: [PATCH 18/18] Move a span_bug under a condition that cx is tainted Fixes an ICE caused when a with expression is not a struct --- compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 4 +++- tests/crashes/127332.rs | 9 --------- .../ui/typeck/ice-with-expr-not-struct-127332.rs | 15 +++++++++++++++ .../typeck/ice-with-expr-not-struct-127332.stderr | 9 +++++++++ 4 files changed, 27 insertions(+), 10 deletions(-) delete mode 100644 tests/crashes/127332.rs create mode 100644 tests/ui/typeck/ice-with-expr-not-struct-127332.rs create mode 100644 tests/ui/typeck/ice-with-expr-not-struct-127332.stderr diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index c8ab0429ffc70..193dbbbcdf44d 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -734,7 +734,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // struct; however, when EUV is run during typeck, it // may not. This will generate an error earlier in typeck, // so we can just ignore it. - span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); + if self.cx.tainted_by_errors().is_ok() { + span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); + } } } diff --git a/tests/crashes/127332.rs b/tests/crashes/127332.rs deleted file mode 100644 index 5c14af01cece8..0000000000000 --- a/tests/crashes/127332.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: rust-lang/rust #127332 - -async fn fun() { - enum Foo { - A { x: u32 }, - } - let orig = Foo::A { x: 5 }; - Foo::A { x: 6, ..orig }; -} diff --git a/tests/ui/typeck/ice-with-expr-not-struct-127332.rs b/tests/ui/typeck/ice-with-expr-not-struct-127332.rs new file mode 100644 index 0000000000000..f3ea360e7e982 --- /dev/null +++ b/tests/ui/typeck/ice-with-expr-not-struct-127332.rs @@ -0,0 +1,15 @@ +// Regression test for ICE #127332 + +// Tests that we do not ICE when a with expr is +// not a struct but something else like an enum + +fn main() { + let x = || { + enum Foo { + A { x: u32 }, + } + let orig = Foo::A { x: 5 }; + Foo::A { x: 6, ..orig }; + //~^ ERROR functional record update syntax requires a struct + }; +} diff --git a/tests/ui/typeck/ice-with-expr-not-struct-127332.stderr b/tests/ui/typeck/ice-with-expr-not-struct-127332.stderr new file mode 100644 index 0000000000000..446f49e863924 --- /dev/null +++ b/tests/ui/typeck/ice-with-expr-not-struct-127332.stderr @@ -0,0 +1,9 @@ +error[E0436]: functional record update syntax requires a struct + --> $DIR/ice-with-expr-not-struct-127332.rs:12:26 + | +LL | Foo::A { x: 6, ..orig }; + | ^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0436`.