From a5a60d75a87881f79deea115d7cd002ce3373fd5 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 28 Mar 2024 14:30:32 +0000 Subject: [PATCH 01/29] Add `size_of`, `size_of_val`, `align_of`, and `align_of_val` to the prelude Many, many projects use `size_of` to get the size of a type. However, it's also often equally easy to hardcode a size (e.g. `8` instead of `size_of::()`). Minimizing friction in the use of `size_of` helps ensure that people use it and make code more self-documenting. The name `size_of` is unambiguous: the name alone, without any prefix or path, is self-explanatory and unmistakeable for any other functionality. Adding it to the prelude cannot produce any name conflicts, as any local definition will silently shadow the one from the prelude. Thus, we don't need to wait for a new edition prelude to add it. Add `size_of_val`, `align_of`, and `align_of_val` as well, with similar justification: widely useful, self-explanatory, unmistakeable for anything else, won't produce conflicts. --- compiler/rustc_middle/src/query/erase.rs | 2 +- library/alloc/src/rc.rs | 2 -- library/alloc/src/sync.rs | 2 -- library/core/src/cell.rs | 2 +- library/core/src/intrinsics.rs | 1 - library/core/src/prelude/common.rs | 3 +++ library/core/src/ptr/mod.rs | 2 +- library/core/src/slice/raw.rs | 1 - library/core/src/sync/atomic.rs | 3 --- .../crates/core_simd/src/simd/ptr/const_ptr.rs | 2 +- .../crates/core_simd/src/simd/ptr/mut_ptr.rs | 2 +- library/proc_macro/src/bridge/fxhash.rs | 1 - library/std/src/io/error/repr_bitpacked.rs | 1 - library/std/src/os/unix/net/ancillary.rs | 2 +- library/std/src/prelude/common.rs | 3 +++ library/std/src/prelude/mod.rs | 4 ++++ tests/ui/resolve/filter-intrinsics.rs | 4 ++-- tests/ui/resolve/filter-intrinsics.stderr | 8 ++++---- 18 files changed, 22 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 320d49ea64674..a4ab6bc7d9de0 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -4,7 +4,7 @@ use crate::traits; use crate::ty::adjustment::CoerceUnsizedInfo; use crate::ty::{self, Ty}; use std::intrinsics::transmute_unchecked; -use std::mem::{size_of, MaybeUninit}; +use std::mem::MaybeUninit; #[derive(Copy, Clone)] pub struct Erased { diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 45b205356758f..52b91c5ac8879 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -257,8 +257,6 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -#[cfg(not(no_global_oom_handling))] -use core::mem::size_of_val; use core::mem::{self, align_of_val_raw, forget, ManuallyDrop}; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index a35c99849b343..d7c3a261fe405 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -18,8 +18,6 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -#[cfg(not(no_global_oom_handling))] -use core::mem::size_of_val; use core::mem::{self, align_of_val_raw}; use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 4b491ffdafa70..dd6466d6285ba 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -238,7 +238,7 @@ use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; use crate::marker::{PhantomData, Unsize}; -use crate::mem::{self, size_of}; +use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn}; use crate::ptr::{self, NonNull}; diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index d1450bf12ce72..56c998d99f258 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -65,7 +65,6 @@ use crate::marker::DiscriminantKind; use crate::marker::Tuple; -use crate::mem::align_of; use crate::ptr; use crate::ub_checks; diff --git a/library/core/src/prelude/common.rs b/library/core/src/prelude/common.rs index afc6817aa1d24..2a0331ef7b274 100644 --- a/library/core/src/prelude/common.rs +++ b/library/core/src/prelude/common.rs @@ -14,6 +14,9 @@ pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use crate::mem::drop; +#[stable(feature = "size_of_prelude", since = "CURRENT_RUSTC_VERSION")] +#[doc(no_inline)] +pub use crate::mem::{align_of, align_of_val, size_of, size_of_val}; // Re-exported types and traits #[stable(feature = "core_prelude", since = "1.4.0")] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 8d7192c1b0fd1..3258e338e837c 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -392,7 +392,7 @@ use crate::intrinsics; use crate::marker::FnPtr; use crate::ub_checks; -use crate::mem::{self, align_of, size_of, MaybeUninit}; +use crate::mem::{self, MaybeUninit}; mod alignment; #[unstable(feature = "ptr_alignment_type", issue = "102070")] diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 29a12f106c5ed..3f4305866e688 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -1,7 +1,6 @@ //! Free functions to create `&[T]` and `&mut [T]`. use crate::array; -use crate::mem::{align_of, size_of}; use crate::ops::Range; use crate::ptr; use crate::ub_checks; diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 232ec589093d3..482bd19705c2f 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1296,7 +1296,6 @@ impl AtomicPtr { #[cfg(target_has_atomic_equal_alignment = "ptr")] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut *mut T) -> &mut Self { - use crate::mem::align_of; let [] = [(); align_of::>() - align_of::<*mut ()>()]; // SAFETY: // - the mutable reference guarantees unique ownership. @@ -2286,7 +2285,6 @@ macro_rules! atomic_int { #[$cfg_align] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut $int_type) -> &mut Self { - use crate::mem::align_of; let [] = [(); align_of::() - align_of::<$int_type>()]; // SAFETY: // - the mutable reference guarantees unique ownership. @@ -2354,7 +2352,6 @@ macro_rules! atomic_int { #[$cfg_align] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut_slice(v: &mut [$int_type]) -> &mut [Self] { - use crate::mem::align_of; let [] = [(); align_of::() - align_of::<$int_type>()]; // SAFETY: // - the mutable reference guarantees unique ownership. diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs index 0f1719206c9ce..cbffbc564cfed 100644 --- a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -96,7 +96,7 @@ where fn cast(self) -> Self::CastPtr { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. - use core::{mem::size_of, ptr::Pointee}; + use core::ptr::Pointee; assert_eq!(size_of::<::Metadata>(), 0); assert_eq!(size_of::<::Metadata>(), 0); diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs index 7ba996d149c0c..6bc6ca3ac42dc 100644 --- a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -93,7 +93,7 @@ where fn cast(self) -> Self::CastPtr { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. - use core::{mem::size_of, ptr::Pointee}; + use core::ptr::Pointee; assert_eq!(size_of::<::Metadata>(), 0); assert_eq!(size_of::<::Metadata>(), 0); diff --git a/library/proc_macro/src/bridge/fxhash.rs b/library/proc_macro/src/bridge/fxhash.rs index f4e9054419721..0923493d06c7c 100644 --- a/library/proc_macro/src/bridge/fxhash.rs +++ b/library/proc_macro/src/bridge/fxhash.rs @@ -7,7 +7,6 @@ use std::collections::HashMap; use std::hash::BuildHasherDefault; use std::hash::Hasher; -use std::mem::size_of; use std::ops::BitXor; /// Type alias for a hashmap using the `fx` hash algorithm. diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 6f8d5e3777568..c9d3934ad70ce 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -104,7 +104,6 @@ use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage}; use core::marker::PhantomData; -use core::mem::{align_of, size_of}; use core::ptr::{self, NonNull}; // The 2 least-significant bits are used as tag. diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index 0597fdcbd7289..fe8e2be93724e 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -3,7 +3,7 @@ use super::{sockaddr_un, SocketAddr}; use crate::io::{self, IoSlice, IoSliceMut}; use crate::marker::PhantomData; -use crate::mem::{size_of, zeroed}; +use crate::mem::zeroed; use crate::os::unix::io::RawFd; use crate::path::Path; use crate::ptr::{eq, read_unaligned}; diff --git a/library/std/src/prelude/common.rs b/library/std/src/prelude/common.rs index 01936734d7548..ceee3e33c3ef0 100644 --- a/library/std/src/prelude/common.rs +++ b/library/std/src/prelude/common.rs @@ -14,6 +14,9 @@ pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::mem::drop; +#[stable(feature = "size_of_prelude", since = "CURRENT_RUSTC_VERSION")] +#[doc(no_inline)] +pub use crate::mem::{align_of, align_of_val, size_of, size_of_val}; // Re-exported types and traits #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 0bdbab716adb4..2d4639342bf85 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -36,6 +36,10 @@ //! operations for both destructors and overloading `()`. //! * [std::mem]::[drop], a convenience function for explicitly //! dropping a value. +//! * [std::mem]::{[size_of], [size_of_val]}, to get the size of +//! a type or value. +//! * [std::mem]::{[align_of], [align_of_val]}, to get the +//! alignment of a type or value. //! * [std::boxed]::[Box], a way to allocate values on the heap. //! * [std::borrow]::[ToOwned], the conversion trait that defines //! [`to_owned`], the generic method for creating an owned type from a diff --git a/tests/ui/resolve/filter-intrinsics.rs b/tests/ui/resolve/filter-intrinsics.rs index c0956ef85aff6..8d6d22817dc5c 100644 --- a/tests/ui/resolve/filter-intrinsics.rs +++ b/tests/ui/resolve/filter-intrinsics.rs @@ -1,6 +1,6 @@ fn main() { - // Should suggest only `std::mem::size_of` - let _ = size_of::(); + // Should suggest only `std::mem::transmute` + let _ = transmute::(); //~^ ERROR cannot find // Should suggest `std::intrinsics::fabsf64`, diff --git a/tests/ui/resolve/filter-intrinsics.stderr b/tests/ui/resolve/filter-intrinsics.stderr index cc1092dd0cfa8..9c9e92f6d4f83 100644 --- a/tests/ui/resolve/filter-intrinsics.stderr +++ b/tests/ui/resolve/filter-intrinsics.stderr @@ -1,12 +1,12 @@ -error[E0425]: cannot find function `size_of` in this scope +error[E0425]: cannot find function `transmute` in this scope --> $DIR/filter-intrinsics.rs:3:13 | -LL | let _ = size_of::(); - | ^^^^^^^ not found in this scope +LL | let _ = transmute::(); + | ^^^^^^^^^ not found in this scope | help: consider importing this function | -LL + use std::mem::size_of; +LL + use std::mem::transmute; | error[E0425]: cannot find function `fabsf64` in this scope From b4834a1c981b1ebddc9a4f33039f1348730540ba Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 28 May 2024 14:37:08 -0400 Subject: [PATCH 02/29] rewrite resolve-rename in rmake --- src/tools/run-make-support/src/rustc.rs | 6 ++++++ src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/resolve-rename/Makefile | 7 ------- tests/run-make/resolve-rename/rmake.rs | 15 +++++++++++++++ 4 files changed, 21 insertions(+), 8 deletions(-) delete mode 100644 tests/run-make/resolve-rename/Makefile create mode 100644 tests/run-make/resolve-rename/rmake.rs diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 1c83b630861cd..3e4e61218caaf 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -70,6 +70,12 @@ impl Rustc { self } + /// Add a suffix in each output filename. + pub fn extra_filename(&mut self, suffix: &str) -> &mut Self { + self.cmd.arg(format!("-Cextra-filename={suffix}")); + self + } + /// Specify type(s) of output files to generate. pub fn emit(&mut self, kinds: &str) -> &mut Self { self.cmd.arg(format!("--emit={kinds}")); diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 2329b8b44dea0..845dd7f0eee97 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -216,7 +216,6 @@ run-make/remap-path-prefix-dwarf/Makefile run-make/remap-path-prefix/Makefile run-make/reproducible-build-2/Makefile run-make/reproducible-build/Makefile -run-make/resolve-rename/Makefile run-make/return-non-c-like-enum-from-c/Makefile run-make/return-non-c-like-enum/Makefile run-make/rlib-chain/Makefile diff --git a/tests/run-make/resolve-rename/Makefile b/tests/run-make/resolve-rename/Makefile deleted file mode 100644 index 00f83a5d6b2d4..0000000000000 --- a/tests/run-make/resolve-rename/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) -C extra-filename=-hash foo.rs - $(RUSTC) bar.rs - mv $(TMPDIR)/libfoo-hash.rlib $(TMPDIR)/libfoo-another-hash.rlib - $(RUSTC) baz.rs diff --git a/tests/run-make/resolve-rename/rmake.rs b/tests/run-make/resolve-rename/rmake.rs new file mode 100644 index 0000000000000..7539d367758e0 --- /dev/null +++ b/tests/run-make/resolve-rename/rmake.rs @@ -0,0 +1,15 @@ +// If a library is compiled with -C extra-filename, the rust compiler +// will take this into account when searching for libraries. However, +// if that library is then renamed, the rust compiler should fall back +// to its regular library location logic and not immediately fail to find +// the renamed library. +// See https://github.com/rust-lang/rust/pull/49253 + +use run_make_support::{rustc, tmp_dir}; +use std::fs; +fn main() { + rustc().extra_filename("-hash").input("foo.rs").run(); + rustc().input("bar.rs").run(); + fs::rename(tmp_dir().join("libfoo-hash.rlib"), tmp_dir().join("libfoo-another-hash.rlib")); + rustc().input("baz.rs").run(); +} From d553d5ba2d77feb67fde6649c03e8d1c486eb278 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 28 May 2024 15:41:51 -0400 Subject: [PATCH 03/29] rewrite incr-prev-body-beyond-eof in rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../incr-prev-body-beyond-eof/Makefile | 19 ----------- .../incr-prev-body-beyond-eof/rmake.rs | 32 +++++++++++++++++++ 3 files changed, 32 insertions(+), 20 deletions(-) delete mode 100644 tests/run-make/incr-prev-body-beyond-eof/Makefile create mode 100644 tests/run-make/incr-prev-body-beyond-eof/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 845dd7f0eee97..4e69d67057a76 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -79,7 +79,6 @@ run-make/inaccessible-temp-dir/Makefile run-make/include_bytes_deps/Makefile run-make/incr-add-rust-src-component/Makefile run-make/incr-foreign-head-span/Makefile -run-make/incr-prev-body-beyond-eof/Makefile run-make/incremental-debugger-visualizer/Makefile run-make/incremental-session-fail/Makefile run-make/inline-always-many-cgu/Makefile diff --git a/tests/run-make/incr-prev-body-beyond-eof/Makefile b/tests/run-make/incr-prev-body-beyond-eof/Makefile deleted file mode 100644 index aa47552f52c93..0000000000000 --- a/tests/run-make/incr-prev-body-beyond-eof/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# ignore-none no-std is not supported -# ignore-nvptx64-nvidia-cuda FIXME: can't find crate for `std` - -include ../tools.mk - -# Tests that we don't ICE during incremental compilation after modifying a -# function span such that its previous end line exceeds the number of lines -# in the new file, but its start line/column and length remain the same. - -SRC=$(TMPDIR)/src -INCR=$(TMPDIR)/incr - -all: - mkdir $(SRC) - mkdir $(INCR) - cp a.rs $(SRC)/main.rs - $(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs --target $(TARGET) - cp b.rs $(SRC)/main.rs - $(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs --target $(TARGET) diff --git a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs new file mode 100644 index 0000000000000..43f137fea20eb --- /dev/null +++ b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs @@ -0,0 +1,32 @@ +// After modifying the span of a function, if the length of +// the span remained the same but the end line number became different, +// this would cause an internal compiler error (ICE), fixed in #76256. + +// This test compiles main.rs twice, first with end line 16 and +// then with end line 12. If compilation is successful, the end line +// was hashed by rustc in addition to the span length, and the fix still +// works. + +// FIXME: Ignore flags temporarily disabled for the test. +// ignore-none +// ignore-nvptx64-nvidia-cuda + +use run_make_support::{rustc, target, tmp_dir}; +use std::fs; + +fn main() { + fs::create_dir(tmp_dir().join("src")); + fs::create_dir(tmp_dir().join("incr")); + fs::copy("a.rs", tmp_dir().join("main.rs")); + rustc() + .incremental(tmp_dir().join("incr")) + .input(tmp_dir().join("src/main.rs")) + .target(target()) + .run(); + fs::copy("b.rs", tmp_dir().join("main.rs")); + rustc() + .incremental(tmp_dir().join("incr")) + .input(tmp_dir().join("src/main.rs")) + .target(target()) + .run(); +} From 8530285f4ef240bf748cb207fa7d1794dca2e68f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 3 Jun 2024 01:01:18 +0300 Subject: [PATCH 04/29] rustc_span: Inline some hot functions --- compiler/rustc_span/src/span_encoding.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 788a52faf5688..6a02822663169 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -216,6 +216,7 @@ impl Span { // Returns either syntactic context, if it can be retrieved without taking the interner lock, // or an index into the interner if it cannot. + #[inline] fn inline_ctxt(self) -> Result { Ok(if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { if self.len_with_tag_or_marker & PARENT_TAG == 0 { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 61ca0d54ca490..fe883e03c44cd 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2213,6 +2213,7 @@ impl fmt::Display for IdentPrinter { pub struct MacroRulesNormalizedIdent(Ident); impl MacroRulesNormalizedIdent { + #[inline] pub fn new(ident: Ident) -> Self { Self(ident.normalize_to_macro_rules()) } From 07dc3ebf5c82f1f1420f37d68204600b87522383 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 3 Jun 2024 10:45:16 +0000 Subject: [PATCH 05/29] Allow static mut definitions with #[linkage] Unlike static declarations with #[linkage], for definitions rustc doesn't rewrite it to add an extra indirection. --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 25 ++++++++++--------- .../linkage-attr-mutable-static.rs | 15 ++++++++--- .../linkage-attr-mutable-static.stderr | 10 ++++---- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 5d7257b15c42e..15955170e8736 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -324,21 +324,22 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let linkage = Some(linkage_by_name(tcx, did, val.as_str())); if tcx.is_foreign_item(did) { codegen_fn_attrs.import_linkage = linkage; + + if tcx.is_mutable_static(did.into()) { + let mut diag = tcx.dcx().struct_span_err( + attr.span, + "extern mutable statics are not allowed with `#[linkage]`", + ); + diag.note( + "marking the extern static mutable would allow changing which symbol \ + the static references rather than make the target of the symbol \ + mutable", + ); + diag.emit(); + } } else { codegen_fn_attrs.linkage = linkage; } - if tcx.is_mutable_static(did.into()) { - let mut diag = tcx.dcx().struct_span_err( - attr.span, - "mutable statics are not allowed with `#[linkage]`", - ); - diag.note( - "making the static mutable would allow changing which symbol the \ - static references rather than make the target of the symbol \ - mutable", - ); - diag.emit(); - } } } sym::link_section => { diff --git a/tests/ui/linkage-attr/linkage-attr-mutable-static.rs b/tests/ui/linkage-attr/linkage-attr-mutable-static.rs index a7109c6d930bc..ed11947f59e74 100644 --- a/tests/ui/linkage-attr/linkage-attr-mutable-static.rs +++ b/tests/ui/linkage-attr/linkage-attr-mutable-static.rs @@ -4,12 +4,21 @@ #![feature(linkage)] fn main() { + #[rustfmt::skip] extern "C" { - #[linkage = "weak"] //~ ERROR mutable statics are not allowed with `#[linkage]` - static mut ABC: *const u8; + #[linkage = "extern_weak"] //~ ERROR extern mutable statics are not allowed with `#[linkage]` + static mut EXTERN_WEAK: *const u8; } unsafe { - assert_eq!(ABC as usize, 0); + assert_eq!(EXTERN_WEAK as usize, 0); + } + + // static mut is fine here as this is a definition rather than declaration. + #[linkage = "weak"] + static mut WEAK_DEF: u8 = 42; + + unsafe { + assert_eq!(WEAK_DEF, 0); } } diff --git a/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr b/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr index 4db41b6239382..ad9997690475b 100644 --- a/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr +++ b/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr @@ -1,10 +1,10 @@ -error: mutable statics are not allowed with `#[linkage]` - --> $DIR/linkage-attr-mutable-static.rs:8:9 +error: extern mutable statics are not allowed with `#[linkage]` + --> $DIR/linkage-attr-mutable-static.rs:9:9 | -LL | #[linkage = "weak"] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[linkage = "extern_weak"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: making the static mutable would allow changing which symbol the static references rather than make the target of the symbol mutable + = note: marking the extern static mutable would allow changing which symbol the static references rather than make the target of the symbol mutable error: aborting due to 1 previous error From 8f0862544327d5419a158c9483ed905d3fb55bf2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 2 Jun 2024 21:19:11 -0400 Subject: [PATCH 06/29] Remove a bunch of redundant args from report_method_error --- compiler/rustc_hir_typeck/src/expr.rs | 31 +++++----- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 10 +--- compiler/rustc_hir_typeck/src/method/mod.rs | 1 - .../rustc_hir_typeck/src/method/suggest.rs | 58 ++++++++++++------- compiler/rustc_hir_typeck/src/pat.rs | 8 +-- tests/ui/issues/issue-28344.stderr | 2 +- tests/ui/resolve/issue-82865.stderr | 7 --- tests/ui/traits/item-privacy.stderr | 9 +-- 8 files changed, 64 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3d88c4255245e..386f4c3af688f 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -13,7 +13,6 @@ use crate::errors::{ YieldExprOutsideOfCoroutine, }; use crate::fatally_break_rust; -use crate::method::SelfSource; use crate::type_error_struct; use crate::CoroutineTypes; use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; @@ -507,7 +506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let tcx = self.tcx; let (res, opt_ty, segs) = - self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span, Some(args)); + self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span); let ty = match res { Res::Err => { self.suggest_assoc_method_call(segs); @@ -1331,9 +1330,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rcvr_t = self.check_expr(rcvr); // no need to check for bot/err -- callee does that let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t); - let span = segment.ident.span; - let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) { + let method = match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args) + { Ok(method) => { // We could add a "consider `foo::`" suggestion here, but I wasn't able to // trigger this codepath causing `structurally_resolve_type` to emit an error. @@ -1342,18 +1341,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(error) => { if segment.ident.name != kw::Empty { - if let Some(err) = self.report_method_error( - span, - Some(rcvr), - rcvr_t, - segment.ident, - expr.hir_id, - SelfSource::MethodCall(rcvr), - error, - Some(args), - expected, - false, - ) { + if let Some(err) = + self.report_method_error(expr.hir_id, rcvr_t, error, expected, false) + { err.emit(); } } @@ -1362,7 +1352,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Call the generic checker. - self.check_method_argument_types(span, expr, method, args, DontTupleArguments, expected) + self.check_method_argument_types( + segment.ident.span, + expr, + method, + args, + DontTupleArguments, + expected, + ) } fn check_expr_cast( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 0c10c67db8c38..3c36eab18cff4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,6 +1,6 @@ use crate::callee::{self, DeferredCallResolution}; use crate::errors::{self, CtorIsPrivate}; -use crate::method::{self, MethodCallee, SelfSource}; +use crate::method::{self, MethodCallee}; use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy}; use rustc_data_structures::fx::FxHashSet; @@ -735,7 +735,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath: &'tcx QPath<'tcx>, hir_id: HirId, span: Span, - args: Option<&'tcx [hir::Expr<'tcx>]>, ) -> (Res, Option>, &'tcx [hir::PathSegment<'tcx>]) { debug!( "resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}", @@ -828,14 +827,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if item_name.name != kw::Empty { if let Some(e) = self.report_method_error( - span, - None, - ty.normalized, - item_name, hir_id, - SelfSource::QPath(qself), + ty.normalized, error, - args, Expectation::NoExpectation, trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021 ) { diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 4165ccb1b80ae..1f90d5e4c88ac 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -7,7 +7,6 @@ mod prelude_edition_lints; pub mod probe; mod suggest; -pub use self::suggest::SelfSource; pub use self::MethodError::*; use crate::FnCtxt; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index daaaf630f2c45..b3947e142b263 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -16,11 +16,11 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, MultiSpan, StashKey, }; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::PathSegment; +use rustc_hir::{self as hir, HirId}; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::{self, RegionVariableOrigin}; use rustc_middle::bug; @@ -187,37 +187,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self))] pub fn report_method_error( &self, - span: Span, - rcvr_opt: Option<&'tcx hir::Expr<'tcx>>, + call_id: HirId, rcvr_ty: Ty<'tcx>, - item_name: Ident, - expr_id: hir::HirId, - source: SelfSource<'tcx>, error: MethodError<'tcx>, - args: Option<&'tcx [hir::Expr<'tcx>]>, expected: Expectation<'tcx>, trait_missing_method: bool, ) -> Option> { + let (span, sugg_span, source, item_name, args) = match self.tcx.hir_node(call_id) { + hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::MethodCall(segment, rcvr, args, _), + span, + .. + }) => { + (segment.ident.span, span, SelfSource::MethodCall(rcvr), segment.ident, Some(args)) + } + hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::Path(QPath::TypeRelative(rcvr, segment)), + span, + .. + }) + | hir::Node::Pat(&hir::Pat { + kind: + hir::PatKind::Path(QPath::TypeRelative(rcvr, segment)) + | hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..) + | hir::PatKind::TupleStruct(QPath::TypeRelative(rcvr, segment), ..), + span, + .. + }) => { + let args = match self.tcx.parent_hir_node(call_id) { + hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::Call(callee, args), .. + }) if callee.hir_id == call_id => Some(args), + _ => None, + }; + (segment.ident.span, span, SelfSource::QPath(rcvr), segment.ident, args) + } + node => unreachable!("{node:?}"), + }; + // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { return None; } - let sugg_span = if let SelfSource::MethodCall(expr) = source { - // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing. - self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id)).span - } else { - span - }; - match error { MethodError::NoMatch(mut no_match_data) => { return self.report_no_match_method_error( span, - rcvr_opt, rcvr_ty, item_name, - expr_id, + call_id, source, args, sugg_span, @@ -362,7 +381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn suggest_use_shadowed_binding_with_method( &self, - rcvr_opt: Option<&'tcx hir::Expr<'tcx>>, + self_source: SelfSource<'tcx>, method_name: Ident, ty_str_reported: &str, err: &mut Diag<'_>, @@ -502,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if let Some(rcvr) = rcvr_opt + if let SelfSource::MethodCall(rcvr) = self_source && let hir::ExprKind::Path(QPath::Resolved(_, path)) = rcvr.kind && let hir::def::Res::Local(recv_id) = path.res && let Some(segment) = path.segments.first() @@ -548,7 +567,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn report_no_match_method_error( &self, mut span: Span, - rcvr_opt: Option<&'tcx hir::Expr<'tcx>>, rcvr_ty: Ty<'tcx>, item_name: Ident, expr_id: hir::HirId, @@ -658,7 +676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if is_method { self.suggest_use_shadowed_binding_with_method( - rcvr_opt, + source, item_name, &ty_str_reported, &mut err, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index b37aba386196b..93fb83fb3e4e5 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -223,9 +223,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info; let path_res = match &pat.kind { - PatKind::Path(qpath) => Some( - self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None), - ), + PatKind::Path(qpath) => { + Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span)) + } _ => None, }; let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); @@ -1184,7 +1184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resolve the path and check the definition for errors. let (res, opt_ty, segments) = - self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None); + self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span); if res == Res::Err { let e = tcx.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); diff --git a/tests/ui/issues/issue-28344.stderr b/tests/ui/issues/issue-28344.stderr index ddc1027c16b8e..d30fb3cfe58ab 100644 --- a/tests/ui/issues/issue-28344.stderr +++ b/tests/ui/issues/issue-28344.stderr @@ -52,7 +52,7 @@ error[E0599]: no function or associated item named `bitor` found for trait objec LL | let g = BitXor::bitor; | ^^^^^ function or associated item not found in `dyn BitXor<_>` | -help: there is a method `bitxor` with a similar name, but with different arguments +help: there is a method `bitxor` with a similar name --> $SRC_DIR/core/src/ops/bit.rs:LL:COL error: aborting due to 4 previous errors; 2 warnings emitted diff --git a/tests/ui/resolve/issue-82865.stderr b/tests/ui/resolve/issue-82865.stderr index 9d0439d9d8763..730fd6d602645 100644 --- a/tests/ui/resolve/issue-82865.stderr +++ b/tests/ui/resolve/issue-82865.stderr @@ -15,13 +15,6 @@ LL | Box::z LL | mac!(); | ------ in this macro invocation | -note: if you're trying to build a new `Box<_, _>` consider using one of the following associated functions: - Box::::new - Box::::new_uninit - Box::::new_zeroed - Box::::try_new - and 18 others - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index d08bb4745bf57..50b561dfd165d 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -126,14 +126,15 @@ LL | S::B; | ^ associated item not found in `S` | = help: items from traits can only be used if the trait is in scope +help: there is a method `b` with a similar name + --> $DIR/item-privacy.rs:11:9 + | +LL | fn b(&self) { } + | ^^^^^^^^^^^ help: trait `B` which provides `B` is implemented but not in scope; perhaps you want to import it | LL + use assoc_const::B; | -help: there is a method `b` with a similar name - | -LL | S::b; - | ~ error[E0624]: associated constant `A` is private --> $DIR/item-privacy.rs:101:14 From e9957b922a8b81dc113e11c19a5ef93d1bdbdcf6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 2 Jun 2024 21:34:21 -0400 Subject: [PATCH 07/29] Stop passing empty args to check_expr_path --- compiler/rustc_hir_typeck/src/expr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 386f4c3af688f..4cc936eed08c5 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -222,7 +222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = ensure_sufficient_stack(|| match &expr.kind { hir::ExprKind::Path( qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)), - ) => self.check_expr_path(qpath, expr, args, call), + ) => self.check_expr_path(qpath, expr, Some(args), call), _ => self.check_expr_kind(expr, expected), }); let ty = self.resolve_vars_if_possible(ty); @@ -289,7 +289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Path(QPath::LangItem(lang_item, _)) => { self.check_lang_item_path(lang_item, expr) } - ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[], None), + ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None, None), ExprKind::InlineAsm(asm) => { // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars). self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); @@ -501,7 +501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, qpath: &'tcx hir::QPath<'tcx>, expr: &'tcx hir::Expr<'tcx>, - args: &'tcx [hir::Expr<'tcx>], + args: Option<&'tcx [hir::Expr<'tcx>]>, call: Option<&'tcx hir::Expr<'tcx>>, ) -> Ty<'tcx> { let tcx = self.tcx; @@ -563,7 +563,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We just want to check sizedness, so instead of introducing // placeholder lifetimes with probing, we just replace higher lifetimes // with fresh vars. - let span = args.get(i).map(|a| a.span).unwrap_or(expr.span); + let span = args.and_then(|args| args.get(i)).map_or(expr.span, |arg| arg.span); let input = self.instantiate_binder_with_fresh_vars( span, infer::BoundRegionConversionTime::FnCall, From 8f677e8fb20f0ad6d93b39d8b736ee7bc0939973 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 19 May 2024 11:42:34 +0300 Subject: [PATCH 08/29] bootstrap: implement new feature `bootstrap-self-test` Some of the bootstrap logics should be ignored during unit tests because they either make the tests take longer or cause them to fail. Therefore we need to be able to exclude them from the bootstrap when it's called by unit tests. This change introduces a new feature called `bootstrap-self-test`, which is enabled on bootstrap unit tests by default. This allows us to keep the logic separate between compiler builds and bootstrap tests without needing messy workarounds (like checking if target names match those in the unit tests). Signed-off-by: onur-ozkan --- src/bootstrap/Cargo.toml | 1 + src/bootstrap/src/core/build_steps/test.rs | 1 + src/bootstrap/src/core/config/config.rs | 19 +++++++++------ src/bootstrap/src/core/config/tests.rs | 28 ++++------------------ src/bootstrap/src/core/download.rs | 22 +++++++++++++++-- src/bootstrap/src/core/sanity.rs | 16 ++++++++----- 6 files changed, 49 insertions(+), 38 deletions(-) diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index ca0d1fa5bd0c0..32dd3efa7a6e7 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -7,6 +7,7 @@ default-run = "bootstrap" [features] build-metrics = ["sysinfo"] +bootstrap-self-test = [] # enabled in the bootstrap unit tests [lib] path = "src/lib.rs" diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 29b3d1669b4bf..aaedee65ed756 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3053,6 +3053,7 @@ impl Step for Bootstrap { let mut cmd = Command::new(&builder.initial_cargo); cmd.arg("test") + .args(["--features", "bootstrap-self-test"]) .current_dir(builder.src.join("src/bootstrap")) .env("RUSTFLAGS", "-Cdebuginfo=2") .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 70d32f2f6d95c..17e37c1ecd238 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -22,8 +22,6 @@ use crate::utils::cache::{Interned, INTERNER}; use crate::utils::channel::{self, GitInfo}; use crate::utils::helpers::{exe, output, t}; use build_helper::exit; -use build_helper::util::fail; -use semver::Version; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -2382,8 +2380,14 @@ impl Config { } } - // check rustc/cargo version is same or lower with 1 apart from the building one + #[cfg(feature = "bootstrap-self-test")] + pub fn check_stage0_version(&self, _program_path: &Path, _component_name: &'static str) {} + + /// check rustc/cargo version is same or lower with 1 apart from the building one + #[cfg(not(feature = "bootstrap-self-test"))] pub fn check_stage0_version(&self, program_path: &Path, component_name: &'static str) { + use build_helper::util::fail; + if self.dry_run() { return; } @@ -2400,11 +2404,12 @@ impl Config { } let stage0_version = - Version::parse(stage0_output.next().unwrap().split('-').next().unwrap().trim()) - .unwrap(); - let source_version = - Version::parse(fs::read_to_string(self.src.join("src/version")).unwrap().trim()) + semver::Version::parse(stage0_output.next().unwrap().split('-').next().unwrap().trim()) .unwrap(); + let source_version = semver::Version::parse( + fs::read_to_string(self.src.join("src/version")).unwrap().trim(), + ) + .unwrap(); if !(source_version == stage0_version || (source_version.major == stage0_version.major && (source_version.minor == stage0_version.minor diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index c4073910623a4..bfb2c02860d21 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -14,16 +14,9 @@ use std::{ }; fn parse(config: &str) -> Config { - Config::parse_inner( - &[ - "check".to_string(), - "--set=build.rustc=/does/not/exist".to_string(), - "--set=build.cargo=/does/not/exist".to_string(), - "--config=/does/not/exist".to_string(), - "--skip-stage0-validation".to_string(), - ], - |&_| toml::from_str(&config).unwrap(), - ) + Config::parse_inner(&["check".to_string(), "--config=/does/not/exist".to_string()], |&_| { + toml::from_str(&config).unwrap() + }) } #[test] @@ -212,10 +205,7 @@ fn override_toml_duplicate() { Config::parse_inner( &[ "check".to_owned(), - "--set=build.rustc=/does/not/exist".to_string(), - "--set=build.cargo=/does/not/exist".to_string(), - "--config=/does/not/exist".to_owned(), - "--skip-stage0-validation".to_owned(), + "--config=/does/not/exist".to_string(), "--set=change-id=1".to_owned(), "--set=change-id=2".to_owned(), ], @@ -238,15 +228,7 @@ fn profile_user_dist() { .and_then(|table: toml::Value| TomlConfig::deserialize(table)) .unwrap() } - Config::parse_inner( - &[ - "check".to_owned(), - "--set=build.rustc=/does/not/exist".to_string(), - "--set=build.cargo=/does/not/exist".to_string(), - "--skip-stage0-validation".to_string(), - ], - get_toml, - ); + Config::parse_inner(&["check".to_owned()], get_toml); } #[test] diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 60f48c5923e1c..2b11b8c3d4f2b 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -9,11 +9,10 @@ use std::{ }; use build_helper::ci::CiEnv; -use build_helper::stage0_parser::VersionMetadata; use xz2::bufread::XzDecoder; +use crate::utils::helpers::hex_encode; use crate::utils::helpers::{check_run, exe, move_file, program_out_of_date}; -use crate::{core::build_steps::llvm::detect_llvm_sha, utils::helpers::hex_encode}; use crate::{t, Config}; static SHOULD_FIX_BINS_AND_DYLIBS: OnceLock = OnceLock::new(); @@ -405,9 +404,17 @@ impl Config { cargo_clippy } + #[cfg(feature = "bootstrap-self-test")] + pub(crate) fn maybe_download_rustfmt(&self) -> Option { + None + } + /// NOTE: rustfmt is a completely different toolchain than the bootstrap compiler, so it can't /// reuse target directories or artifacts + #[cfg(not(feature = "bootstrap-self-test"))] pub(crate) fn maybe_download_rustfmt(&self) -> Option { + use build_helper::stage0_parser::VersionMetadata; + let VersionMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?; let channel = format!("{version}-{date}"); @@ -487,6 +494,10 @@ impl Config { ); } + #[cfg(feature = "bootstrap-self-test")] + pub(crate) fn download_beta_toolchain(&self) {} + + #[cfg(not(feature = "bootstrap-self-test"))] pub(crate) fn download_beta_toolchain(&self) { self.verbose(|| println!("downloading stage0 beta artifacts")); @@ -665,7 +676,13 @@ download-rustc = false self.unpack(&tarball, &bin_root, prefix); } + #[cfg(feature = "bootstrap-self-test")] + pub(crate) fn maybe_download_ci_llvm(&self) {} + + #[cfg(not(feature = "bootstrap-self-test"))] pub(crate) fn maybe_download_ci_llvm(&self) { + use crate::core::build_steps::llvm::detect_llvm_sha; + if !self.llvm_from_ci { return; } @@ -707,6 +724,7 @@ download-rustc = false } } + #[cfg(not(feature = "bootstrap-self-test"))] fn download_ci_llvm(&self, llvm_sha: &str) { let llvm_assertions = self.llvm_assertions; diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 8ffa97ab78b55..ead38ebc6d5e7 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -8,13 +8,15 @@ //! In theory if we get past this phase it's a bug if a build fails, but in //! practice that's likely not true! -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::env; use std::ffi::{OsStr, OsString}; use std::fs; use std::path::PathBuf; use std::process::Command; -use walkdir::WalkDir; + +#[cfg(not(feature = "bootstrap-self-test"))] +use std::collections::HashSet; use crate::builder::Kind; use crate::core::config::Target; @@ -31,6 +33,7 @@ pub struct Finder { // it might not yet be included in stage0. In such cases, we handle the targets missing from stage0 in this list. // // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). +#[cfg(not(feature = "bootstrap-self-test"))] const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined ]; @@ -167,6 +170,7 @@ than building it. .map(|p| cmd_finder.must_have(p)) .or_else(|| cmd_finder.maybe_have("reuse")); + #[cfg(not(feature = "bootstrap-self-test"))] let stage0_supported_target_list: HashSet = output(Command::new(&build.config.initial_rustc).args(["--print", "target-list"])) .lines() @@ -193,11 +197,11 @@ than building it. continue; } - let target_str = target.to_string(); - // Ignore fake targets that are only used for unit tests in bootstrap. - if !["A-A", "B-B", "C-C"].contains(&target_str.as_str()) { + #[cfg(not(feature = "bootstrap-self-test"))] + { let mut has_target = false; + let target_str = target.to_string(); let missing_targets_hashset: HashSet<_> = STAGE0_MISSING_TARGETS.iter().map(|t| t.to_string()).collect(); @@ -226,7 +230,7 @@ than building it. target_filename.push(".json"); // Recursively traverse through nested directories. - let walker = WalkDir::new(custom_target_path).into_iter(); + let walker = walkdir::WalkDir::new(custom_target_path).into_iter(); for entry in walker.filter_map(|e| e.ok()) { has_target |= entry.file_name() == target_filename; } From 2bad3d13926f5de344bb85ec58de6abf5e5d3475 Mon Sep 17 00:00:00 2001 From: Andrei Damian Date: Tue, 4 Jun 2024 18:49:13 +0300 Subject: [PATCH 09/29] Make deleting on LinkedList aware of the allocator --- library/alloc/src/collections/linked_list.rs | 4 +- .../src/collections/linked_list/tests.rs | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 1c90c171a155b..01510a6140512 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1705,7 +1705,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { unsafe { self.current = unlinked_node.as_ref().next; self.list.unlink_node(unlinked_node); - let unlinked_node = Box::from_raw(unlinked_node.as_ptr()); + let unlinked_node = Box::from_raw_in(unlinked_node.as_ptr(), &self.list.alloc); Some(unlinked_node.element) } } @@ -1946,7 +1946,7 @@ where if (self.pred)(&mut node.as_mut().element) { // `unlink_node` is okay with aliasing `element` references. self.list.unlink_node(node); - return Some(Box::from_raw(node.as_ptr()).element); + return Some(Box::from_raw_in(node.as_ptr(), &self.list.alloc).element); } } } diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs index 8dcd59d12d927..d3744c5a9d0c9 100644 --- a/library/alloc/src/collections/linked_list/tests.rs +++ b/library/alloc/src/collections/linked_list/tests.rs @@ -1164,3 +1164,42 @@ fn test_drop_panic() { assert_eq!(unsafe { DROPS }, 8); } + +#[test] +fn test_allocator() { + use core::alloc::AllocError; + use core::alloc::Allocator; + use core::alloc::Layout; + use core::cell::Cell; + + struct A { + has_allocated: Cell, + has_deallocated: Cell, + } + + unsafe impl Allocator for A { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + assert!(!self.has_allocated.get()); + self.has_allocated.set(true); + + Global.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + assert!(!self.has_deallocated.get()); + self.has_deallocated.set(true); + + unsafe { Global.deallocate(ptr, layout) } + } + } + + let alloc = &A { has_allocated: Cell::new(false), has_deallocated: Cell::new(false) }; + { + let mut list = LinkedList::new_in(alloc); + list.push_back(5u32); + list.remove(0); + } + + assert!(alloc.has_allocated.get()); + assert!(alloc.has_deallocated.get()); +} From 59e2074c79aaea17ed1b4e16081983e5f03c6bd2 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 28 May 2024 15:54:09 -0400 Subject: [PATCH 10/29] rewrite suspicious-library in rmake --- src/tools/compiletest/src/header.rs | 1 + .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../incr-prev-body-beyond-eof/rmake.rs | 31 ++++++++----------- tests/run-make/resolve-rename/rmake.rs | 3 +- tests/run-make/suspicious-library/Makefile | 8 ----- tests/run-make/suspicious-library/rmake.rs | 14 +++++++++ 6 files changed, 30 insertions(+), 28 deletions(-) delete mode 100644 tests/run-make/suspicious-library/Makefile create mode 100644 tests/run-make/suspicious-library/rmake.rs diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index c7c807d3e6846..a8c2962f779cb 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -798,6 +798,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-none", "ignore-nto", "ignore-nvptx64", + "ignore-nvptx64-nvidia-cuda", "ignore-openbsd", "ignore-pass", "ignore-remote", diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 4e69d67057a76..252ce2c653838 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -246,7 +246,6 @@ run-make/static-pie/Makefile run-make/staticlib-blank-lib/Makefile run-make/staticlib-dylib-linkage/Makefile run-make/std-core-cycle/Makefile -run-make/suspicious-library/Makefile run-make/symbol-mangling-hashed/Makefile run-make/symbol-visibility/Makefile run-make/symbols-include-type-name/Makefile diff --git a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs index 43f137fea20eb..8aa3893727f66 100644 --- a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs +++ b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs @@ -7,26 +7,21 @@ // was hashed by rustc in addition to the span length, and the fix still // works. -// FIXME: Ignore flags temporarily disabled for the test. -// ignore-none -// ignore-nvptx64-nvidia-cuda +//@ ignore-none +// reason: no-std is not supported -use run_make_support::{rustc, target, tmp_dir}; +//@ ignore-nvptx64-nvidia-cuda +// FIXME: can't find crate for `std` + +use run_make_support::{rustc, tmp_dir}; use std::fs; fn main() { - fs::create_dir(tmp_dir().join("src")); - fs::create_dir(tmp_dir().join("incr")); - fs::copy("a.rs", tmp_dir().join("main.rs")); - rustc() - .incremental(tmp_dir().join("incr")) - .input(tmp_dir().join("src/main.rs")) - .target(target()) - .run(); - fs::copy("b.rs", tmp_dir().join("main.rs")); - rustc() - .incremental(tmp_dir().join("incr")) - .input(tmp_dir().join("src/main.rs")) - .target(target()) - .run(); + // FIXME(Oneirical): Use run_make_support::fs_wrapper here. + fs::create_dir(tmp_dir().join("src")).unwrap(); + fs::create_dir(tmp_dir().join("incr")).unwrap(); + fs::copy("a.rs", tmp_dir().join("src/main.rs")).unwrap(); + rustc().incremental(tmp_dir().join("incr")).input(tmp_dir().join("src/main.rs")).run(); + fs::copy("b.rs", tmp_dir().join("src/main.rs")).unwrap(); + rustc().incremental(tmp_dir().join("incr")).input(tmp_dir().join("src/main.rs")).run(); } diff --git a/tests/run-make/resolve-rename/rmake.rs b/tests/run-make/resolve-rename/rmake.rs index 7539d367758e0..8c6e3c24714e1 100644 --- a/tests/run-make/resolve-rename/rmake.rs +++ b/tests/run-make/resolve-rename/rmake.rs @@ -10,6 +10,7 @@ use std::fs; fn main() { rustc().extra_filename("-hash").input("foo.rs").run(); rustc().input("bar.rs").run(); - fs::rename(tmp_dir().join("libfoo-hash.rlib"), tmp_dir().join("libfoo-another-hash.rlib")); + fs::rename(tmp_dir().join("libfoo-hash.rlib"), tmp_dir().join("libfoo-another-hash.rlib")) + .unwrap(); rustc().input("baz.rs").run(); } diff --git a/tests/run-make/suspicious-library/Makefile b/tests/run-make/suspicious-library/Makefile deleted file mode 100644 index 3b5ab3c53a564..0000000000000 --- a/tests/run-make/suspicious-library/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) foo.rs -C prefer-dynamic - touch $(call DYLIB,foo-something-special) - touch $(call DYLIB,foo-something-special2) - $(RUSTC) bar.rs diff --git a/tests/run-make/suspicious-library/rmake.rs b/tests/run-make/suspicious-library/rmake.rs new file mode 100644 index 0000000000000..9e91de70bfce4 --- /dev/null +++ b/tests/run-make/suspicious-library/rmake.rs @@ -0,0 +1,14 @@ +// This test creates some fake dynamic libraries with nothing inside, +// and checks if rustc avoids them and successfully compiles as a result. + +//@ ignore-cross-compile + +use run_make_support::{dynamic_lib, rustc}; +use std::fs::File; + +fn main() { + rustc().input("foo.rs").arg("-Cprefer-dynamic").run(); + File::create(dynamic_lib("foo-something-special")).unwrap(); + File::create(dynamic_lib("foo-something-special2")).unwrap(); + rustc().input("bar.rs").run(); +} From 5d26f58423f72e300ef48df591c08e3d446b51aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 4 Jun 2024 00:00:00 +0000 Subject: [PATCH 11/29] Closures are recursively reachable --- compiler/rustc_passes/src/reachable.rs | 1 + tests/ui/cross-crate/auxiliary/static_init_aux.rs | 6 ++++++ tests/ui/cross-crate/static-init.rs | 2 ++ 3 files changed, 9 insertions(+) diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index ab1dd2485566e..954a1ab6560fe 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -157,6 +157,7 @@ impl<'tcx> ReachableContext<'tcx> { } hir::ImplItemKind::Type(_) => false, }, + Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => true, _ => false, } } diff --git a/tests/ui/cross-crate/auxiliary/static_init_aux.rs b/tests/ui/cross-crate/auxiliary/static_init_aux.rs index dca708733b923..832cee8d4d4e1 100644 --- a/tests/ui/cross-crate/auxiliary/static_init_aux.rs +++ b/tests/ui/cross-crate/auxiliary/static_init_aux.rs @@ -3,6 +3,12 @@ pub static F: fn() = f; pub static G: fn() = G0; pub static H: &(dyn Fn() + Sync) = &h; pub static I: fn() = Helper(j).mk(); +pub static K: fn() -> fn() = { + #[inline(never)] + fn k() {} + #[inline(always)] + || -> fn() { k } +}; static X: u32 = 42; static G0: fn() = g; diff --git a/tests/ui/cross-crate/static-init.rs b/tests/ui/cross-crate/static-init.rs index c4697a1d010c7..f8003856c5c49 100644 --- a/tests/ui/cross-crate/static-init.rs +++ b/tests/ui/cross-crate/static-init.rs @@ -8,6 +8,7 @@ static F: fn() = aux::F; static G: fn() = aux::G; static H: &(dyn Fn() + Sync) = aux::H; static I: fn() = aux::I; +static K: fn() -> fn() = aux::K; fn v() -> *const u32 { V @@ -19,4 +20,5 @@ fn main() { G(); H(); I(); + K()(); } From ac96fa44faa786ad5682e6ed7359842d0e6a4b53 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Sun, 12 May 2024 21:31:13 -0700 Subject: [PATCH 12/29] Use inline const instead of unsafe to construct arrays in `MaybeUninit` examples. --- library/core/src/mem/maybe_uninit.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 026e21586d403..56af7fa9c89c2 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -120,12 +120,8 @@ use crate::slice; /// use std::mem::{self, MaybeUninit}; /// /// let data = { -/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is -/// // safe because the type we are claiming to have initialized here is a -/// // bunch of `MaybeUninit`s, which do not require initialization. -/// let mut data: [MaybeUninit>; 1000] = unsafe { -/// MaybeUninit::uninit().assume_init() -/// }; +/// // Create an uninitialized array of `MaybeUninit`. +/// let mut data: [MaybeUninit>; 1000] = [const { MaybeUninit::uninit() }; 1000]; /// /// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop, /// // we have a memory leak, but there is no memory safety issue. @@ -147,10 +143,8 @@ use crate::slice; /// ``` /// use std::mem::MaybeUninit; /// -/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is -/// // safe because the type we are claiming to have initialized here is a -/// // bunch of `MaybeUninit`s, which do not require initialization. -/// let mut data: [MaybeUninit; 1000] = unsafe { MaybeUninit::uninit().assume_init() }; +/// // Create an uninitialized array of `MaybeUninit`. +/// let mut data: [MaybeUninit; 1000] = [const { MaybeUninit::uninit() }; 1000]; /// // Count the number of elements we have assigned. /// let mut data_len: usize = 0; /// From ec8fa177190f1f0279fade487dfa4cef23dd1101 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Sun, 12 May 2024 21:36:09 -0700 Subject: [PATCH 13/29] Use inline const instead of unsafe to implement `MaybeUninit::uninit_array()`. --- library/core/src/mem/maybe_uninit.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 56af7fa9c89c2..4175d4a33294b 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -342,8 +342,7 @@ impl MaybeUninit { #[must_use] #[inline(always)] pub const fn uninit_array() -> [Self; N] { - // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. - unsafe { MaybeUninit::<[MaybeUninit; N]>::uninit().assume_init() } + [const { MaybeUninit::uninit() }; N] } /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being From 2a219372376fef987ddc79332cd682f17f3ca281 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Tue, 4 Jun 2024 17:50:06 -0600 Subject: [PATCH 14/29] Add a co-maintainer for the two ARMv4T targets --- src/doc/rustc/src/platform-support/armv4t-none-eabi.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md index ab8b4caaadffa..0c5129d0efbbc 100644 --- a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md @@ -12,6 +12,7 @@ overall performance. ## Target Maintainers * [@Lokathor](https://github.com/lokathor) +* [@corwinkuiper](https://github.com/corwinkuiper) ## Testing From e1ae0fa055bf358cec14d41e7ddd96cd8964eb9d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 29 May 2024 16:20:19 +1000 Subject: [PATCH 15/29] `UNICODE_ARRAY` and `ASCII_ARRAY` fixes. - Avoid unnecessary escaping of single quotes within string literals. - Add a missing blank line between two `UNICODE_ARRAY` sections. --- .../rustc_parse/src/lexer/unicode_chars.rs | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index c9470151a7baf..8eb299108d102 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -129,42 +129,42 @@ pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ ('。', "Ideographic Full Stop", "."), ('︒', "Presentation Form For Vertical Ideographic Full Stop", "."), - ('՝', "Armenian Comma", "\'"), - (''', "Fullwidth Apostrophe", "\'"), - ('‘', "Left Single Quotation Mark", "\'"), - ('’', "Right Single Quotation Mark", "\'"), - ('‛', "Single High-Reversed-9 Quotation Mark", "\'"), - ('′', "Prime", "\'"), - ('‵', "Reversed Prime", "\'"), - ('՚', "Armenian Apostrophe", "\'"), - ('׳', "Hebrew Punctuation Geresh", "\'"), - ('`', "Grave Accent", "\'"), - ('`', "Greek Varia", "\'"), - ('`', "Fullwidth Grave Accent", "\'"), - ('´', "Acute Accent", "\'"), - ('΄', "Greek Tonos", "\'"), - ('´', "Greek Oxia", "\'"), - ('᾽', "Greek Koronis", "\'"), - ('᾿', "Greek Psili", "\'"), - ('῾', "Greek Dasia", "\'"), - ('ʹ', "Modifier Letter Prime", "\'"), - ('ʹ', "Greek Numeral Sign", "\'"), - ('ˈ', "Modifier Letter Vertical Line", "\'"), - ('ˊ', "Modifier Letter Acute Accent", "\'"), - ('ˋ', "Modifier Letter Grave Accent", "\'"), - ('˴', "Modifier Letter Middle Grave Accent", "\'"), - ('ʻ', "Modifier Letter Turned Comma", "\'"), - ('ʽ', "Modifier Letter Reversed Comma", "\'"), - ('ʼ', "Modifier Letter Apostrophe", "\'"), - ('ʾ', "Modifier Letter Right Half Ring", "\'"), - ('ꞌ', "Latin Small Letter Saltillo", "\'"), - ('י', "Hebrew Letter Yod", "\'"), - ('ߴ', "Nko High Tone Apostrophe", "\'"), - ('ߵ', "Nko Low Tone Apostrophe", "\'"), - ('ᑊ', "Canadian Syllabics West-Cree P", "\'"), - ('ᛌ', "Runic Letter Short-Twig-Sol S", "\'"), - ('𖽑', "Miao Sign Aspiration", "\'"), - ('𖽒', "Miao Sign Reformed Voicing", "\'"), + ('՝', "Armenian Comma", "'"), + (''', "Fullwidth Apostrophe", "'"), + ('‘', "Left Single Quotation Mark", "'"), + ('’', "Right Single Quotation Mark", "'"), + ('‛', "Single High-Reversed-9 Quotation Mark", "'"), + ('′', "Prime", "'"), + ('‵', "Reversed Prime", "'"), + ('՚', "Armenian Apostrophe", "'"), + ('׳', "Hebrew Punctuation Geresh", "'"), + ('`', "Grave Accent", "'"), + ('`', "Greek Varia", "'"), + ('`', "Fullwidth Grave Accent", "'"), + ('´', "Acute Accent", "'"), + ('΄', "Greek Tonos", "'"), + ('´', "Greek Oxia", "'"), + ('᾽', "Greek Koronis", "'"), + ('᾿', "Greek Psili", "'"), + ('῾', "Greek Dasia", "'"), + ('ʹ', "Modifier Letter Prime", "'"), + ('ʹ', "Greek Numeral Sign", "'"), + ('ˈ', "Modifier Letter Vertical Line", "'"), + ('ˊ', "Modifier Letter Acute Accent", "'"), + ('ˋ', "Modifier Letter Grave Accent", "'"), + ('˴', "Modifier Letter Middle Grave Accent", "'"), + ('ʻ', "Modifier Letter Turned Comma", "'"), + ('ʽ', "Modifier Letter Reversed Comma", "'"), + ('ʼ', "Modifier Letter Apostrophe", "'"), + ('ʾ', "Modifier Letter Right Half Ring", "'"), + ('ꞌ', "Latin Small Letter Saltillo", "'"), + ('י', "Hebrew Letter Yod", "'"), + ('ߴ', "Nko High Tone Apostrophe", "'"), + ('ߵ', "Nko Low Tone Apostrophe", "'"), + ('ᑊ', "Canadian Syllabics West-Cree P", "'"), + ('ᛌ', "Runic Letter Short-Twig-Sol S", "'"), + ('𖽑', "Miao Sign Aspiration", "'"), + ('𖽒', "Miao Sign Reformed Voicing", "'"), ('᳓', "Vedic Sign Nihshvasa", "\""), ('"', "Fullwidth Quotation Mark", "\""), @@ -298,6 +298,7 @@ pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ ('〉', "Right Angle Bracket", ">"), ('》', "Right Double Angle Bracket", ">"), ('>', "Fullwidth Greater-Than Sign", ">"), + ('⩵', "Two Consecutive Equals Signs", "==") ]; @@ -332,7 +333,7 @@ const ASCII_ARRAY: &[(&str, &str, Option)] = &[ (">", "Greater-Than Sign", Some(token::Gt)), // FIXME: Literals are already lexed by this point, so we can't recover gracefully just by // spitting the correct token out. - ("\'", "Single Quote", None), + ("'", "Single Quote", None), ("\"", "Quotation Mark", None), ]; From d1215da26e7848bd925a9fffecdaa7ea51b360c3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 09:23:35 +1000 Subject: [PATCH 16/29] Don't use the word "parse" for lexing operations. Lexing converts source text into a token stream. Parsing converts a token stream into AST fragments. This commit renames several lexing operations that have "parse" in the name. I think these names have been subtly confusing me for years. This is just a `s/parse/lex/` on function names, with one exception: `parse_stream_from_source_str` becomes `source_str_to_stream`, to make it consistent with the existing `source_file_to_stream`. The commit also moves that function's location in the file to be just above `source_file_to_stream`. The commit also cleans up a few comments along the way. --- .../rustc_expand/src/proc_macro_server.rs | 4 +- compiler/rustc_parse/src/lexer/mod.rs | 4 +- compiler/rustc_parse/src/lexer/tokentrees.rs | 47 +++++++++---------- compiler/rustc_parse/src/lib.rs | 24 +++++----- .../passes/lint/check_code_block_syntax.rs | 11 ++--- 5 files changed, 41 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index c2e799abae804..3b167c42e57d9 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -13,7 +13,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, ErrorGuaranteed, MultiSpan, PResult}; use rustc_parse::lexer::nfc_normalize; -use rustc_parse::parse_stream_from_source_str; +use rustc_parse::source_str_to_stream; use rustc_session::parse::ParseSess; use rustc_span::def_id::CrateNum; use rustc_span::symbol::{self, sym, Symbol}; @@ -538,7 +538,7 @@ impl server::TokenStream for Rustc<'_, '_> { } fn from_str(&mut self, src: &str) -> Self::TokenStream { - parse_stream_from_source_str( + source_str_to_stream( FileName::proc_macro_source_code(src), src.to_string(), self.psess(), diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index d3a6a0339784a..43f4963b27acb 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -42,7 +42,7 @@ pub(crate) struct UnmatchedDelim { pub candidate_span: Option, } -pub(crate) fn parse_token_trees<'psess, 'src>( +pub(crate) fn lex_token_trees<'psess, 'src>( psess: &'psess ParseSess, mut src: &'src str, mut start_pos: BytePos, @@ -66,7 +66,7 @@ pub(crate) fn parse_token_trees<'psess, 'src>( last_lifetime: None, }; let (stream, res, unmatched_delims) = - tokentrees::TokenTreesReader::parse_all_token_trees(string_reader); + tokentrees::TokenTreesReader::lex_all_token_trees(string_reader); match res { Ok(()) if unmatched_delims.is_empty() => Ok(stream), _ => { diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index eabe0226b2fb9..fcbfa108d0660 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -17,7 +17,7 @@ pub(super) struct TokenTreesReader<'psess, 'src> { } impl<'psess, 'src> TokenTreesReader<'psess, 'src> { - pub(super) fn parse_all_token_trees( + pub(super) fn lex_all_token_trees( string_reader: StringReader<'psess, 'src>, ) -> (TokenStream, Result<(), Vec>>, Vec) { let mut tt_reader = TokenTreesReader { @@ -25,14 +25,13 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { token: Token::dummy(), diag_info: TokenTreeDiagInfo::default(), }; - let (_open_spacing, stream, res) = - tt_reader.parse_token_trees(/* is_delimited */ false); + let (_open_spacing, stream, res) = tt_reader.lex_token_trees(/* is_delimited */ false); (stream, res, tt_reader.diag_info.unmatched_delims) } - // Parse a stream of tokens into a list of `TokenTree`s. The `Spacing` in - // the result is that of the opening delimiter. - fn parse_token_trees( + // Lex into a token stream. The `Spacing` in the result is that of the + // opening delimiter. + fn lex_token_trees( &mut self, is_delimited: bool, ) -> (Spacing, TokenStream, Result<(), Vec>>) { @@ -42,12 +41,10 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { let mut buf = Vec::new(); loop { match self.token.kind { - token::OpenDelim(delim) => { - buf.push(match self.parse_token_tree_open_delim(delim) { - Ok(val) => val, - Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)), - }) - } + token::OpenDelim(delim) => buf.push(match self.lex_token_tree_open_delim(delim) { + Ok(val) => val, + Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)), + }), token::CloseDelim(delim) => { return ( open_spacing, @@ -95,24 +92,24 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { err } - fn parse_token_tree_open_delim( + fn lex_token_tree_open_delim( &mut self, open_delim: Delimiter, ) -> Result>> { - // The span for beginning of the delimited section + // The span for beginning of the delimited section. let pre_span = self.token.span; self.diag_info.open_braces.push((open_delim, self.token.span)); - // Parse the token trees within the delimiters. + // Lex the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user // uses an incorrect delimiter. - let (open_spacing, tts, res) = self.parse_token_trees(/* is_delimited */ true); + let (open_spacing, tts, res) = self.lex_token_trees(/* is_delimited */ true); if let Err(errs) = res { return Err(self.unclosed_delim_err(tts, errs)); } - // Expand to cover the entire delimited token tree + // 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(); @@ -150,7 +147,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { self.diag_info.last_unclosed_found_span = Some(self.token.span); // This is a conservative error: only report the last unclosed // delimiter. The previous unclosed delimiters could actually be - // closed! The parser just hasn't gotten to them yet. + // closed! The lexer just hasn't gotten to them yet. if let Some(&(_, sp)) = self.diag_info.open_braces.last() { unclosed_delimiter = Some(sp); }; @@ -236,9 +233,9 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { // out instead of complaining about the unclosed delims. let mut parser = crate::stream_to_parser(self.string_reader.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, but - // we have no way of tracking this in the lexer itself, so we piggyback on the parser + // 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, + // but we have no way of tracking this in the lexer itself, so we piggyback on the parser. let mut in_cond = false; while parser.token != token::Eof { if let Err(diff_err) = parser.err_vcs_conflict_marker() { @@ -249,14 +246,15 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { parser.token.kind, token::CloseDelim(Delimiter::Brace) | token::FatArrow ) { - // end of the `if`/`while` body, or the end of a `match` guard + // End of the `if`/`while` body, or the end of a `match` guard. in_cond = false; } else if in_cond && parser.token == token::OpenDelim(Delimiter::Brace) { // Store the `&&` and `let` to use their spans later when creating the diagnostic let maybe_andand = parser.look_ahead(1, |t| t.clone()); let maybe_let = parser.look_ahead(2, |t| t.clone()); if maybe_andand == token::OpenDelim(Delimiter::Brace) { - // This might be the beginning of the `if`/`while` body (i.e., the end of the condition) + // This might be the beginning of the `if`/`while` body (i.e., the end of the + // condition). in_cond = false; } else if maybe_andand == token::AndAnd && maybe_let.is_keyword(kw::Let) { let mut err = parser.dcx().struct_span_err( @@ -288,8 +286,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { } fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'psess> { - // An unexpected closing delimiter (i.e., there is no - // matching opening delimiter). + // 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.psess.dcx.struct_span_err(self.token.span, msg); diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 322739be3fb3c..b4610447be7bb 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -84,15 +84,6 @@ pub fn parse_crate_attrs_from_source_str( new_parser_from_source_str(psess, name, source).parse_inner_attributes() } -pub fn parse_stream_from_source_str( - name: FileName, - source: String, - psess: &ParseSess, - override_span: Option, -) -> TokenStream { - source_file_to_stream(psess, psess.source_map().new_source_file(name, source), override_span) -} - /// Creates a new parser from a source string. pub fn new_parser_from_source_str(psess: &ParseSess, name: FileName, source: String) -> Parser<'_> { panictry_buffer!(maybe_new_parser_from_source_str(psess, name, source)) @@ -142,6 +133,15 @@ fn maybe_source_file_to_parser( // Base abstractions +pub fn source_str_to_stream( + name: FileName, + source: String, + psess: &ParseSess, + override_span: Option, +) -> TokenStream { + source_file_to_stream(psess, psess.source_map().new_source_file(name, source), override_span) +} + /// Given a `source_file`, produces a sequence of token trees. pub fn source_file_to_stream( psess: &ParseSess, @@ -165,7 +165,7 @@ fn maybe_file_to_stream<'psess>( )); }); - lexer::parse_token_trees(psess, src.as_str(), source_file.start_pos, override_span) + lexer::lex_token_trees(psess, src.as_str(), source_file.start_pos, override_span) } /// Given a stream and the `ParseSess`, produces a parser. @@ -195,13 +195,13 @@ pub fn parse_in<'a, T>( pub fn fake_token_stream_for_item(psess: &ParseSess, item: &ast::Item) -> TokenStream { let source = pprust::item_to_string(item); let filename = FileName::macro_expansion_source_code(&source); - parse_stream_from_source_str(filename, source, psess, Some(item.span)) + source_str_to_stream(filename, source, psess, Some(item.span)) } pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> TokenStream { let source = pprust::crate_to_string_for_macros(krate); let filename = FileName::macro_expansion_source_code(&source); - parse_stream_from_source_str(filename, source, psess, Some(krate.spans.inner_span)) + source_str_to_stream(filename, source, psess, Some(krate.spans.inner_span)) } pub fn parse_cfg_attr( diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 39350f4cbbb62..4f044450df27e 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -5,7 +5,7 @@ use rustc_errors::{ translation::{to_fluent_args, Translate}, Applicability, DiagCtxt, DiagInner, LazyFallbackBundle, }; -use rustc_parse::parse_stream_from_source_str; +use rustc_parse::source_str_to_stream; use rustc_resolve::rustdoc::source_span_for_markdown_range; use rustc_session::parse::ParseSess; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, Transparency}; @@ -51,13 +51,8 @@ fn check_rust_syntax( let span = DUMMY_SP.apply_mark(expn_id.to_expn_id(), Transparency::Transparent); let is_empty = rustc_driver::catch_fatal_errors(|| { - parse_stream_from_source_str( - FileName::Custom(String::from("doctest")), - source, - &psess, - Some(span), - ) - .is_empty() + source_str_to_stream(FileName::Custom(String::from("doctest")), source, &psess, Some(span)) + .is_empty() }) .unwrap_or(false); let buffer = buffer.borrow(); From f6576249abf9d66b936d55a4d15c44932c800fe2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 10:59:16 +1000 Subject: [PATCH 17/29] Inline and remove `error_malformed_cfg_attr_missing`. It has a single call site. This also means `CFG_ATTR_{GRAMMAR_HELP,NOTE_REF}` can be moved into `parse_cfg_attr`, now that it's the only function that uses them. And the commit removes the line break in the URL. --- compiler/rustc_parse/src/lib.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index b4610447be7bb..a3de5db734745 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -208,6 +208,10 @@ pub fn parse_cfg_attr( attr: &Attribute, psess: &ParseSess, ) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { + const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; + const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ + "; + match attr.get_normal_item().args { ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) if !tokens.is_empty() => @@ -222,16 +226,12 @@ pub fn parse_cfg_attr( } } } - _ => error_malformed_cfg_attr_missing(attr.span, psess), + _ => { + psess.dcx.emit_err(errors::MalformedCfgAttr { + span: attr.span, + sugg: CFG_ATTR_GRAMMAR_HELP, + }); + } } None } - -const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; -const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ - "; - -fn error_malformed_cfg_attr_missing(span: Span, psess: &ParseSess) { - psess.dcx.emit_err(errors::MalformedCfgAttr { span, sugg: CFG_ATTR_GRAMMAR_HELP }); -} From 769ca3f661e3c9ef3b97007f210f73415fb92796 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 11:01:23 +1000 Subject: [PATCH 18/29] Rename `maybe_file_to_stream` as `maybe_source_file_to_stream`. Because it takes an `Lrc`, and for consistency with `source_file_to_stream`. --- compiler/rustc_parse/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index a3de5db734745..a818aae27b109 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -122,7 +122,7 @@ fn maybe_source_file_to_parser( source_file: Lrc, ) -> Result, Vec>> { let end_pos = source_file.end_position(); - let stream = maybe_file_to_stream(psess, source_file, None)?; + let stream = maybe_source_file_to_stream(psess, source_file, None)?; let mut parser = stream_to_parser(psess, stream, None); if parser.token == token::Eof { parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None); @@ -148,12 +148,12 @@ pub fn source_file_to_stream( source_file: Lrc, override_span: Option, ) -> TokenStream { - panictry_buffer!(maybe_file_to_stream(psess, source_file, override_span)) + panictry_buffer!(maybe_source_file_to_stream(psess, source_file, override_span)) } /// Given a source file, produces a sequence of token trees. Returns any buffered errors from /// parsing the token stream. -fn maybe_file_to_stream<'psess>( +fn maybe_source_file_to_stream<'psess>( psess: &'psess ParseSess, source_file: Lrc, override_span: Option, From 3c321b9ea8706ca0b8e05222b82100bad8da805e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 13:32:54 +1000 Subject: [PATCH 19/29] Remove `stream_to_parser`. It's a zero-value wrapper of `Parser::new`. --- compiler/rustc_builtin_macros/src/cfg_eval.rs | 2 +- compiler/rustc_expand/src/base.rs | 6 +++--- compiler/rustc_expand/src/proc_macro.rs | 5 ++--- compiler/rustc_expand/src/proc_macro_server.rs | 7 ++----- compiler/rustc_parse/src/lexer/tokentrees.rs | 3 ++- compiler/rustc_parse/src/lib.rs | 11 +---------- src/tools/rustfmt/src/parse/macros/mod.rs | 4 ++-- 7 files changed, 13 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 5f63a8ae0a8c2..03aff6f96330e 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -196,7 +196,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]`) - let mut parser = rustc_parse::stream_to_parser(&self.cfg.sess.psess, orig_tokens, None); + let mut parser = Parser::new(&self.cfg.sess.psess, orig_tokens, None); parser.capture_cfg = true; match parse_annotatable_with(&mut parser) { Ok(a) => annotatable = a, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 4539129bd0f78..b3f6a35f3a4b3 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -15,7 +15,7 @@ use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; -use rustc_parse::{parser, MACRO_ARGUMENTS}; +use rustc_parse::{parser::Parser, MACRO_ARGUMENTS}; use rustc_session::config::CollapseMacroDebuginfo; use rustc_session::{parse::ParseSess, Limit, Session}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; @@ -1149,8 +1149,8 @@ impl<'a> ExtCtxt<'a> { pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { expand::MacroExpander::new(self, true) } - pub fn new_parser_from_tts(&self, stream: TokenStream) -> parser::Parser<'a> { - rustc_parse::stream_to_parser(&self.sess.psess, stream, MACRO_ARGUMENTS) + pub fn new_parser_from_tts(&self, stream: TokenStream) -> Parser<'a> { + Parser::new(&self.sess.psess, stream, MACRO_ARGUMENTS) } pub fn source_map(&self) -> &'a SourceMap { self.sess.psess.source_map() diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index c11369f505f8c..96145affe0ae8 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -6,7 +6,7 @@ use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_errors::ErrorGuaranteed; -use rustc_parse::parser::ForceCollect; +use rustc_parse::parser::{ForceCollect, Parser}; use rustc_session::config::ProcMacroExecutionStrategy; use rustc_span::profiling::SpannedEventArgRecorder; use rustc_span::Span; @@ -154,8 +154,7 @@ impl MultiItemModifier for DeriveProcMacro { }; let error_count_before = ecx.dcx().err_count(); - let mut parser = - rustc_parse::stream_to_parser(&ecx.sess.psess, stream, Some("proc-macro derive")); + let mut parser = Parser::new(&ecx.sess.psess, stream, Some("proc-macro derive")); let mut items = vec![]; loop { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 3b167c42e57d9..9ae9f7c10c01f 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -13,6 +13,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, ErrorGuaranteed, MultiSpan, PResult}; use rustc_parse::lexer::nfc_normalize; +use rustc_parse::parser::Parser; use rustc_parse::source_str_to_stream; use rustc_session::parse::ParseSess; use rustc_span::def_id::CrateNum; @@ -553,11 +554,7 @@ impl server::TokenStream for Rustc<'_, '_> { fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result { // Parse the expression from our tokenstream. let expr: PResult<'_, _> = try { - let mut p = rustc_parse::stream_to_parser( - self.psess(), - stream.clone(), - Some("proc_macro expand expr"), - ); + let mut p = Parser::new(self.psess(), stream.clone(), Some("proc_macro expand expr")); let expr = p.parse_expr()?; if p.token != token::Eof { p.unexpected()?; diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index fcbfa108d0660..f7645446081ad 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -2,6 +2,7 @@ use super::diagnostics::report_suspicious_mismatch_block; use super::diagnostics::same_indentation_level; use super::diagnostics::TokenTreeDiagInfo; use super::{StringReader, UnmatchedDelim}; +use crate::Parser; use rustc_ast::token::{self, Delimiter, Token}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust::token_to_string; @@ -231,7 +232,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 = crate::stream_to_parser(self.string_reader.psess, tts, None); + let mut parser = Parser::new(self.string_reader.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, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index a818aae27b109..5bbbfe1430c33 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -123,7 +123,7 @@ fn maybe_source_file_to_parser( ) -> Result, Vec>> { let end_pos = source_file.end_position(); let stream = maybe_source_file_to_stream(psess, source_file, None)?; - let mut parser = stream_to_parser(psess, stream, None); + let mut parser = Parser::new(psess, stream, None); if parser.token == token::Eof { parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None); } @@ -168,15 +168,6 @@ fn maybe_source_file_to_stream<'psess>( lexer::lex_token_trees(psess, src.as_str(), source_file.start_pos, override_span) } -/// Given a stream and the `ParseSess`, produces a parser. -pub fn stream_to_parser<'a>( - psess: &'a ParseSess, - stream: TokenStream, - subparser_name: Option<&'static str>, -) -> Parser<'a> { - Parser::new(psess, stream, subparser_name) -} - /// Runs the given subparser `f` on the tokens of the given `attr`'s item. pub fn parse_in<'a, T>( psess: &'a ParseSess, diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index 3cf133c647cc4..cbcc0b2d63648 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -2,7 +2,7 @@ use rustc_ast::token::{Delimiter, NonterminalKind, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ast, ptr}; use rustc_parse::parser::{ForceCollect, Parser, Recovery}; -use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS}; +use rustc_parse::MACRO_ARGUMENTS; use rustc_session::parse::ParseSess; use rustc_span::symbol::{self, kw}; use rustc_span::Symbol; @@ -15,7 +15,7 @@ pub(crate) mod cfg_if; pub(crate) mod lazy_static; fn build_stream_parser<'a>(psess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> { - stream_to_parser(psess, tokens, MACRO_ARGUMENTS).recovery(Recovery::Forbidden) + Parser::new(psess, tokens, MACRO_ARGUMENTS).recovery(Recovery::Forbidden) } fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a> { From af13b4892786a3f77d440016409414eeadd7d37e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 13:36:18 +1000 Subject: [PATCH 20/29] Improve `panictry_buffer!`. - Convert it from a macro to a function, which is nicer. - Rename it as `unwrap_or_emit_fatal`, which is clearer. - Fix the comment. In particular, `panictry!` no longer exists. - Remove the unnecessary `use` declaration. --- compiler/rustc_parse/src/lib.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 5bbbfe1430c33..298d02d2e58f2 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -39,20 +39,17 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } // uses a HOF to parse anything, and includes file and // `source_str`. -/// A variant of 'panictry!' that works on a `Vec` instead of a single `Diag`. -macro_rules! panictry_buffer { - ($e:expr) => {{ - use std::result::Result::{Err, Ok}; - match $e { - Ok(e) => e, - Err(errs) => { - for e in errs { - e.emit(); - } - FatalError.raise() +// Unwrap the result if `Ok`, otherwise emit the diagnostics and abort. +fn unwrap_or_emit_fatal(expr: Result>>) -> T { + match expr { + Ok(expr) => expr, + Err(errs) => { + for err in errs { + err.emit(); } + FatalError.raise() } - }}; + } } pub fn parse_crate_from_file<'a>(input: &Path, psess: &'a ParseSess) -> PResult<'a, ast::Crate> { @@ -86,7 +83,7 @@ pub fn parse_crate_attrs_from_source_str( /// Creates a new parser from a source string. pub fn new_parser_from_source_str(psess: &ParseSess, name: FileName, source: String) -> Parser<'_> { - panictry_buffer!(maybe_new_parser_from_source_str(psess, name, source)) + unwrap_or_emit_fatal(maybe_new_parser_from_source_str(psess, name, source)) } /// Creates a new parser from a source string. Returns any buffered errors from lexing the initial @@ -112,7 +109,7 @@ pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option, override_span: Option, ) -> TokenStream { - panictry_buffer!(maybe_source_file_to_stream(psess, source_file, override_span)) + unwrap_or_emit_fatal(maybe_source_file_to_stream(psess, source_file, override_span)) } /// Given a source file, produces a sequence of token trees. Returns any buffered errors from From 29e6e2859be6ea69a486bdc155df9311455f55dc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 13:38:51 +1000 Subject: [PATCH 21/29] Remove low-value comments. The first one is out-of-date -- there are no longer functions expr, item, stmt. And I don't know what a "HOF" is. The second one doesn't really tell you anything. --- compiler/rustc_parse/src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 298d02d2e58f2..2c5a0abc6aca3 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -34,11 +34,6 @@ mod errors; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } -// A bunch of utility functions of the form `parse__from_` -// where includes crate, expr, item, stmt, tts, and one that -// uses a HOF to parse anything, and includes file and -// `source_str`. - // Unwrap the result if `Ok`, otherwise emit the diagnostics and abort. fn unwrap_or_emit_fatal(expr: Result>>) -> T { match expr { @@ -128,8 +123,6 @@ fn maybe_source_file_to_parser( Ok(parser) } -// Base abstractions - pub fn source_str_to_stream( name: FileName, source: String, From 191b76ef3116736416c28d39d35102c78cb33a07 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 13:39:24 +1000 Subject: [PATCH 22/29] Rename `maybe_source_file_to_parser` as `maybe_new_parser_from_source_file`. For consistency with `new_parser_from_{file,source_str}` and `maybe_new_parser_from_source_str`. --- compiler/rustc_parse/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 2c5a0abc6aca3..1a0535684e8e9 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -89,7 +89,7 @@ pub fn maybe_new_parser_from_source_str( name: FileName, source: String, ) -> Result, Vec>> { - maybe_source_file_to_parser(psess, psess.source_map().new_source_file(name, source)) + maybe_new_parser_from_source_file(psess, psess.source_map().new_source_file(name, source)) } /// Creates a new parser, aborting if the file doesn't exist. If a span is given, that is used on @@ -104,12 +104,12 @@ pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option, ) -> Result, Vec>> { From 8964106e44c39cced6cc039bf512a69513a2bbe5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 13:43:38 +1000 Subject: [PATCH 23/29] Use `source_str_to_stream` in a test file. It does exactly what is required. --- compiler/rustc_parse/src/parser/tests.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index a31e350541ab3..b72cfd63d00db 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1,5 +1,5 @@ use crate::parser::ForceCollect; -use crate::{new_parser_from_source_str, parser::Parser, source_file_to_stream}; +use crate::{new_parser_from_source_str, parser::Parser, source_str_to_stream}; use ast::token::IdentIsRaw; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token}; @@ -82,11 +82,7 @@ where /// Maps a string to tts, using a made-up filename. pub(crate) fn string_to_stream(source_str: String) -> TokenStream { let psess = psess(); - source_file_to_stream( - &psess, - psess.source_map().new_source_file(PathBuf::from("bogofile").into(), source_str), - None, - ) + source_str_to_stream(PathBuf::from("bogofile").into(), source_str, &psess, None) } /// Parses a string, returns a crate. From 25972aec67e900aeefe4014deecf5ef853a4bab4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 13:56:44 +1000 Subject: [PATCH 24/29] Inline and remove `parse_crate{,_attrs}_from_{file,source_str}`. All four functions are simple and have a single call site. This requires making `Parser::parse_inner_attributes` public, which is no big deal. --- compiler/rustc_driver_impl/src/lib.rs | 10 +++++---- compiler/rustc_interface/src/passes.rs | 15 ++++++++----- compiler/rustc_parse/src/lib.rs | 29 ------------------------- compiler/rustc_parse/src/parser/attr.rs | 2 +- 4 files changed, 16 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 627fd74c8d77c..236880420fc2e 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -32,6 +32,7 @@ use rustc_interface::{interface, Queries}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; +use rustc_parse::{new_parser_from_file, new_parser_from_source_str}; use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType}; use rustc_session::getopts::{self, Matches}; @@ -1264,12 +1265,13 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option(sess: &'a Session) -> PResult<'a, ast::AttrVec> { - match &sess.io.input { - Input::File(ifile) => rustc_parse::parse_crate_attrs_from_file(ifile, &sess.psess), + let mut parser = match &sess.io.input { + Input::File(file) => new_parser_from_file(&sess.psess, file, None), Input::Str { name, input } => { - rustc_parse::parse_crate_attrs_from_source_str(name.clone(), input.clone(), &sess.psess) + new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) } - } + }; + parser.parse_inner_attributes() } /// Runs a closure and catches unwinds triggered by fatal errors. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index b678582766d5d..b3ed66220977c 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -19,7 +19,7 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_middle::util::Providers; -use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; +use rustc_parse::{new_parser_from_file, new_parser_from_source_str, validate_attr}; use rustc_passes::{abi_test, hir_stats, layout_test}; use rustc_resolve::Resolver; use rustc_session::code_stats::VTableSizeInfo; @@ -42,11 +42,14 @@ use std::{env, fs, iter}; use tracing::{info, instrument}; pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> { - let krate = sess.time("parse_crate", || match &sess.io.input { - Input::File(file) => parse_crate_from_file(file, &sess.psess), - Input::Str { input, name } => { - parse_crate_from_source_str(name.clone(), input.clone(), &sess.psess) - } + let krate = sess.time("parse_crate", || { + let mut parser = match &sess.io.input { + Input::File(file) => new_parser_from_file(&sess.psess, file, None), + Input::Str { input, name } => { + new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) + } + }; + parser.parse_crate_mod() })?; if sess.opts.unstable_opts.input_stats { diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 1a0535684e8e9..b804e77e7a4e5 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -47,35 +47,6 @@ fn unwrap_or_emit_fatal(expr: Result>>) -> T { } } -pub fn parse_crate_from_file<'a>(input: &Path, psess: &'a ParseSess) -> PResult<'a, ast::Crate> { - let mut parser = new_parser_from_file(psess, input, None); - parser.parse_crate_mod() -} - -pub fn parse_crate_attrs_from_file<'a>( - input: &Path, - psess: &'a ParseSess, -) -> PResult<'a, ast::AttrVec> { - let mut parser = new_parser_from_file(psess, input, None); - parser.parse_inner_attributes() -} - -pub fn parse_crate_from_source_str( - name: FileName, - source: String, - psess: &ParseSess, -) -> PResult<'_, ast::Crate> { - new_parser_from_source_str(psess, name, source).parse_crate_mod() -} - -pub fn parse_crate_attrs_from_source_str( - name: FileName, - source: String, - psess: &ParseSess, -) -> PResult<'_, ast::AttrVec> { - new_parser_from_source_str(psess, name, source).parse_inner_attributes() -} - /// Creates a new parser from a source string. pub fn new_parser_from_source_str(psess: &ParseSess, name: FileName, source: String) -> Parser<'_> { unwrap_or_emit_fatal(maybe_new_parser_from_source_str(psess, name, source)) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index a57eb70c7053a..4acc610d8c405 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -265,7 +265,7 @@ impl<'a> Parser<'a> { /// terminated by a semicolon. /// /// Matches `inner_attrs*`. - pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> { + 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(); From ab192a0c97cd0d03d24e402640576474cb62c972 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 14:33:56 +1000 Subject: [PATCH 25/29] Reorder `source_str_to_stream` arguments. It's the only one of these functions where `psess` isn't the first argument. --- compiler/rustc_expand/src/proc_macro_server.rs | 2 +- compiler/rustc_parse/src/lib.rs | 6 +++--- compiler/rustc_parse/src/parser/tests.rs | 2 +- src/librustdoc/passes/lint/check_code_block_syntax.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 9ae9f7c10c01f..330a6c347702e 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -540,9 +540,9 @@ impl server::TokenStream for Rustc<'_, '_> { fn from_str(&mut self, src: &str) -> Self::TokenStream { source_str_to_stream( + self.psess(), FileName::proc_macro_source_code(src), src.to_string(), - self.psess(), Some(self.call_site), ) } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index b804e77e7a4e5..5ba6db3b2620b 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -95,9 +95,9 @@ fn maybe_new_parser_from_source_file( } pub fn source_str_to_stream( + psess: &ParseSess, name: FileName, source: String, - psess: &ParseSess, override_span: Option, ) -> TokenStream { source_file_to_stream(psess, psess.source_map().new_source_file(name, source), override_span) @@ -147,13 +147,13 @@ pub fn parse_in<'a, T>( pub fn fake_token_stream_for_item(psess: &ParseSess, item: &ast::Item) -> TokenStream { let source = pprust::item_to_string(item); let filename = FileName::macro_expansion_source_code(&source); - source_str_to_stream(filename, source, psess, Some(item.span)) + source_str_to_stream(psess, filename, source, Some(item.span)) } pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> TokenStream { let source = pprust::crate_to_string_for_macros(krate); let filename = FileName::macro_expansion_source_code(&source); - source_str_to_stream(filename, source, psess, Some(krate.spans.inner_span)) + source_str_to_stream(psess, filename, source, Some(krate.spans.inner_span)) } pub fn parse_cfg_attr( diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index b72cfd63d00db..2900d44089ea7 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -82,7 +82,7 @@ where /// Maps a string to tts, using a made-up filename. pub(crate) fn string_to_stream(source_str: String) -> TokenStream { let psess = psess(); - source_str_to_stream(PathBuf::from("bogofile").into(), source_str, &psess, None) + source_str_to_stream(&psess, PathBuf::from("bogofile").into(), source_str, None) } /// Parses a string, returns a crate. diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 4f044450df27e..409546734cb11 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -51,7 +51,7 @@ fn check_rust_syntax( let span = DUMMY_SP.apply_mark(expn_id.to_expn_id(), Transparency::Transparent); let is_empty = rustc_driver::catch_fatal_errors(|| { - source_str_to_stream(FileName::Custom(String::from("doctest")), source, &psess, Some(span)) + source_str_to_stream(&psess, FileName::Custom(String::from("doctest")), source, Some(span)) .is_empty() }) .unwrap_or(false); From 264dbe4d8145c076557a95a93183b8c1d6e1f564 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 14:38:34 +1000 Subject: [PATCH 26/29] Inline and remove `source_file_to_stream`. It has a single call site. --- compiler/rustc_parse/src/lib.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 5ba6db3b2620b..8a061ce8f1b55 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -100,15 +100,7 @@ pub fn source_str_to_stream( source: String, override_span: Option, ) -> TokenStream { - source_file_to_stream(psess, psess.source_map().new_source_file(name, source), override_span) -} - -/// Given a `source_file`, produces a sequence of token trees. -pub fn source_file_to_stream( - psess: &ParseSess, - source_file: Lrc, - override_span: Option, -) -> TokenStream { + let source_file = psess.source_map().new_source_file(name, source); unwrap_or_emit_fatal(maybe_source_file_to_stream(psess, source_file, override_span)) } From b9037339cbc636349b02088486effa21f9ab16aa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 May 2024 15:43:18 +1000 Subject: [PATCH 27/29] Make top-level `rustc_parse` functions fallible. Currently we have an awkward mix of fallible and infallible functions: ``` new_parser_from_source_str maybe_new_parser_from_source_str new_parser_from_file (maybe_new_parser_from_file) // missing (new_parser_from_source_file) // missing maybe_new_parser_from_source_file source_str_to_stream maybe_source_file_to_stream ``` We could add the two missing functions, but instead this commit removes of all the infallible ones and renames the fallible ones leaving us with these which are all fallible: ``` new_parser_from_source_str new_parser_from_file new_parser_from_source_file source_str_to_stream source_file_to_stream ``` This requires making `unwrap_or_emit_fatal` public so callers of formerly infallible functions can still work. This does make some of the call sites slightly more verbose, but I think it's worth it for the simpler API. Also, there are two `catch_unwind` calls and one `catch_fatal_errors` call in this diff that become removable thanks this change. (I will do that in a follow-up PR.) --- .../rustc_builtin_macros/src/cmdline_attrs.rs | 5 +- .../rustc_builtin_macros/src/source_util.rs | 4 +- compiler/rustc_driver_impl/src/lib.rs | 6 +-- compiler/rustc_expand/src/module.rs | 5 +- .../rustc_expand/src/proc_macro_server.rs | 9 ++-- compiler/rustc_interface/src/interface.rs | 6 +-- compiler/rustc_interface/src/passes.rs | 8 +-- compiler/rustc_parse/src/lib.rs | 54 ++++++++++--------- compiler/rustc_parse/src/parser/tests.rs | 22 ++++++-- src/librustdoc/clean/render_macro_matchers.rs | 2 +- src/librustdoc/doctest.rs | 23 ++++---- .../passes/lint/check_code_block_syntax.rs | 11 ++-- .../src/doc/needless_doctest_main.rs | 4 +- src/tools/rustfmt/src/parse/parser.rs | 10 ++-- .../ui-fulldeps/mod_dir_path_canonicalized.rs | 4 +- tests/ui-fulldeps/pprust-expr-roundtrip.rs | 7 +-- 16 files changed, 105 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index ada82e45712d8..e9b63b4abebb6 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -4,16 +4,17 @@ use crate::errors; use rustc_ast::attr::mk_attr; use rustc_ast::token; use rustc_ast::{self as ast, AttrItem, AttrStyle}; +use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::FileName; pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { for raw_attr in attrs { - let mut parser = rustc_parse::new_parser_from_source_str( + let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str( psess, FileName::cli_crate_attr_source_code(raw_attr), raw_attr.clone(), - ); + )); let start_span = parser.token.span; let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) { diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 29e991525a9be..dc1d82df0c395 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -12,8 +12,8 @@ use rustc_expand::base::{ }; use rustc_expand::module::DirOwnership; use rustc_lint_defs::BuiltinLintDiag; -use rustc_parse::new_parser_from_file; use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; @@ -126,7 +126,7 @@ pub(crate) fn expand_include<'cx>( return ExpandResult::Ready(DummyResult::any(sp, guar)); } }; - let p = new_parser_from_file(cx.psess(), &file, Some(sp)); + let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp))); // If in the included file we have e.g., `mod bar;`, // then the path of `bar.rs` should be relative to the directory of `file`. diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 236880420fc2e..93a65290602af 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -32,7 +32,7 @@ use rustc_interface::{interface, Queries}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; -use rustc_parse::{new_parser_from_file, new_parser_from_source_str}; +use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType}; use rustc_session::getopts::{self, Matches}; @@ -1265,12 +1265,12 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option(sess: &'a Session) -> PResult<'a, ast::AttrVec> { - let mut parser = match &sess.io.input { + let mut parser = unwrap_or_emit_fatal(match &sess.io.input { Input::File(file) => new_parser_from_file(&sess.psess, file, None), Input::Str { name, input } => { new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) } - }; + }); parser.parse_inner_attributes() } diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index c8983619e7016..506bd445be35f 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -5,8 +5,8 @@ use crate::errors::{ use rustc_ast::ptr::P; use rustc_ast::{token, AttrVec, Attribute, Inline, Item, ModSpans}; use rustc_errors::{Diag, ErrorGuaranteed}; -use rustc_parse::new_parser_from_file; use rustc_parse::validate_attr; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; @@ -66,7 +66,8 @@ pub(crate) fn parse_external_mod( } // Actually parse the external file as a module. - let mut parser = new_parser_from_file(&sess.psess, &mp.file_path, Some(span)); + let mut parser = + unwrap_or_emit_fatal(new_parser_from_file(&sess.psess, &mp.file_path, Some(span))); let (inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof).map_err(|err| ModError::ParserError(err))?; attrs.extend(inner_attrs); diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 330a6c347702e..93f8682090d74 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -14,7 +14,7 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, ErrorGuaranteed, MultiSpan, PResult}; use rustc_parse::lexer::nfc_normalize; use rustc_parse::parser::Parser; -use rustc_parse::source_str_to_stream; +use rustc_parse::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::def_id::CrateNum; use rustc_span::symbol::{self, sym, Symbol}; @@ -467,7 +467,8 @@ impl server::FreeFunctions for Rustc<'_, '_> { fn literal_from_str(&mut self, s: &str) -> Result, ()> { let name = FileName::proc_macro_source_code(s); - let mut parser = rustc_parse::new_parser_from_source_str(self.psess(), name, s.to_owned()); + let mut parser = + unwrap_or_emit_fatal(new_parser_from_source_str(self.psess(), name, s.to_owned())); let first_span = parser.token.span.data(); let minus_present = parser.eat(&token::BinOp(token::Minus)); @@ -539,12 +540,12 @@ impl server::TokenStream for Rustc<'_, '_> { } fn from_str(&mut self, src: &str) -> Self::TokenStream { - source_str_to_stream( + unwrap_or_emit_fatal(source_str_to_stream( self.psess(), FileName::proc_macro_source_code(src), src.to_string(), Some(self.call_site), - ) + )) } fn to_string(&mut self, stream: &Self::TokenStream) -> String { diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 5254a6576f905..c95a10f4e8d22 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -14,7 +14,7 @@ use rustc_lint::LintStore; use rustc_middle::ty; use rustc_middle::ty::CurrentGcx; use rustc_middle::util::Providers; -use rustc_parse::maybe_new_parser_from_source_str; +use rustc_parse::new_parser_from_source_str; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; @@ -67,7 +67,7 @@ pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec) -> Cfg { }; } - match maybe_new_parser_from_source_str(&psess, filename, s.to_string()) { + match new_parser_from_source_str(&psess, filename, s.to_string()) { Ok(mut parser) => match parser.parse_meta_item() { Ok(meta_item) if parser.token == token::Eof => { if meta_item.path.segments.len() != 1 { @@ -166,7 +166,7 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec) -> CheckCfg { error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`") }; - let mut parser = match maybe_new_parser_from_source_str(&psess, filename, s.to_string()) { + let mut parser = match new_parser_from_source_str(&psess, filename, s.to_string()) { Ok(parser) => parser, Err(errs) => { errs.into_iter().for_each(|err| err.cancel()); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index b3ed66220977c..a342577cffb82 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -19,7 +19,9 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_middle::util::Providers; -use rustc_parse::{new_parser_from_file, new_parser_from_source_str, validate_attr}; +use rustc_parse::{ + new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr, +}; use rustc_passes::{abi_test, hir_stats, layout_test}; use rustc_resolve::Resolver; use rustc_session::code_stats::VTableSizeInfo; @@ -43,12 +45,12 @@ use tracing::{info, instrument}; pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> { let krate = sess.time("parse_crate", || { - let mut parser = match &sess.io.input { + let mut parser = unwrap_or_emit_fatal(match &sess.io.input { Input::File(file) => new_parser_from_file(&sess.psess, file, None), Input::Str { input, name } => { new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) } - }; + }); parser.parse_crate_mod() })?; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 8a061ce8f1b55..b316327a262de 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -35,7 +35,7 @@ mod errors; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } // Unwrap the result if `Ok`, otherwise emit the diagnostics and abort. -fn unwrap_or_emit_fatal(expr: Result>>) -> T { +pub fn unwrap_or_emit_fatal(expr: Result>>) -> T { match expr { Ok(expr) => expr, Err(errs) => { @@ -47,25 +47,28 @@ fn unwrap_or_emit_fatal(expr: Result>>) -> T { } } -/// Creates a new parser from a source string. -pub fn new_parser_from_source_str(psess: &ParseSess, name: FileName, source: String) -> Parser<'_> { - unwrap_or_emit_fatal(maybe_new_parser_from_source_str(psess, name, source)) -} - -/// Creates a new parser from a source string. Returns any buffered errors from lexing the initial -/// token stream; these must be consumed via `emit`, `cancel`, etc., otherwise a panic will occur -/// when they are dropped. -pub fn maybe_new_parser_from_source_str( +/// Creates a new parser from a source string. On failure, the errors must be consumed via +/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are +/// dropped. +pub fn new_parser_from_source_str( psess: &ParseSess, name: FileName, source: String, ) -> Result, Vec>> { - maybe_new_parser_from_source_file(psess, psess.source_map().new_source_file(name, source)) + let source_file = psess.source_map().new_source_file(name, source); + new_parser_from_source_file(psess, source_file) } -/// Creates a new parser, aborting if the file doesn't exist. If a span is given, that is used on -/// an error as the source of the problem. -pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option) -> Parser<'a> { +/// Creates a new parser from a filename. On failure, the errors must be consumed via +/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are +/// dropped. +/// +/// If a span is given, that is used on an error as the source of the problem. +pub fn new_parser_from_file<'a>( + psess: &'a ParseSess, + path: &Path, + sp: Option, +) -> Result, Vec>> { let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| { let msg = format!("couldn't read {}: {}", path.display(), e); let mut err = psess.dcx.struct_fatal(msg); @@ -74,23 +77,21 @@ pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option, ) -> Result, Vec>> { let end_pos = source_file.end_position(); - let stream = maybe_source_file_to_stream(psess, source_file, None)?; + let stream = source_file_to_stream(psess, source_file, None)?; let mut parser = Parser::new(psess, stream, None); if parser.token == token::Eof { parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None); } - Ok(parser) } @@ -99,14 +100,14 @@ pub fn source_str_to_stream( name: FileName, source: String, override_span: Option, -) -> TokenStream { +) -> Result>> { let source_file = psess.source_map().new_source_file(name, source); - unwrap_or_emit_fatal(maybe_source_file_to_stream(psess, source_file, override_span)) + source_file_to_stream(psess, source_file, override_span) } /// Given a source file, produces a sequence of token trees. Returns any buffered errors from /// parsing the token stream. -fn maybe_source_file_to_stream<'psess>( +fn source_file_to_stream<'psess>( psess: &'psess ParseSess, source_file: Lrc, override_span: Option, @@ -139,13 +140,18 @@ pub fn parse_in<'a, T>( pub fn fake_token_stream_for_item(psess: &ParseSess, item: &ast::Item) -> TokenStream { let source = pprust::item_to_string(item); let filename = FileName::macro_expansion_source_code(&source); - source_str_to_stream(psess, filename, source, Some(item.span)) + unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span))) } pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> TokenStream { let source = pprust::crate_to_string_for_macros(krate); let filename = FileName::macro_expansion_source_code(&source); - source_str_to_stream(psess, filename, source, Some(krate.spans.inner_span)) + unwrap_or_emit_fatal(source_str_to_stream( + psess, + filename, + source, + Some(krate.spans.inner_span), + )) } pub fn parse_cfg_attr( diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 2900d44089ea7..79a6cf1b541ea 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1,5 +1,7 @@ use crate::parser::ForceCollect; -use crate::{new_parser_from_source_str, parser::Parser, source_str_to_stream}; +use crate::{ + new_parser_from_source_str, parser::Parser, source_str_to_stream, unwrap_or_emit_fatal, +}; use ast::token::IdentIsRaw; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token}; @@ -29,7 +31,11 @@ fn psess() -> ParseSess { /// Map string to parser (via tts). fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> { - new_parser_from_source_str(psess, PathBuf::from("bogofile").into(), source_str) + unwrap_or_emit_fatal(new_parser_from_source_str( + psess, + PathBuf::from("bogofile").into(), + source_str, + )) } fn create_test_handler() -> (DiagCtxt, Lrc, Arc>>) { @@ -82,7 +88,12 @@ where /// Maps a string to tts, using a made-up filename. pub(crate) fn string_to_stream(source_str: String) -> TokenStream { let psess = psess(); - source_str_to_stream(&psess, PathBuf::from("bogofile").into(), source_str, None) + unwrap_or_emit_fatal(source_str_to_stream( + &psess, + PathBuf::from("bogofile").into(), + source_str, + None, + )) } /// Parses a string, returns a crate. @@ -1064,7 +1075,8 @@ fn parse_item_from_source_str( source: String, psess: &ParseSess, ) -> PResult<'_, Option>> { - new_parser_from_source_str(psess, name, source).parse_item(ForceCollect::No) + unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)) + .parse_item(ForceCollect::No) } // Produces a `rustc_span::span`. @@ -1345,7 +1357,7 @@ fn ttdelim_span() { source: String, psess: &ParseSess, ) -> PResult<'_, P> { - new_parser_from_source_str(psess, name, source).parse_expr() + unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)).parse_expr() } create_default_session_globals_then(|| { diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index 5ac1b742c386a..995919f73f83b 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -65,7 +65,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option parser, Err(errs) => { errs.into_iter().for_each(|err| err.cancel()); diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a536a71392190..0d4bad6921db9 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -9,7 +9,7 @@ use rustc_interface::interface; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; -use rustc_parse::maybe_new_parser_from_source_str; +use rustc_parse::new_parser_from_source_str; use rustc_parse::parser::attr::InnerAttrPolicy; use rustc_resolve::rustdoc::span_of_fragments; use rustc_session::config::{self, CrateType, ErrorOutputType}; @@ -638,7 +638,7 @@ pub(crate) fn make_test( let mut found_extern_crate = crate_name.is_none(); let mut found_macro = false; - let mut parser = match maybe_new_parser_from_source_str(&psess, filename, source) { + let mut parser = match new_parser_from_source_str(&psess, filename, source) { Ok(p) => p, Err(errs) => { errs.into_iter().for_each(|err| err.cancel()); @@ -818,16 +818,15 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool { let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); let psess = ParseSess::with_dcx(dcx, sm); - let mut parser = - match maybe_new_parser_from_source_str(&psess, filename, source.to_owned()) { - Ok(p) => p, - Err(errs) => { - errs.into_iter().for_each(|err| err.cancel()); - // If there is an unclosed delimiter, an error will be returned by the - // tokentrees. - return false; - } - }; + let mut parser = match new_parser_from_source_str(&psess, filename, source.to_owned()) { + Ok(p) => p, + Err(errs) => { + errs.into_iter().for_each(|err| err.cancel()); + // If there is an unclosed delimiter, an error will be returned by the + // tokentrees. + return false; + } + }; // If a parsing error happened, it's very likely that the attribute is incomplete. if let Err(e) = parser.parse_attribute(InnerAttrPolicy::Permitted) { e.cancel(); diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 409546734cb11..c185442fd55dd 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -5,7 +5,7 @@ use rustc_errors::{ translation::{to_fluent_args, Translate}, Applicability, DiagCtxt, DiagInner, LazyFallbackBundle, }; -use rustc_parse::source_str_to_stream; +use rustc_parse::{source_str_to_stream, unwrap_or_emit_fatal}; use rustc_resolve::rustdoc::source_span_for_markdown_range; use rustc_session::parse::ParseSess; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, Transparency}; @@ -51,8 +51,13 @@ fn check_rust_syntax( let span = DUMMY_SP.apply_mark(expn_id.to_expn_id(), Transparency::Transparent); let is_empty = rustc_driver::catch_fatal_errors(|| { - source_str_to_stream(&psess, FileName::Custom(String::from("doctest")), source, Some(span)) - .is_empty() + unwrap_or_emit_fatal(source_str_to_stream( + &psess, + FileName::Custom(String::from("doctest")), + source, + Some(span), + )) + .is_empty() }) .unwrap_or(false); let buffer = buffer.borrow(); diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs index 651f2ebaee6f4..c3e3c0431e6b7 100644 --- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs +++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs @@ -8,7 +8,7 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::HumanEmitter; use rustc_errors::{Diag, DiagCtxt}; use rustc_lint::LateContext; -use rustc_parse::maybe_new_parser_from_source_str; +use rustc_parse::new_parser_from_source_str; use rustc_parse::parser::ForceCollect; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; @@ -50,7 +50,7 @@ pub fn check( let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let psess = ParseSess::with_dcx(dcx, sm); - let mut parser = match maybe_new_parser_from_source_str(&psess, filename, code) { + let mut parser = match new_parser_from_source_str(&psess, filename, code) { Ok(p) => p, Err(errs) => { errs.into_iter().for_each(Diag::cancel); diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index 5dcdca1d9538d..7adf339b453ae 100644 --- a/src/tools/rustfmt/src/parse/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -4,7 +4,8 @@ use std::path::{Path, PathBuf}; use rustc_ast::token::TokenKind; use rustc_ast::{ast, attr, ptr}; use rustc_errors::Diag; -use rustc_parse::{new_parser_from_file, parser::Parser as RawParser}; +use rustc_parse::parser::Parser as RawParser; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; use rustc_span::{sym, Span}; use thin_vec::ThinVec; @@ -68,10 +69,10 @@ impl<'a> ParserBuilder<'a> { ) -> Result, Option>>> { match input { Input::File(ref file) => catch_unwind(AssertUnwindSafe(move || { - new_parser_from_file(psess, file, None) + unwrap_or_emit_fatal(new_parser_from_file(psess, file, None)) })) .map_err(|_| None), - Input::Text(text) => rustc_parse::maybe_new_parser_from_source_str( + Input::Text(text) => rustc_parse::new_parser_from_source_str( psess, rustc_span::FileName::Custom("stdin".to_owned()), text, @@ -111,7 +112,8 @@ impl<'a> Parser<'a> { span: Span, ) -> Result<(ast::AttrVec, ThinVec>, Span), ParserError> { let result = catch_unwind(AssertUnwindSafe(|| { - let mut parser = new_parser_from_file(psess.inner(), path, Some(span)); + let mut parser = + unwrap_or_emit_fatal(new_parser_from_file(psess.inner(), path, Some(span))); match parser.parse_mod(&TokenKind::Eof) { Ok((a, i, spans)) => Some((a, i, spans.inner_span)), Err(e) => { diff --git a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs index ef70e64ed7e91..99cb5fc5aa1c6 100644 --- a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -16,7 +16,7 @@ extern crate rustc_span; #[allow(unused_extern_crates)] extern crate rustc_driver; -use rustc_parse::new_parser_from_file; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use std::path::Path; @@ -34,6 +34,6 @@ fn parse() { let path = Path::new(file!()); let path = path.canonicalize().unwrap(); - let mut parser = new_parser_from_file(&psess, &path, None); + let mut parser = unwrap_or_emit_fatal(new_parser_from_file(&psess, &path, None)); let _ = parser.parse_crate_mod(); } diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index 2b1fec9438717..762ad0b79ecc2 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -36,7 +36,7 @@ use rustc_ast::mut_visit::{visit_clobber, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::*; use rustc_ast_pretty::pprust; -use rustc_parse::new_parser_from_source_str; +use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; @@ -46,8 +46,9 @@ use thin_vec::{thin_vec, ThinVec}; fn parse_expr(psess: &ParseSess, src: &str) -> Option> { let src_as_string = src.to_string(); - let mut p = - new_parser_from_source_str(psess, FileName::Custom(src_as_string.clone()), src_as_string); + let mut p = unwrap_or_emit_fatal( + new_parser_from_source_str(psess, FileName::Custom(src_as_string.clone()), src_as_string) + ); p.parse_expr().map_err(|e| e.cancel()).ok() } From 2d4e7df14422ec46422e79ddae5af3ed78632bef Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 3 Jun 2024 14:32:03 +1000 Subject: [PATCH 28/29] rustfmt: Remove an unnecessary `catch_unwind` use. The `Input::File` and `Input::Text` cases should be very similar. However, currently the `Input::File` case uses `catch_unwind` because, until recently (#125815) there was a fallible version of `new_parser_from_source_str` but only an infallible version of `new_parser_from_file`. This difference wasn't fundamental, just an overlooked gap in the API of `rustc_parse`. Both of those operations are now fallible, so the `Input::File` and `Input::Text` cases can made more similar, with no need for `catch_unwind`. This also lets us simplify an `Option>` to `Vec`. --- src/tools/rustfmt/src/parse/parser.rs | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index 7adf339b453ae..6051241309d19 100644 --- a/src/tools/rustfmt/src/parse/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -5,7 +5,7 @@ use rustc_ast::token::TokenKind; use rustc_ast::{ast, attr, ptr}; use rustc_errors::Diag; use rustc_parse::parser::Parser as RawParser; -use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; +use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_span::{sym, Span}; use thin_vec::ThinVec; @@ -51,12 +51,9 @@ impl<'a> ParserBuilder<'a> { let parser = match Self::parser(psess.inner(), input) { Ok(p) => p, - Err(db) => { - if let Some(diagnostics) = db { - psess.emit_diagnostics(diagnostics); - return Err(ParserError::ParserCreationError); - } - return Err(ParserError::ParsePanicError); + Err(diagnostics) => { + psess.emit_diagnostics(diagnostics); + return Err(ParserError::ParserCreationError); } }; @@ -66,18 +63,14 @@ impl<'a> ParserBuilder<'a> { fn parser( psess: &'a rustc_session::parse::ParseSess, input: Input, - ) -> Result, Option>>> { + ) -> Result, Vec>> { match input { - Input::File(ref file) => catch_unwind(AssertUnwindSafe(move || { - unwrap_or_emit_fatal(new_parser_from_file(psess, file, None)) - })) - .map_err(|_| None), - Input::Text(text) => rustc_parse::new_parser_from_source_str( + Input::File(ref file) => new_parser_from_file(psess, file, None), + Input::Text(text) => new_parser_from_source_str( psess, rustc_span::FileName::Custom("stdin".to_owned()), text, - ) - .map_err(Some), + ), } } } From dd6bca56ecb354a80ba4c818c47f92e6a88d611a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 4 Jun 2024 21:06:29 -0400 Subject: [PATCH 29/29] Add another test for hidden types capturing lifetimes that outlive but arent mentioned in substs --- .../tait-hidden-erased-unsoundness-2.rs | 38 +++++++++++++++++++ .../tait-hidden-erased-unsoundness-2.stderr | 15 ++++++++ 2 files changed, 53 insertions(+) create mode 100644 tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.rs create mode 100644 tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.stderr diff --git a/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.rs b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.rs new file mode 100644 index 0000000000000..65e90c1ca53c0 --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.rs @@ -0,0 +1,38 @@ +// This test should never pass! + +#![feature(type_alias_impl_trait)] + +pub trait Captures<'a> {} +impl Captures<'_> for T {} + +pub struct MyTy<'a, 'b>(Option<*mut &'a &'b ()>); +unsafe impl Send for MyTy<'_, 'static> {} + +pub mod step1 { + use super::*; + pub type Step1<'a, 'b: 'a> = impl Sized + Captures<'b> + 'a; + pub fn step1<'a, 'b: 'a>() -> Step1<'a, 'b> { + MyTy::<'a, 'b>(None) + } +} + +pub mod step2 { + pub type Step2<'a> = impl Send + 'a; + + // Although `Step2` is WF at the definition site, it's not WF in its + // declaration site (above). We check this in `check_opaque_meets_bounds`, + // which must remain sound. + pub fn step2<'a, 'b: 'a>() -> Step2<'a> + where crate::step1::Step1<'a, 'b>: Send + { + crate::step1::step1::<'a, 'b>() + //~^ ERROR hidden type for `Step2<'a>` captures lifetime that does not appear in bounds + } +} + +fn step3<'a, 'b>() { + fn is_send() {} + is_send::>(); +} + +fn main() {} diff --git a/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.stderr b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.stderr new file mode 100644 index 0000000000000..58d7f9959d346 --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.stderr @@ -0,0 +1,15 @@ +error[E0700]: hidden type for `Step2<'a>` captures lifetime that does not appear in bounds + --> $DIR/tait-hidden-erased-unsoundness-2.rs:28:9 + | +LL | pub type Step2<'a> = impl Send + 'a; + | -------------- opaque type defined here +... +LL | pub fn step2<'a, 'b: 'a>() -> Step2<'a> + | -- hidden type `Step1<'a, 'b>` captures the lifetime `'b` as defined here +... +LL | crate::step1::step1::<'a, 'b>() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0700`.