From d6a17b598f0e82535fc38c8455aed9571f44aaa2 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 4 Mar 2020 14:21:38 +0900 Subject: [PATCH 01/36] Move tidy check to mingw-check --- src/ci/docker/mingw-check/Dockerfile | 1 + src/ci/docker/x86_64-gnu-llvm-7/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/mingw-check/Dockerfile b/src/ci/docker/mingw-check/Dockerfile index b2d96aed2a9e8..e973ba2e33c64 100644 --- a/src/ci/docker/mingw-check/Dockerfile +++ b/src/ci/docker/mingw-check/Dockerfile @@ -25,4 +25,5 @@ ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 ENV SCRIPT python2.7 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ python2.7 ../x.py build --stage 0 src/tools/build-manifest && \ python2.7 ../x.py test --stage 0 src/tools/compiletest && \ + python2.7 ../x.py test src/tools/tidy && \ /scripts/validate-toolstate.sh diff --git a/src/ci/docker/x86_64-gnu-llvm-7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-7/Dockerfile index dc90c286f5cd1..284c1e763e5c7 100644 --- a/src/ci/docker/x86_64-gnu-llvm-7/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-7/Dockerfile @@ -28,7 +28,7 @@ ENV RUST_CONFIGURE_ARGS \ --enable-llvm-link-shared \ --set rust.thin-lto-import-instr-limit=10 -ENV SCRIPT python2.7 ../x.py test src/tools/tidy && python2.7 ../x.py test +ENV SCRIPT python2.7 ../x.py test --exclude src/tools/tidy && python2.7 ../x.py test src/tools/tidy # The purpose of this container isn't to test with debug assertions and # this is run on all PRs, so let's get speedier builds by disabling these extra From 726d5185e00d37ad7bd24aac4f05bf9fd34765be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 5 Mar 2020 00:00:00 +0000 Subject: [PATCH 02/36] bootstrap: Use hash to determine if sanitizers needs to be rebuilt * Rebuild sanitizers runtimes when LLVM submodule commit changes. * When rebuilding LLVM / sanitizers, remove the stamp file before starting the build process to invalidate previous build output. --- src/bootstrap/native.rs | 98 ++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 31 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index c22c2a336f124..d4d66abd520a1 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -11,6 +11,7 @@ use std::env; use std::ffi::OsString; use std::fs::{self, File}; +use std::io; use std::path::{Path, PathBuf}; use std::process::Command; @@ -54,7 +55,6 @@ impl Step for Llvm { } } - let llvm_info = &builder.in_tree_llvm_info; let root = "src/llvm-project/llvm"; let out_dir = builder.llvm_out(target); let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build); @@ -65,40 +65,35 @@ impl Step for Llvm { let build_llvm_config = llvm_config_ret_dir.join(exe("llvm-config", &*builder.config.build)); - let done_stamp = out_dir.join("llvm-finished-building"); - if done_stamp.exists() { - if builder.config.llvm_skip_rebuild { - builder.info( - "Warning: \ - Using a potentially stale build of LLVM; \ - This may not behave well.", - ); - return build_llvm_config; - } + let stamp = out_dir.join("llvm-finished-building"); + let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha()); - if let Some(llvm_commit) = llvm_info.sha() { - let done_contents = t!(fs::read(&done_stamp)); + if builder.config.llvm_skip_rebuild && stamp.path.exists() { + builder.info( + "Warning: \ + Using a potentially stale build of LLVM; \ + This may not behave well.", + ); + return build_llvm_config; + } - // If LLVM was already built previously and the submodule's commit didn't change - // from the previous build, then no action is required. - if done_contents == llvm_commit.as_bytes() { - return build_llvm_config; - } - } else { + if stamp.is_done() { + if stamp.hash.is_none() { builder.info( "Could not determine the LLVM submodule commit hash. \ Assuming that an LLVM rebuild is not necessary.", ); builder.info(&format!( "To force LLVM to rebuild, remove the file `{}`", - done_stamp.display() + stamp.path.display() )); - return build_llvm_config; } + return build_llvm_config; } builder.info(&format!("Building LLVM for {}", target)); + t!(stamp.remove()); let _time = util::timeit(&builder); t!(fs::create_dir_all(&out_dir)); @@ -271,7 +266,7 @@ impl Step for Llvm { cfg.build(); - t!(fs::write(&done_stamp, llvm_info.sha().unwrap_or(""))); + t!(stamp.write()); build_llvm_config } @@ -584,17 +579,21 @@ impl Step for Sanitizers { return runtimes; } - let done_stamp = out_dir.join("sanitizers-finished-building"); - if done_stamp.exists() { - builder.info(&format!( - "Assuming that sanitizers rebuild is not necessary. \ - To force a rebuild, remove the file `{}`", - done_stamp.display() - )); + let stamp = out_dir.join("sanitizers-finished-building"); + let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha()); + + if stamp.is_done() { + if stamp.hash.is_none() { + builder.info(&format!( + "Rebuild sanitizers by removing the file `{}`", + stamp.path.display() + )); + } return runtimes; } builder.info(&format!("Building sanitizers for {}", self.target)); + t!(stamp.remove()); let _time = util::timeit(&builder); let mut cfg = cmake::Config::new(&compiler_rt_dir); @@ -623,8 +622,7 @@ impl Step for Sanitizers { cfg.build_target(&runtime.cmake_target); cfg.build(); } - - t!(fs::write(&done_stamp, b"")); + t!(stamp.write()); runtimes } @@ -689,3 +687,41 @@ fn supported_sanitizers( } result } + +struct HashStamp { + path: PathBuf, + hash: Option>, +} + +impl HashStamp { + fn new(path: PathBuf, hash: Option<&str>) -> Self { + HashStamp { path, hash: hash.map(|s| s.as_bytes().to_owned()) } + } + + fn is_done(&self) -> bool { + match fs::read(&self.path) { + Ok(h) => self.hash.as_deref().unwrap_or(b"") == h.as_slice(), + Err(e) if e.kind() == io::ErrorKind::NotFound => false, + Err(e) => { + panic!("failed to read stamp file `{}`: {}", self.path.display(), e); + } + } + } + + fn remove(&self) -> io::Result<()> { + match fs::remove_file(&self.path) { + Ok(()) => Ok(()), + Err(e) => { + if e.kind() == io::ErrorKind::NotFound { + Ok(()) + } else { + Err(e) + } + } + } + } + + fn write(&self) -> io::Result<()> { + fs::write(&self.path, self.hash.as_deref().unwrap_or(b"")) + } +} From d49306da136c1c433a95babc82cc278cbf192238 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Mar 2020 14:23:13 +0100 Subject: [PATCH 03/36] implement zeroed and uninitialized with MaybeUninit --- src/libcore/intrinsics.rs | 40 +------------------- src/libcore/mem/mod.rs | 4 +- src/librustc_codegen_llvm/intrinsic.rs | 22 +---------- src/librustc_typeck/check/intrinsic.rs | 2 - src/test/ui/init-large-type.rs | 8 +--- src/test/ui/init-unsafe.rs | 9 ----- src/test/ui/init-unsafe.stderr | 11 ------ src/test/ui/intrinsics/intrinsic-move-val.rs | 15 ++++---- src/test/ui/intrinsics/intrinsic-uninit.rs | 13 ------- 9 files changed, 14 insertions(+), 110 deletions(-) delete mode 100644 src/test/ui/init-unsafe.rs delete mode 100644 src/test/ui/init-unsafe.stderr delete mode 100644 src/test/ui/intrinsics/intrinsic-uninit.rs diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 3c060cc6e840b..265ed48809527 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1021,46 +1021,8 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] pub fn caller_location() -> &'static crate::panic::Location<'static>; - /// Creates a value initialized to zero. - /// - /// `init` is unsafe because it returns a zeroed-out datum, - /// which is unsafe unless `T` is `Copy`. Also, even if T is - /// `Copy`, an all-zero value may not correspond to any legitimate - /// state for the type in question. - /// - /// The stabilized version of this intrinsic is - /// [`std::mem::zeroed`](../../std/mem/fn.zeroed.html). - #[unstable( - feature = "core_intrinsics", - reason = "intrinsics are unlikely to ever be stabilized, instead \ - they should be used through stabilized interfaces \ - in the rest of the standard library", - issue = "none" - )] - #[rustc_deprecated(reason = "superseded by MaybeUninit, removal planned", since = "1.38.0")] - pub fn init() -> T; - - /// Creates an uninitialized value. - /// - /// `uninit` is unsafe because there is no guarantee of what its - /// contents are. In particular its drop-flag may be set to any - /// state, which means it may claim either dropped or - /// undropped. In the general case one must use `ptr::write` to - /// initialize memory previous set to the result of `uninit`. - /// - /// The stabilized version of this intrinsic is - /// [`std::mem::MaybeUninit`](../../std/mem/union.MaybeUninit.html). - #[unstable( - feature = "core_intrinsics", - reason = "intrinsics are unlikely to ever be stabilized, instead \ - they should be used through stabilized interfaces \ - in the rest of the standard library", - issue = "none" - )] - #[rustc_deprecated(reason = "superseded by MaybeUninit, removal planned", since = "1.38.0")] - pub fn uninit() -> T; - /// Moves a value out of scope without running drop glue. + /// This exists solely for `mem::forget_unsized`; normal `forget` uses `ManuallyDrop` instead. pub fn forget(_: T); /// Reinterprets the bits of a value of one type as another type. diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 7d9a8bcd05b1c..9f7868005225e 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -500,7 +500,7 @@ pub unsafe fn zeroed() -> T { intrinsics::panic_if_zero_invalid::(); #[cfg(bootstrap)] intrinsics::panic_if_uninhabited::(); - intrinsics::init() + MaybeUninit::zeroed().assume_init() } /// Bypasses Rust's normal memory-initialization checks by pretending to @@ -536,7 +536,7 @@ pub unsafe fn uninitialized() -> T { intrinsics::panic_if_any_invalid::(); #[cfg(bootstrap)] intrinsics::panic_if_uninhabited::(); - intrinsics::uninit() + MaybeUninit::uninit().assume_init() } /// Swaps the values at two mutable locations, without deinitializing either one. diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 1ae9d2a684131..aa42d557b0261 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -195,26 +195,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { .unwrap(); OperandRef::from_const(self, ty_name, ret_ty).immediate_or_packed_pair(self) } - "init" => { - let ty = substs.type_at(0); - if !self.layout_of(ty).is_zst() { - // Just zero out the stack slot. - // If we store a zero constant, LLVM will drown in vreg allocation for large - // data structures, and the generated code will be awful. (A telltale sign of - // this is large quantities of `mov [byte ptr foo],0` in the generated code.) - memset_intrinsic( - self, - false, - ty, - llresult, - self.const_u8(0), - self.const_usize(1), - ); - } - return; - } - // Effectively no-ops - "uninit" | "forget" => { + // Effectively no-op + "forget" => { return; } "offset" => { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index d2a358c3e09b8..36b7ef87b5ef4 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -150,8 +150,6 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { "panic_if_uninhabited" | "panic_if_zero_invalid" | "panic_if_any_invalid" => { (1, Vec::new(), tcx.mk_unit()) } - "init" => (1, Vec::new(), param(0)), - "uninit" => (1, Vec::new(), param(0)), "forget" => (1, vec![param(0)], tcx.mk_unit()), "transmute" => (2, vec![param(0)], param(1)), "move_val_init" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), diff --git a/src/test/ui/init-large-type.rs b/src/test/ui/init-large-type.rs index a304fc9356b51..7a3ffbb6ad7bf 100644 --- a/src/test/ui/init-large-type.rs +++ b/src/test/ui/init-large-type.rs @@ -10,17 +10,13 @@ #![feature(intrinsics)] -use std::thread; - -extern "rust-intrinsic" { - pub fn init() -> T; -} +use std::{mem, thread}; const SIZE: usize = 1024 * 1024; fn main() { // do the test in a new thread to avoid (spurious?) stack overflows thread::spawn(|| { - let _memory: [u8; SIZE] = unsafe { init() }; + let _memory: [u8; SIZE] = unsafe { mem::zeroed() }; }).join(); } diff --git a/src/test/ui/init-unsafe.rs b/src/test/ui/init-unsafe.rs deleted file mode 100644 index 3d65cfc234092..0000000000000 --- a/src/test/ui/init-unsafe.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![allow(deprecated)] -#![feature(core_intrinsics)] - -use std::intrinsics::{init}; - -// Test that the `init` intrinsic is really unsafe -pub fn main() { - let stuff = init::(); //~ ERROR call to unsafe function is unsafe -} diff --git a/src/test/ui/init-unsafe.stderr b/src/test/ui/init-unsafe.stderr deleted file mode 100644 index e1126316af34e..0000000000000 --- a/src/test/ui/init-unsafe.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/init-unsafe.rs:8:17 - | -LL | let stuff = init::(); - | ^^^^^^^^^^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/intrinsics/intrinsic-move-val.rs b/src/test/ui/intrinsics/intrinsic-move-val.rs index 75b4ec365fe03..b672f1ed26e8d 100644 --- a/src/test/ui/intrinsics/intrinsic-move-val.rs +++ b/src/test/ui/intrinsics/intrinsic-move-val.rs @@ -5,7 +5,6 @@ mod rusti { extern "rust-intrinsic" { - pub fn init() -> T; pub fn move_val_init(dst: *mut T, src: T); } } @@ -15,17 +14,17 @@ pub fn main() { // sanity check check_drops_state(0, None); - let mut x: Box = box D(1); - assert_eq!(x.0, 1); + let mut x: Option> = Some(box D(1)); + assert_eq!(x.as_ref().unwrap().0, 1); // A normal overwrite, to demonstrate `check_drops_state`. - x = box D(2); + x = Some(box D(2)); // At this point, one destructor has run, because the // overwrite of `x` drops its initial value. check_drops_state(1, Some(1)); - let mut y: Box = rusti::init(); + let mut y: Option> = std::mem::zeroed(); // An initial binding does not overwrite anything. check_drops_state(1, Some(1)); @@ -51,9 +50,9 @@ pub fn main() { // during such a destructor call. We do so after the end of // this scope. - assert_eq!(y.0, 2); - y.0 = 3; - assert_eq!(y.0, 3); + assert_eq!(y.as_ref().unwrap().0, 2); + y.as_mut().unwrap().0 = 3; + assert_eq!(y.as_ref().unwrap().0, 3); check_drops_state(1, Some(1)); } diff --git a/src/test/ui/intrinsics/intrinsic-uninit.rs b/src/test/ui/intrinsics/intrinsic-uninit.rs deleted file mode 100644 index 9555efb639b50..0000000000000 --- a/src/test/ui/intrinsics/intrinsic-uninit.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass -// pretty-expanded FIXME #23616 - -#![feature(intrinsics)] - -mod rusti { - extern "rust-intrinsic" { - pub fn uninit() -> T; - } -} -pub fn main() { - let _a : isize = unsafe {rusti::uninit()}; -} From c7eb0f2a40c25b6cec131b28a3638a6c27dbb5e8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Mar 2020 19:41:41 +0100 Subject: [PATCH 04/36] fix expand-to-unstable test --- src/test/ui/proc-macro/auxiliary/derive-unstable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/proc-macro/auxiliary/derive-unstable.rs b/src/test/ui/proc-macro/auxiliary/derive-unstable.rs index f702df66db1b8..2ccd3f88200e3 100644 --- a/src/test/ui/proc-macro/auxiliary/derive-unstable.rs +++ b/src/test/ui/proc-macro/auxiliary/derive-unstable.rs @@ -10,5 +10,5 @@ use proc_macro::TokenStream; #[proc_macro_derive(Unstable)] pub fn derive(_input: TokenStream) -> TokenStream { - "unsafe fn foo() -> u32 { ::std::intrinsics::init() }".parse().unwrap() + "unsafe fn foo() -> u32 { ::std::intrinsics::abort() }".parse().unwrap() } From f4eb6ed6b407bcbbd7311a2983ff661b2cd15393 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 11 Mar 2020 20:34:57 +0000 Subject: [PATCH 05/36] Ensure HAS_FREE_LOCAL_NAMES is set for ReFree --- src/librustc/ty/mod.rs | 27 +++++++++++++++------------ src/librustc/ty/sty.rs | 28 ++++++++++++++-------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7bcd63b965534..7df235b3cc1d4 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -554,24 +554,26 @@ bitflags! { /// Does this have [ConstKind::Placeholder]? const HAS_CT_PLACEHOLDER = 1 << 8; + /// `true` if there are "names" of regions and so forth + /// that are local to a particular fn/inferctxt + const HAS_FREE_LOCAL_REGIONS = 1 << 9; + /// `true` if there are "names" of types and regions and so forth /// that are local to a particular fn const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_RE_PARAM.bits | TypeFlags::HAS_CT_PARAM.bits | TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_RE_INFER.bits | TypeFlags::HAS_CT_INFER.bits | TypeFlags::HAS_TY_PLACEHOLDER.bits - | TypeFlags::HAS_RE_PLACEHOLDER.bits - | TypeFlags::HAS_CT_PLACEHOLDER.bits; + | TypeFlags::HAS_CT_PLACEHOLDER.bits + | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; /// Does this have [Projection] or [UnnormalizedProjection]? - const HAS_TY_PROJECTION = 1 << 9; + const HAS_TY_PROJECTION = 1 << 10; /// Does this have [Opaque]? - const HAS_TY_OPAQUE = 1 << 10; + const HAS_TY_OPAQUE = 1 << 11; /// Does this have [ConstKind::Unevaluated]? - const HAS_CT_PROJECTION = 1 << 11; + const HAS_CT_PROJECTION = 1 << 12; /// Could this type be normalized further? const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits @@ -580,21 +582,21 @@ bitflags! { /// Present if the type belongs in a local type context. /// Set for placeholders and inference variables that are not "Fresh". - const KEEP_IN_LOCAL_TCX = 1 << 12; + const KEEP_IN_LOCAL_TCX = 1 << 13; /// Is an error type reachable? - const HAS_TY_ERR = 1 << 13; + const HAS_TY_ERR = 1 << 14; /// Does this have any region that "appears free" in the type? /// Basically anything but [ReLateBound] and [ReErased]. - const HAS_FREE_REGIONS = 1 << 14; + const HAS_FREE_REGIONS = 1 << 15; /// Does this have any [ReLateBound] regions? Used to check /// if a global bound is safe to evaluate. - const HAS_RE_LATE_BOUND = 1 << 15; + const HAS_RE_LATE_BOUND = 1 << 16; /// Does this have any [ReErased] regions? - const HAS_RE_ERASED = 1 << 16; + const HAS_RE_ERASED = 1 << 17; /// Flags representing the nominal content of a type, /// computed by FlagsComputation. If you add a new nominal @@ -608,6 +610,7 @@ bitflags! { | TypeFlags::HAS_TY_PLACEHOLDER.bits | TypeFlags::HAS_RE_PLACEHOLDER.bits | TypeFlags::HAS_CT_PLACEHOLDER.bits + | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits | TypeFlags::HAS_TY_PROJECTION.bits | TypeFlags::HAS_TY_OPAQUE.bits | TypeFlags::HAS_CT_PROJECTION.bits diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 47bf7822b1f55..649381db7cace 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1743,42 +1743,42 @@ impl RegionKind { } } - pub fn keep_in_local_tcx(&self) -> bool { - if let ty::ReVar(..) = self { true } else { false } - } - pub fn type_flags(&self) -> TypeFlags { let mut flags = TypeFlags::empty(); - if self.keep_in_local_tcx() { - flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX; - } - match *self { ty::ReVar(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_INFER; + flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX; } ty::RePlaceholder(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; } - ty::ReLateBound(..) => { - flags = flags | TypeFlags::HAS_RE_LATE_BOUND; - } ty::ReEarlyBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PARAM; } - ty::ReEmpty(_) | ty::ReStatic | ty::ReFree { .. } | ty::ReScope { .. } => { + ty::ReFree { .. } | ty::ReScope { .. } => { flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; } - ty::ReErased => { - flags = flags | TypeFlags::HAS_RE_ERASED; + ty::ReEmpty(_) | ty::ReStatic => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; } ty::ReClosureBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } + ty::ReLateBound(..) => { + flags = flags | TypeFlags::HAS_RE_LATE_BOUND; + } + ty::ReErased => { + flags = flags | TypeFlags::HAS_RE_ERASED; + } } debug!("type_flags({:?}) = {:?}", self, flags); From 996a51bcd04e097254b5072270e10b1280ff1b28 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Mar 2020 14:38:33 +0100 Subject: [PATCH 06/36] init-large-type test needs optimizations --- src/test/ui/init-large-type.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/init-large-type.rs b/src/test/ui/init-large-type.rs index 7a3ffbb6ad7bf..ce905572f2a8c 100644 --- a/src/test/ui/init-large-type.rs +++ b/src/test/ui/init-large-type.rs @@ -1,3 +1,4 @@ +// compile-flags: -O // run-pass #![allow(unused_must_use)] From a2160e6a4a91490117b9f0469c49b6f86d0d20d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Mar 2020 17:37:26 +0100 Subject: [PATCH 07/36] make mem::{zeroed,uninitialized} inline(always) --- src/libcore/mem/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 9f7868005225e..ae4c0a98ea930 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -490,7 +490,7 @@ pub const fn needs_drop() -> bool { /// /// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior! /// ``` -#[inline] +#[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated_in_future)] #[allow(deprecated)] @@ -525,7 +525,7 @@ pub unsafe fn zeroed() -> T { /// [uninit]: union.MaybeUninit.html#method.uninit /// [assume_init]: union.MaybeUninit.html#method.assume_init /// [inv]: union.MaybeUninit.html#initialization-invariant -#[inline] +#[inline(always)] #[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated_in_future)] From ec862703fde44d23f7da8bc5fdd94a63354d5daf Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 11 Mar 2020 20:05:19 +0000 Subject: [PATCH 08/36] Make macro metavars respect (non-)hygiene --- src/librustc_expand/mbe/macro_check.rs | 13 +++++---- src/librustc_expand/mbe/macro_parser.rs | 17 ++++++----- src/librustc_expand/mbe/macro_rules.rs | 6 ++-- src/librustc_expand/mbe/transcribe.rs | 21 ++++++++------ src/librustc_span/symbol.rs | 25 ++++++++++++++++ src/test/ui/hygiene/macro-metavars-legacy.rs | 29 +++++++++++++++++++ .../ui/hygiene/macro-metavars-transparent.rs | 24 +++++++++++++++ 7 files changed, 111 insertions(+), 24 deletions(-) create mode 100644 src/test/ui/hygiene/macro-metavars-legacy.rs create mode 100644 src/test/ui/hygiene/macro-metavars-transparent.rs diff --git a/src/librustc_expand/mbe/macro_check.rs b/src/librustc_expand/mbe/macro_check.rs index 8c6bfbec90277..582c26162ed6d 100644 --- a/src/librustc_expand/mbe/macro_check.rs +++ b/src/librustc_expand/mbe/macro_check.rs @@ -112,7 +112,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_session::lint::builtin::META_VARIABLE_MISUSE; use rustc_session::parse::ParseSess; use rustc_span::symbol::kw; -use rustc_span::{symbol::Ident, MultiSpan, Span}; +use rustc_span::{symbol::MacroRulesNormalizedIdent, MultiSpan, Span}; use smallvec::SmallVec; @@ -179,7 +179,7 @@ struct BinderInfo { } /// An environment of meta-variables to their binder information. -type Binders = FxHashMap; +type Binders = FxHashMap; /// The state at which we entered a macro definition in the RHS of another macro definition. struct MacroState<'a> { @@ -245,6 +245,7 @@ fn check_binders( if macros.is_empty() { sess.span_diagnostic.span_bug(span, "unexpected MetaVar in lhs"); } + let name = MacroRulesNormalizedIdent::new(name); // There are 3 possibilities: if let Some(prev_info) = binders.get(&name) { // 1. The meta-variable is already bound in the current LHS: This is an error. @@ -264,6 +265,7 @@ fn check_binders( if !macros.is_empty() { sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in nested lhs"); } + let name = MacroRulesNormalizedIdent::new(name); if let Some(prev_info) = get_binder_info(macros, binders, name) { // Duplicate binders at the top-level macro definition are errors. The lint is only // for nested macro definitions. @@ -300,7 +302,7 @@ fn check_binders( fn get_binder_info<'a>( mut macros: &'a Stack<'a, MacroState<'a>>, binders: &'a Binders, - name: Ident, + name: MacroRulesNormalizedIdent, ) -> Option<&'a BinderInfo> { binders.get(&name).or_else(|| macros.find_map(|state| state.binders.get(&name))) } @@ -331,6 +333,7 @@ fn check_occurrences( sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in rhs") } TokenTree::MetaVar(span, name) => { + let name = MacroRulesNormalizedIdent::new(name); check_ops_is_prefix(sess, node_id, macros, binders, ops, span, name); } TokenTree::Delimited(_, ref del) => { @@ -552,7 +555,7 @@ fn check_ops_is_prefix( binders: &Binders, ops: &Stack<'_, KleeneToken>, span: Span, - name: Ident, + name: MacroRulesNormalizedIdent, ) { let macros = macros.push(MacroState { binders, ops: ops.into() }); // Accumulates the stacks the operators of each state until (and including when) the @@ -598,7 +601,7 @@ fn ops_is_prefix( sess: &ParseSess, node_id: NodeId, span: Span, - name: Ident, + name: MacroRulesNormalizedIdent, binder_ops: &[KleeneToken], occurrence_ops: &[KleeneToken], ) { diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index 6d4d7f5b4f394..3b9158f444519 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -76,13 +76,13 @@ use TokenTreeOrTokenTreeSlice::*; use crate::mbe::{self, TokenTree}; -use rustc_ast::ast::{Ident, Name}; +use rustc_ast::ast::Name; use rustc_ast::ptr::P; use rustc_ast::token::{self, DocComment, Nonterminal, Token}; use rustc_ast_pretty::pprust; use rustc_parse::parser::{FollowedByType, Parser, PathStyle}; use rustc_session::parse::ParseSess; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent, Symbol}; use rustc_errors::{FatalError, PResult}; use rustc_span::Span; @@ -273,9 +273,10 @@ crate enum ParseResult { Error(rustc_span::Span, String), } -/// A `ParseResult` where the `Success` variant contains a mapping of `Ident`s to `NamedMatch`es. -/// This represents the mapping of metavars to the token trees they bind to. -crate type NamedParseResult = ParseResult>; +/// A `ParseResult` where the `Success` variant contains a mapping of +/// `MacroRulesNormalizedIdent`s to `NamedMatch`es. This represents the mapping +/// of metavars to the token trees they bind to. +crate type NamedParseResult = ParseResult>; /// Count how many metavars are named in the given matcher `ms`. pub(super) fn count_names(ms: &[TokenTree]) -> usize { @@ -368,7 +369,7 @@ fn nameize>( sess: &ParseSess, m: &TokenTree, res: &mut I, - ret_val: &mut FxHashMap, + ret_val: &mut FxHashMap, ) -> Result<(), (rustc_span::Span, String)> { match *m { TokenTree::Sequence(_, ref seq) => { @@ -386,7 +387,9 @@ fn nameize>( return Err((span, "missing fragment specifier".to_string())); } } - TokenTree::MetaVarDecl(sp, bind_name, _) => match ret_val.entry(bind_name) { + TokenTree::MetaVarDecl(sp, bind_name, _) => match ret_val + .entry(MacroRulesNormalizedIdent::new(bind_name)) + { Vacant(spot) => { spot.insert(res.next().unwrap()); } diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 3cad3ff55d910..2268c9b385477 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -22,7 +22,7 @@ use rustc_parse::Directory; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{kw, sym, MacroRulesNormalizedIdent, Symbol}; use rustc_span::Span; use log::debug; @@ -411,7 +411,7 @@ pub fn compile_declarative_macro( let mut valid = true; // Extract the arguments: - let lhses = match argument_map[&lhs_nm] { + let lhses = match argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] { MatchedSeq(ref s) => s .iter() .map(|m| { @@ -428,7 +428,7 @@ pub fn compile_declarative_macro( _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"), }; - let rhses = match argument_map[&rhs_nm] { + let rhses = match argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] { MatchedSeq(ref s) => s .iter() .map(|m| { diff --git a/src/librustc_expand/mbe/transcribe.rs b/src/librustc_expand/mbe/transcribe.rs index 7a64d40785e09..1b1093c9529f4 100644 --- a/src/librustc_expand/mbe/transcribe.rs +++ b/src/librustc_expand/mbe/transcribe.rs @@ -2,7 +2,7 @@ use crate::base::ExtCtxt; use crate::mbe; use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; -use rustc_ast::ast::{Ident, MacCall}; +use rustc_ast::ast::MacCall; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{self, NtTT, Token}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; @@ -10,6 +10,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::pluralize; use rustc_span::hygiene::{ExpnId, Transparency}; +use rustc_span::symbol::MacroRulesNormalizedIdent; use rustc_span::Span; use smallvec::{smallvec, SmallVec}; @@ -81,7 +82,7 @@ impl Iterator for Frame { /// Along the way, we do some additional error checking. pub(super) fn transcribe( cx: &ExtCtxt<'_>, - interp: &FxHashMap, + interp: &FxHashMap, src: Vec, transparency: Transparency, ) -> TokenStream { @@ -223,9 +224,10 @@ pub(super) fn transcribe( } // Replace the meta-var with the matched token tree from the invocation. - mbe::TokenTree::MetaVar(mut sp, mut ident) => { + mbe::TokenTree::MetaVar(mut sp, mut orignal_ident) => { // Find the matched nonterminal from the macro invocation, and use it to replace // the meta-var. + let ident = MacroRulesNormalizedIdent::new(orignal_ident); if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { if let MatchedNonterminal(ref nt) = cur_matched { // FIXME #2887: why do we apply a mark when matching a token tree meta-var @@ -249,9 +251,9 @@ pub(super) fn transcribe( // If we aren't able to match the meta-var, we push it back into the result but // with modified syntax context. (I believe this supports nested macros). marker.visit_span(&mut sp); - marker.visit_ident(&mut ident); + marker.visit_ident(&mut orignal_ident); result.push(TokenTree::token(token::Dollar, sp).into()); - result.push(TokenTree::Token(Token::from_ast_ident(ident)).into()); + result.push(TokenTree::Token(Token::from_ast_ident(orignal_ident)).into()); } } @@ -287,8 +289,8 @@ pub(super) fn transcribe( /// into the right place in nested matchers. If we attempt to descend too far, the macro writer has /// made a mistake, and we return `None`. fn lookup_cur_matched<'a>( - ident: Ident, - interpolations: &'a FxHashMap, + ident: MacroRulesNormalizedIdent, + interpolations: &'a FxHashMap, repeats: &[(usize, usize)], ) -> Option<&'a NamedMatch> { interpolations.get(&ident).map(|matched| { @@ -316,7 +318,7 @@ enum LockstepIterSize { /// A `MetaVar` with an actual `MatchedSeq`. The length of the match and the name of the /// meta-var are returned. - Constraint(usize, Ident), + Constraint(usize, MacroRulesNormalizedIdent), /// Two `Constraint`s on the same sequence had different lengths. This is an error. Contradiction(String), @@ -360,7 +362,7 @@ impl LockstepIterSize { /// multiple nested matcher sequences. fn lockstep_iter_size( tree: &mbe::TokenTree, - interpolations: &FxHashMap, + interpolations: &FxHashMap, repeats: &[(usize, usize)], ) -> LockstepIterSize { use mbe::TokenTree; @@ -376,6 +378,7 @@ fn lockstep_iter_size( }) } TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => { + let name = MacroRulesNormalizedIdent::new(name); match lookup_cur_matched(name, interpolations, repeats) { Some(matched) => match matched { MatchedNonterminal(_) => LockstepIterSize::Unconstrained, diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 5760e1d004e03..7dfd6c58046fb 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -979,6 +979,31 @@ impl fmt::Display for IdentPrinter { } } +/// An newtype around `Ident` that calls [Ident::normalize_to_macro_rules] on +/// construction. +// FIXME(matthewj, petrochenkov) Use this more often, add a similar +// `ModernIdent` struct and use that as well. +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct MacroRulesNormalizedIdent(Ident); + +impl MacroRulesNormalizedIdent { + pub fn new(ident: Ident) -> Self { + Self(ident.normalize_to_macro_rules()) + } +} + +impl fmt::Debug for MacroRulesNormalizedIdent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl fmt::Display for MacroRulesNormalizedIdent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + /// An interned string. /// /// Internally, a `Symbol` is implemented as an index, and all operations diff --git a/src/test/ui/hygiene/macro-metavars-legacy.rs b/src/test/ui/hygiene/macro-metavars-legacy.rs new file mode 100644 index 0000000000000..09070f0f561a6 --- /dev/null +++ b/src/test/ui/hygiene/macro-metavars-legacy.rs @@ -0,0 +1,29 @@ +// Ensure macro metavariables are compared with legacy hygiene + +#![feature(rustc_attrs)] + +// run-pass + +macro_rules! make_mac { + ( $($dollar:tt $arg:ident),+ ) => { + macro_rules! mac { + ( $($dollar $arg : ident),+ ) => { + $( $dollar $arg )-+ + } + } + } +} + +macro_rules! show_hygiene { + ( $dollar:tt $arg:ident ) => { + make_mac!($dollar $arg, $dollar arg); + } +} + +show_hygiene!( $arg ); + +fn main() { + let x = 5; + let y = 3; + assert_eq!(2, mac!(x, y)); +} diff --git a/src/test/ui/hygiene/macro-metavars-transparent.rs b/src/test/ui/hygiene/macro-metavars-transparent.rs new file mode 100644 index 0000000000000..e475b5728a098 --- /dev/null +++ b/src/test/ui/hygiene/macro-metavars-transparent.rs @@ -0,0 +1,24 @@ +// Ensure macro metavariables are not compared without removing transparent +// marks. + +#![feature(rustc_attrs)] + +// run-pass + +#[rustc_macro_transparency = "transparent"] +macro_rules! k { + ($($s:tt)*) => { + macro_rules! m { + ($y:tt) => { + $($s)* + } + } + } +} + +k!(1 + $y); + +fn main() { + let x = 2; + assert_eq!(3, m!(x)); +} From a4125a621991029d9bc45825343ad102bd6ea304 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 18:59:44 +0100 Subject: [PATCH 09/36] submod_path_from_attr: simplify & document --- src/librustc_parse/parser/module.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 7b46601cc7d80..4965615c64cfb 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -179,21 +179,22 @@ impl<'a> Parser<'a> { } } + /// Derive a submodule path from the first found `#[path = "path_string"]`. + /// The provided `dir_path` is joined with the `path_string`. // Public for rustfmt usage. pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option { - if let Some(s) = attr::first_attr_value_str_by_name(attrs, sym::path) { - let s = s.as_str(); + // Extract path string from first `#[path = "path_string"]` attribute. + let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?; + let path_string = path_string.as_str(); - // On windows, the base path might have the form - // `\\?\foo\bar` in which case it does not tolerate - // mixed `/` and `\` separators, so canonicalize - // `/` to `\`. - #[cfg(windows)] - let s = s.replace("/", "\\"); - Some(dir_path.join(&*s)) - } else { - None - } + // On windows, the base path might have the form + // `\\?\foo\bar` in which case it does not tolerate + // mixed `/` and `\` separators, so canonicalize + // `/` to `\`. + #[cfg(windows)] + let path_string = path_string.replace("/", "\\"); + + Some(dir_path.join(&*path_string)) } /// Returns a path to a module. From 48b9526d4e8302c9768e774036aa68f01194454e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 19:11:47 +0100 Subject: [PATCH 10/36] extract error_cannot_declare_mod_here --- src/librustc_parse/parser/module.rs | 54 ++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 4965615c64cfb..43d93e3957583 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -142,41 +142,41 @@ impl<'a> Parser<'a> { } Err(err) } - DirectoryOwnership::UnownedViaMod => { - let mut err = - self.struct_span_err(id_sp, "cannot declare a new module at this location"); - if !id_sp.is_dummy() { - let src_path = self.sess.source_map().span_to_filename(id_sp); - if let FileName::Real(src_path) = src_path { - if let Some(stem) = src_path.file_stem() { - let mut dest_path = src_path.clone(); - dest_path.set_file_name(stem); - dest_path.push("mod.rs"); - err.span_note( - id_sp, - &format!( - "maybe move this module `{}` to its own \ - directory via `{}`", - src_path.display(), - dest_path.display() - ), - ); - } - } - } - if paths.path_exists { + DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id_sp, paths), + } + } + + fn error_cannot_declare_mod_here(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> { + let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location"); + if !id_sp.is_dummy() { + if let FileName::Real(src_path) = self.sess.source_map().span_to_filename(id_sp) { + if let Some(stem) = src_path.file_stem() { + let mut dest_path = src_path.clone(); + dest_path.set_file_name(stem); + dest_path.push("mod.rs"); err.span_note( id_sp, &format!( - "... or maybe `use` the module `{}` instead \ - of possibly redeclaring it", - paths.name + "maybe move this module `{}` to its own \ + directory via `{}`", + src_path.display(), + dest_path.display() ), ); } - Err(err) } } + if paths.path_exists { + err.span_note( + id_sp, + &format!( + "... or maybe `use` the module `{}` instead \ + of possibly redeclaring it", + paths.name + ), + ); + } + Err(err) } /// Derive a submodule path from the first found `#[path = "path_string"]`. From bbd2129e60582336c3068cf403bad0ab35a691a6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 19:15:35 +0100 Subject: [PATCH 11/36] extract error_decl_mod_in_block --- src/librustc_parse/parser/module.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 43d93e3957583..c7d120e3cc6c6 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -129,23 +129,22 @@ impl<'a> Parser<'a> { DirectoryOwnership::Owned { .. } => { paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) } - DirectoryOwnership::UnownedViaBlock => { - let msg = "Cannot declare a non-inline module inside a block \ - unless it has a path attribute"; - let mut err = self.struct_span_err(id_sp, msg); - if paths.path_exists { - let msg = format!( - "Maybe `use` the module `{}` instead of redeclaring it", - paths.name - ); - err.span_note(id_sp, &msg); - } - Err(err) - } + DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id_sp, paths), DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id_sp, paths), } } + fn error_decl_mod_in_block(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> { + let msg = + "Cannot declare a non-inline module inside a block unless it has a path attribute"; + let mut err = self.struct_span_err(id_sp, msg); + if paths.path_exists { + let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", paths.name); + err.span_note(id_sp, &msg); + } + Err(err) + } + fn error_cannot_declare_mod_here(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> { let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location"); if !id_sp.is_dummy() { From 7042554d85ee1950951bd1319ab40ca65ca950c3 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 19:20:31 +0100 Subject: [PATCH 12/36] simplify submod_path --- src/librustc_parse/parser/module.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index c7d120e3cc6c6..c426b073a0517 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -102,20 +102,18 @@ impl<'a> Parser<'a> { id_sp: Span, ) -> PResult<'a, ModulePathSuccess> { if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) { - return Ok(ModulePathSuccess { - directory_ownership: match path.file_name().and_then(|s| s.to_str()) { - // All `#[path]` files are treated as though they are a `mod.rs` file. - // This means that `mod foo;` declarations inside `#[path]`-included - // files are siblings, - // - // Note that this will produce weirdness when a file named `foo.rs` is - // `#[path]` included and contains a `mod foo;` declaration. - // If you encounter this, it's your own darn fault :P - Some(_) => DirectoryOwnership::Owned { relative: None }, - _ => DirectoryOwnership::UnownedViaMod, - }, - path, - }); + let directory_ownership = match path.file_name().and_then(|s| s.to_str()) { + // All `#[path]` files are treated as though they are a `mod.rs` file. + // This means that `mod foo;` declarations inside `#[path]`-included + // files are siblings, + // + // Note that this will produce weirdness when a file named `foo.rs` is + // `#[path]` included and contains a `mod foo;` declaration. + // If you encounter this, it's your own darn fault :P + Some(_) => DirectoryOwnership::Owned { relative: None }, + _ => DirectoryOwnership::UnownedViaMod, + }; + return Ok(ModulePathSuccess { directory_ownership, path }); } let relative = match self.directory.ownership { From 586c9b574e05cc6c2340aca98b39a8a951781b28 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 19:41:24 +0100 Subject: [PATCH 13/36] submod_path: use id.span --- src/librustc_parse/parser/module.rs | 12 +++++------- .../ui/directory_ownership/macro-expanded-mod.rs | 6 ++++-- .../ui/directory_ownership/macro-expanded-mod.stderr | 9 ++------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index c426b073a0517..4538799919644 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -45,14 +45,13 @@ impl<'a> Parser<'a> { pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs); - let id_span = self.token.span; let id = self.parse_ident()?; let (module, mut inner_attrs) = if self.eat(&token::Semi) { if in_cfg && self.recurse_into_file_modules { // This mod is in an external file. Let's go get it! let ModulePathSuccess { path, directory_ownership } = - self.submod_path(id, &attrs, id_span)?; - self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)? + self.submod_path(id, &attrs)?; + self.eval_src_mod(path, directory_ownership, id.to_string(), id.span)? } else { (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new()) } @@ -99,7 +98,6 @@ impl<'a> Parser<'a> { &mut self, id: ast::Ident, outer_attrs: &[Attribute], - id_sp: Span, ) -> PResult<'a, ModulePathSuccess> { if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) { let directory_ownership = match path.file_name().and_then(|s| s.to_str()) { @@ -125,10 +123,10 @@ impl<'a> Parser<'a> { match self.directory.ownership { DirectoryOwnership::Owned { .. } => { - paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) + paths.result.map_err(|err| self.span_fatal_err(id.span, err)) } - DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id_sp, paths), - DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id_sp, paths), + DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id.span, paths), + DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id.span, paths), } } diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.rs b/src/test/ui/directory_ownership/macro-expanded-mod.rs index 376c1a9cd6627..1066a2ba71209 100644 --- a/src/test/ui/directory_ownership/macro-expanded-mod.rs +++ b/src/test/ui/directory_ownership/macro-expanded-mod.rs @@ -1,7 +1,9 @@ // Test that macro-expanded non-inline modules behave correctly macro_rules! mod_decl { - ($i:ident) => { mod $i; } //~ ERROR Cannot declare a non-inline module inside a block + ($i:ident) => { + mod $i; + }; } mod macro_expanded_mod_helper { @@ -9,5 +11,5 @@ mod macro_expanded_mod_helper { } fn main() { - mod_decl!(foo); + mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block } diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.stderr b/src/test/ui/directory_ownership/macro-expanded-mod.stderr index c7780c869d635..d9d8a8ffed751 100644 --- a/src/test/ui/directory_ownership/macro-expanded-mod.stderr +++ b/src/test/ui/directory_ownership/macro-expanded-mod.stderr @@ -1,13 +1,8 @@ error: Cannot declare a non-inline module inside a block unless it has a path attribute - --> $DIR/macro-expanded-mod.rs:4:25 + --> $DIR/macro-expanded-mod.rs:14:15 | -LL | ($i:ident) => { mod $i; } - | ^^ -... LL | mod_decl!(foo); - | --------------- in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^ error: aborting due to previous error From d06031c418231e6e2de59bab5ab01fd1f07a1e3d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 20:19:52 +0100 Subject: [PATCH 14/36] extract parse_mod --- src/librustc_parse/parser/module.rs | 35 +++++++++++++++-------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 4538799919644..9ccafd7932ab4 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -31,14 +31,10 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> { let lo = self.token.span; - let krate = Ok(ast::Crate { - attrs: self.parse_inner_attributes()?, - module: self.parse_mod_items(&token::Eof, lo)?, - span: lo.to(self.token.span), - // Filled in by proc_macro_harness::inject() - proc_macros: Vec::new(), - }); - krate + let (module, attrs) = self.parse_mod(&token::Eof)?; + let span = lo.to(self.token.span); + let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`. + Ok(ast::Crate { attrs, module, span, proc_macros }) } /// Parses a `mod { ... }` or `mod ;` item. @@ -60,17 +56,23 @@ impl<'a> Parser<'a> { self.push_directory(id, &attrs); self.expect(&token::OpenDelim(token::Brace))?; - let mod_inner_lo = self.token.span; - let inner_attrs = self.parse_inner_attributes()?; - let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?; + let module = self.parse_mod(&token::CloseDelim(token::Brace))?; self.directory = old_directory; - (module, inner_attrs) + module }; attrs.append(&mut inner_attrs); Ok((id, ItemKind::Mod(module))) } + /// Parses the contents of a module (inner attributes followed by module items). + fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec)> { + let lo = self.token.span; + let attrs = self.parse_inner_attributes()?; + let module = self.parse_mod_items(term, lo)?; + Ok((module, attrs)) + } + /// Given a termination token, parses all of the items in a module. fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> { let mut items = vec![]; @@ -268,12 +270,11 @@ impl<'a> Parser<'a> { let mut p0 = new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp); p0.cfg_mods = self.cfg_mods; - let mod_inner_lo = p0.token.span; - let mod_attrs = p0.parse_inner_attributes()?; - let mut m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?; - m0.inline = false; + let mut module = p0.parse_mod(&token::Eof)?; + module.0.inline = false; + self.sess.included_mod_stack.borrow_mut().pop(); - Ok((m0, mod_attrs)) + Ok(module) } fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { From a2a32c71d848461037efea795f9fbbdc149c00de Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 19:53:25 +0100 Subject: [PATCH 15/36] extract error_on_circular_module --- src/librustc_parse/parser/module.rs | 30 +++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 9ccafd7932ab4..d203e665c950a 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -254,16 +254,7 @@ impl<'a> Parser<'a> { id_sp: Span, ) -> PResult<'a, (Mod, Vec)> { let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut(); - if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { - let mut err = String::from("circular modules: "); - let len = included_mod_stack.len(); - for p in &included_mod_stack[i..len] { - err.push_str(&p.to_string_lossy()); - err.push_str(" -> "); - } - err.push_str(&path.to_string_lossy()); - return Err(self.struct_span_err(id_sp, &err[..])); - } + self.error_on_circular_module(id_sp, &path, &included_mod_stack)?; included_mod_stack.push(path.clone()); drop(included_mod_stack); @@ -277,6 +268,25 @@ impl<'a> Parser<'a> { Ok(module) } + fn error_on_circular_module( + &self, + span: Span, + path: &Path, + included_mod_stack: &[PathBuf], + ) -> PResult<'a, ()> { + if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { + let mut err = String::from("circular modules: "); + let len = included_mod_stack.len(); + for p in &included_mod_stack[i..len] { + err.push_str(&p.to_string_lossy()); + err.push_str(" -> "); + } + err.push_str(&path.to_string_lossy()); + return Err(self.struct_span_err(span, &err[..])); + } + Ok(()) + } + fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { self.directory.path.push(&*path.as_str()); From 4d05f9037cd275fa2486d9f61690a60ba86aac17 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 09:28:46 +0100 Subject: [PATCH 16/36] detach submod_path from Parser --- src/librustc_parse/parser/diagnostics.rs | 31 -- src/librustc_parse/parser/module.rs | 348 +++++++++++++---------- 2 files changed, 192 insertions(+), 187 deletions(-) diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 8e52bb1614757..87255386b9e66 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -18,7 +18,6 @@ use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP}; use log::{debug, trace}; use std::mem; -use std::path::PathBuf; const TURBOFISH: &str = "use `::<...>` instead of `<...>` to specify type arguments"; @@ -41,42 +40,12 @@ pub(super) fn dummy_arg(ident: Ident) -> Param { } pub enum Error { - FileNotFoundForModule { mod_name: String, default_path: PathBuf }, - DuplicatePaths { mod_name: String, default_path: String, secondary_path: String }, UselessDocComment, } impl Error { fn span_err(self, sp: impl Into, handler: &Handler) -> DiagnosticBuilder<'_> { match self { - Error::FileNotFoundForModule { ref mod_name, ref default_path } => { - let mut err = struct_span_err!( - handler, - sp, - E0583, - "file not found for module `{}`", - mod_name, - ); - err.help(&format!( - "to create the module `{}`, create file \"{}\"", - mod_name, - default_path.display(), - )); - err - } - Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => { - let mut err = struct_span_err!( - handler, - sp, - E0584, - "file for module `{}` found at both {} and {}", - mod_name, - default_path, - secondary_path, - ); - err.help("delete or rename one of them to remove the ambiguity"); - err - } Error::UselessDocComment => { let mut err = struct_span_err!( handler, diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index d203e665c950a..a30d6da281a25 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -1,4 +1,3 @@ -use super::diagnostics::Error; use super::item::ItemInfo; use super::Parser; @@ -7,18 +6,19 @@ use crate::{new_sub_parser_from_file, DirectoryOwnership}; use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod}; use rustc_ast::attr; use rustc_ast::token::{self, TokenKind}; -use rustc_errors::PResult; -use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP}; +use rustc_errors::{struct_span_err, PResult}; +use rustc_session::parse::ParseSess; +use rustc_span::source_map::{FileName, Span, DUMMY_SP}; use rustc_span::symbol::sym; use std::path::{self, Path, PathBuf}; /// Information about the path to a module. // Public for rustfmt usage. -pub struct ModulePath { +pub struct ModulePath<'a> { name: String, path_exists: bool, - pub result: Result, + pub result: PResult<'a, ModulePathSuccess>, } // Public for rustfmt usage. @@ -45,8 +45,13 @@ impl<'a> Parser<'a> { let (module, mut inner_attrs) = if self.eat(&token::Semi) { if in_cfg && self.recurse_into_file_modules { // This mod is in an external file. Let's go get it! - let ModulePathSuccess { path, directory_ownership } = - self.submod_path(id, &attrs)?; + let ModulePathSuccess { path, directory_ownership } = submod_path( + self.sess, + id, + &attrs, + self.directory.ownership, + &self.directory.path, + )?; self.eval_src_mod(path, directory_ownership, id.to_string(), id.span)? } else { (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new()) @@ -96,155 +101,6 @@ impl<'a> Parser<'a> { Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) } - fn submod_path( - &mut self, - id: ast::Ident, - outer_attrs: &[Attribute], - ) -> PResult<'a, ModulePathSuccess> { - if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) { - let directory_ownership = match path.file_name().and_then(|s| s.to_str()) { - // All `#[path]` files are treated as though they are a `mod.rs` file. - // This means that `mod foo;` declarations inside `#[path]`-included - // files are siblings, - // - // Note that this will produce weirdness when a file named `foo.rs` is - // `#[path]` included and contains a `mod foo;` declaration. - // If you encounter this, it's your own darn fault :P - Some(_) => DirectoryOwnership::Owned { relative: None }, - _ => DirectoryOwnership::UnownedViaMod, - }; - return Ok(ModulePathSuccess { directory_ownership, path }); - } - - let relative = match self.directory.ownership { - DirectoryOwnership::Owned { relative } => relative, - DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None, - }; - let paths = - Parser::default_submod_path(id, relative, &self.directory.path, self.sess.source_map()); - - match self.directory.ownership { - DirectoryOwnership::Owned { .. } => { - paths.result.map_err(|err| self.span_fatal_err(id.span, err)) - } - DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id.span, paths), - DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id.span, paths), - } - } - - fn error_decl_mod_in_block(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> { - let msg = - "Cannot declare a non-inline module inside a block unless it has a path attribute"; - let mut err = self.struct_span_err(id_sp, msg); - if paths.path_exists { - let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", paths.name); - err.span_note(id_sp, &msg); - } - Err(err) - } - - fn error_cannot_declare_mod_here(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> { - let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location"); - if !id_sp.is_dummy() { - if let FileName::Real(src_path) = self.sess.source_map().span_to_filename(id_sp) { - if let Some(stem) = src_path.file_stem() { - let mut dest_path = src_path.clone(); - dest_path.set_file_name(stem); - dest_path.push("mod.rs"); - err.span_note( - id_sp, - &format!( - "maybe move this module `{}` to its own \ - directory via `{}`", - src_path.display(), - dest_path.display() - ), - ); - } - } - } - if paths.path_exists { - err.span_note( - id_sp, - &format!( - "... or maybe `use` the module `{}` instead \ - of possibly redeclaring it", - paths.name - ), - ); - } - Err(err) - } - - /// Derive a submodule path from the first found `#[path = "path_string"]`. - /// The provided `dir_path` is joined with the `path_string`. - // Public for rustfmt usage. - pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option { - // Extract path string from first `#[path = "path_string"]` attribute. - let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?; - let path_string = path_string.as_str(); - - // On windows, the base path might have the form - // `\\?\foo\bar` in which case it does not tolerate - // mixed `/` and `\` separators, so canonicalize - // `/` to `\`. - #[cfg(windows)] - let path_string = path_string.replace("/", "\\"); - - Some(dir_path.join(&*path_string)) - } - - /// Returns a path to a module. - // Public for rustfmt usage. - pub fn default_submod_path( - id: ast::Ident, - relative: Option, - dir_path: &Path, - source_map: &SourceMap, - ) -> ModulePath { - // If we're in a foo.rs file instead of a mod.rs file, - // we need to look for submodules in - // `./foo/.rs` and `./foo//mod.rs` rather than - // `./.rs` and `.//mod.rs`. - let relative_prefix_string; - let relative_prefix = if let Some(ident) = relative { - relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR); - &relative_prefix_string - } else { - "" - }; - - let mod_name = id.name.to_string(); - let default_path_str = format!("{}{}.rs", relative_prefix, mod_name); - let secondary_path_str = - format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR); - let default_path = dir_path.join(&default_path_str); - let secondary_path = dir_path.join(&secondary_path_str); - let default_exists = source_map.file_exists(&default_path); - let secondary_exists = source_map.file_exists(&secondary_path); - - let result = match (default_exists, secondary_exists) { - (true, false) => Ok(ModulePathSuccess { - path: default_path, - directory_ownership: DirectoryOwnership::Owned { relative: Some(id) }, - }), - (false, true) => Ok(ModulePathSuccess { - path: secondary_path, - directory_ownership: DirectoryOwnership::Owned { relative: None }, - }), - (false, false) => { - Err(Error::FileNotFoundForModule { mod_name: mod_name.clone(), default_path }) - } - (true, true) => Err(Error::DuplicatePaths { - mod_name: mod_name.clone(), - default_path: default_path_str, - secondary_path: secondary_path_str, - }), - }; - - ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result } - } - /// Reads a module from a source file. fn eval_src_mod( &mut self, @@ -308,3 +164,183 @@ impl<'a> Parser<'a> { } } } + +fn submod_path<'a>( + sess: &'a ParseSess, + id: ast::Ident, + outer_attrs: &[Attribute], + directory_ownership: DirectoryOwnership, + dir_path: &Path, +) -> PResult<'a, ModulePathSuccess> { + if let Some(path) = submod_path_from_attr(outer_attrs, dir_path) { + let directory_ownership = match path.file_name().and_then(|s| s.to_str()) { + // All `#[path]` files are treated as though they are a `mod.rs` file. + // This means that `mod foo;` declarations inside `#[path]`-included + // files are siblings, + // + // Note that this will produce weirdness when a file named `foo.rs` is + // `#[path]` included and contains a `mod foo;` declaration. + // If you encounter this, it's your own darn fault :P + Some(_) => DirectoryOwnership::Owned { relative: None }, + _ => DirectoryOwnership::UnownedViaMod, + }; + return Ok(ModulePathSuccess { directory_ownership, path }); + } + + let relative = match directory_ownership { + DirectoryOwnership::Owned { relative } => relative, + DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None, + }; + let ModulePath { path_exists, name, result } = + default_submod_path(sess, id, relative, dir_path); + match directory_ownership { + DirectoryOwnership::Owned { .. } => Ok(result?), + DirectoryOwnership::UnownedViaBlock => { + let _ = result.map_err(|mut err| err.cancel()); + error_decl_mod_in_block(sess, id.span, path_exists, &name) + } + DirectoryOwnership::UnownedViaMod => { + let _ = result.map_err(|mut err| err.cancel()); + error_cannot_declare_mod_here(sess, id.span, path_exists, &name) + } + } +} + +fn error_decl_mod_in_block<'a, T>( + sess: &'a ParseSess, + id_sp: Span, + path_exists: bool, + name: &str, +) -> PResult<'a, T> { + let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute"; + let mut err = sess.span_diagnostic.struct_span_err(id_sp, msg); + if path_exists { + let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name); + err.span_note(id_sp, &msg); + } + Err(err) +} + +fn error_cannot_declare_mod_here<'a, T>( + sess: &'a ParseSess, + id_sp: Span, + path_exists: bool, + name: &str, +) -> PResult<'a, T> { + let mut err = + sess.span_diagnostic.struct_span_err(id_sp, "cannot declare a new module at this location"); + if !id_sp.is_dummy() { + if let FileName::Real(src_path) = sess.source_map().span_to_filename(id_sp) { + if let Some(stem) = src_path.file_stem() { + let mut dest_path = src_path.clone(); + dest_path.set_file_name(stem); + dest_path.push("mod.rs"); + err.span_note( + id_sp, + &format!( + "maybe move this module `{}` to its own \ + directory via `{}`", + src_path.display(), + dest_path.display() + ), + ); + } + } + } + if path_exists { + err.span_note( + id_sp, + &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name), + ); + } + Err(err) +} + +/// Derive a submodule path from the first found `#[path = "path_string"]`. +/// The provided `dir_path` is joined with the `path_string`. +// Public for rustfmt usage. +pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option { + // Extract path string from first `#[path = "path_string"]` attribute. + let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?; + let path_string = path_string.as_str(); + + // On windows, the base path might have the form + // `\\?\foo\bar` in which case it does not tolerate + // mixed `/` and `\` separators, so canonicalize + // `/` to `\`. + #[cfg(windows)] + let path_string = path_string.replace("/", "\\"); + + Some(dir_path.join(&*path_string)) +} + +/// Returns a path to a module. +// Public for rustfmt usage. +pub fn default_submod_path<'a>( + sess: &'a ParseSess, + id: ast::Ident, + relative: Option, + dir_path: &Path, +) -> ModulePath<'a> { + // If we're in a foo.rs file instead of a mod.rs file, + // we need to look for submodules in + // `./foo/.rs` and `./foo//mod.rs` rather than + // `./.rs` and `.//mod.rs`. + let relative_prefix_string; + let relative_prefix = if let Some(ident) = relative { + relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR); + &relative_prefix_string + } else { + "" + }; + + let mod_name = id.name.to_string(); + let default_path_str = format!("{}{}.rs", relative_prefix, mod_name); + let secondary_path_str = + format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR); + let default_path = dir_path.join(&default_path_str); + let secondary_path = dir_path.join(&secondary_path_str); + let default_exists = sess.source_map().file_exists(&default_path); + let secondary_exists = sess.source_map().file_exists(&secondary_path); + + let result = match (default_exists, secondary_exists) { + (true, false) => Ok(ModulePathSuccess { + path: default_path, + directory_ownership: DirectoryOwnership::Owned { relative: Some(id) }, + }), + (false, true) => Ok(ModulePathSuccess { + path: secondary_path, + directory_ownership: DirectoryOwnership::Owned { relative: None }, + }), + (false, false) => { + let mut err = struct_span_err!( + sess.span_diagnostic, + id.span, + E0583, + "file not found for module `{}`", + mod_name, + ); + err.help(&format!( + "to create the module `{}`, create file \"{}\"", + mod_name, + default_path.display(), + )); + Err(err) + } + (true, true) => { + let mut err = struct_span_err!( + sess.span_diagnostic, + id.span, + E0584, + "file for module `{}` found at both {} and {}", + mod_name, + default_path_str, + secondary_path_str, + ); + err.help("delete or rename one of them to remove the ambiguity"); + Err(err) + } + }; + + ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result } +} From c824f5daec658ef52cc2261a08ef0592d5aae255 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 09:54:19 +0100 Subject: [PATCH 17/36] decouple push_directory from Parser --- src/librustc_parse/parser/module.rs | 41 ++++++++++++++++------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index a30d6da281a25..53c0c9154bc4a 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -58,7 +58,7 @@ impl<'a> Parser<'a> { } } else { let old_directory = self.directory.clone(); - self.push_directory(id, &attrs); + push_directory(id, &attrs, &mut self.directory.ownership, &mut self.directory.path); self.expect(&token::OpenDelim(token::Brace))?; let module = self.parse_mod(&token::CloseDelim(token::Brace))?; @@ -142,26 +142,31 @@ impl<'a> Parser<'a> { } Ok(()) } +} - fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { - if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { - self.directory.path.push(&*path.as_str()); - self.directory.ownership = DirectoryOwnership::Owned { relative: None }; - } else { - // We have to push on the current module name in the case of relative - // paths in order to ensure that any additional module paths from inline - // `mod x { ... }` come after the relative extension. - // - // For example, a `mod z { ... }` inside `x/y.rs` should set the current - // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`. - if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership { - if let Some(ident) = relative.take() { - // remove the relative offset - self.directory.path.push(&*ident.as_str()); - } +fn push_directory( + id: Ident, + attrs: &[Attribute], + dir_ownership: &mut DirectoryOwnership, + dir_path: &mut PathBuf, +) { + if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { + dir_path.push(&*path.as_str()); + *dir_ownership = DirectoryOwnership::Owned { relative: None }; + } else { + // We have to push on the current module name in the case of relative + // paths in order to ensure that any additional module paths from inline + // `mod x { ... }` come after the relative extension. + // + // For example, a `mod z { ... }` inside `x/y.rs` should set the current + // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`. + if let DirectoryOwnership::Owned { relative } = dir_ownership { + if let Some(ident) = relative.take() { + // Remove the relative offset. + dir_path.push(&*ident.as_str()); } - self.directory.path.push(&*id.as_str()); } + dir_path.push(&*id.as_str()); } } From 4a70313326098eb1b9983660cfaa0809c1a551f5 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 11:06:30 +0100 Subject: [PATCH 18/36] decouple eval_src_mod from Parser --- src/librustc_parse/parser/module.rs | 69 ++++++++++++----------------- 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 53c0c9154bc4a..245d06333f7d1 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -52,7 +52,7 @@ impl<'a> Parser<'a> { self.directory.ownership, &self.directory.path, )?; - self.eval_src_mod(path, directory_ownership, id.to_string(), id.span)? + eval_src_mod(self.sess, self.cfg_mods, path, directory_ownership, id)? } else { (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new()) } @@ -100,48 +100,37 @@ impl<'a> Parser<'a> { Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) } +} - /// Reads a module from a source file. - fn eval_src_mod( - &mut self, - path: PathBuf, - directory_ownership: DirectoryOwnership, - name: String, - id_sp: Span, - ) -> PResult<'a, (Mod, Vec)> { - let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut(); - self.error_on_circular_module(id_sp, &path, &included_mod_stack)?; - included_mod_stack.push(path.clone()); - drop(included_mod_stack); - - let mut p0 = - new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp); - p0.cfg_mods = self.cfg_mods; - let mut module = p0.parse_mod(&token::Eof)?; - module.0.inline = false; - - self.sess.included_mod_stack.borrow_mut().pop(); - Ok(module) - } - - fn error_on_circular_module( - &self, - span: Span, - path: &Path, - included_mod_stack: &[PathBuf], - ) -> PResult<'a, ()> { - if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { - let mut err = String::from("circular modules: "); - let len = included_mod_stack.len(); - for p in &included_mod_stack[i..len] { - err.push_str(&p.to_string_lossy()); - err.push_str(" -> "); - } - err.push_str(&path.to_string_lossy()); - return Err(self.struct_span_err(span, &err[..])); +/// Reads a module from a source file. +fn eval_src_mod<'a>( + sess: &'a ParseSess, + cfg_mods: bool, + path: PathBuf, + dir_ownership: DirectoryOwnership, + id: ast::Ident, +) -> PResult<'a, (Mod, Vec)> { + let mut included_mod_stack = sess.included_mod_stack.borrow_mut(); + if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { + let mut err = String::from("circular modules: "); + for p in &included_mod_stack[i..] { + err.push_str(&p.to_string_lossy()); + err.push_str(" -> "); } - Ok(()) + err.push_str(&path.to_string_lossy()); + return Err(sess.span_diagnostic.struct_span_err(id.span, &err[..])); } + included_mod_stack.push(path.clone()); + drop(included_mod_stack); + + let mut p0 = + new_sub_parser_from_file(sess, &path, dir_ownership, Some(id.to_string()), id.span); + p0.cfg_mods = cfg_mods; + let mut module = p0.parse_mod(&token::Eof)?; + module.0.inline = false; + + sess.included_mod_stack.borrow_mut().pop(); + Ok(module) } fn push_directory( From 033f8a2fbb28a45e115e9d28ad30f5e70088d0fa Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 11:18:26 +0100 Subject: [PATCH 19/36] expand: use push_directory --- src/librustc_expand/expand.rs | 14 +++++++------- src/librustc_parse/parser/mod.rs | 2 +- src/librustc_parse/parser/module.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 73197160a0269..38df430c28966 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -18,6 +18,7 @@ use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; use rustc_parse::configure; +use rustc_parse::parser::module; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; use rustc_parse::DirectoryOwnership; @@ -1387,13 +1388,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { module.mod_path.push(item.ident); if inline { - if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, sym::path) { - self.cx.current_expansion.directory_ownership = - DirectoryOwnership::Owned { relative: None }; - module.directory.push(&*path.as_str()); - } else { - module.directory.push(&*item.ident.as_str()); - } + module::push_directory( + item.ident, + &item.attrs, + &mut self.cx.current_expansion.directory_ownership, + &mut module.directory, + ); } else { let path = self.cx.parse_sess.source_map().span_to_unmapped_path(inner); let mut path = match path { diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 9376c7c1c724d..40dc9275b32a5 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -1,7 +1,7 @@ pub mod attr; mod expr; mod item; -mod module; +pub mod module; pub use module::{ModulePath, ModulePathSuccess}; mod pat; mod path; diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 245d06333f7d1..d4cf39e28b045 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -133,7 +133,7 @@ fn eval_src_mod<'a>( Ok(module) } -fn push_directory( +pub fn push_directory( id: Ident, attrs: &[Attribute], dir_ownership: &mut DirectoryOwnership, From 60a00b09440b517a66f1c4f149649f48c4bb8764 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 12:19:27 +0100 Subject: [PATCH 20/36] de-fatalize outline module parsing --- src/librustc_ast/ast.rs | 2 +- src/librustc_parse/parser/module.rs | 37 +++++++++---------- src/test/ui/mod/mod_file_disambig.rs | 1 + src/test/ui/mod/mod_file_disambig.stderr | 11 +++++- src/test/ui/parser/circular_modules_main.rs | 2 +- .../ui/parser/circular_modules_main.stderr | 14 ++++++- src/test/ui/parser/mod_file_not_exist.rs | 1 + src/test/ui/parser/mod_file_not_exist.stderr | 11 +++++- 8 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 68960ba9fe920..e3077b9897c18 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -2153,7 +2153,7 @@ impl FnRetTy { /// Module declaration. /// /// E.g., `mod foo;` or `mod foo { .. }`. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)] pub struct Mod { /// A span from the first token past `{` to the last token until `}`. /// For `mod foo;`, the inner span ranges from the first token diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index d4cf39e28b045..8f99d88b8e47a 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -8,7 +8,7 @@ use rustc_ast::attr; use rustc_ast::token::{self, TokenKind}; use rustc_errors::{struct_span_err, PResult}; use rustc_session::parse::ParseSess; -use rustc_span::source_map::{FileName, Span, DUMMY_SP}; +use rustc_span::source_map::{FileName, Span}; use rustc_span::symbol::sym; use std::path::{self, Path, PathBuf}; @@ -24,7 +24,7 @@ pub struct ModulePath<'a> { // Public for rustfmt usage. pub struct ModulePathSuccess { pub path: PathBuf, - pub directory_ownership: DirectoryOwnership, + pub ownership: DirectoryOwnership, } impl<'a> Parser<'a> { @@ -45,16 +45,13 @@ impl<'a> Parser<'a> { let (module, mut inner_attrs) = if self.eat(&token::Semi) { if in_cfg && self.recurse_into_file_modules { // This mod is in an external file. Let's go get it! - let ModulePathSuccess { path, directory_ownership } = submod_path( - self.sess, - id, - &attrs, - self.directory.ownership, - &self.directory.path, - )?; - eval_src_mod(self.sess, self.cfg_mods, path, directory_ownership, id)? + let dir = &self.directory; + submod_path(self.sess, id, &attrs, dir.ownership, &dir.path) + .and_then(|r| eval_src_mod(self.sess, self.cfg_mods, r.path, r.ownership, id)) + .map_err(|mut err| err.emit()) + .unwrap_or_default() } else { - (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new()) + Default::default() } } else { let old_directory = self.directory.clone(); @@ -162,12 +159,12 @@ pub fn push_directory( fn submod_path<'a>( sess: &'a ParseSess, id: ast::Ident, - outer_attrs: &[Attribute], - directory_ownership: DirectoryOwnership, + attrs: &[Attribute], + ownership: DirectoryOwnership, dir_path: &Path, ) -> PResult<'a, ModulePathSuccess> { - if let Some(path) = submod_path_from_attr(outer_attrs, dir_path) { - let directory_ownership = match path.file_name().and_then(|s| s.to_str()) { + if let Some(path) = submod_path_from_attr(attrs, dir_path) { + let ownership = match path.file_name().and_then(|s| s.to_str()) { // All `#[path]` files are treated as though they are a `mod.rs` file. // This means that `mod foo;` declarations inside `#[path]`-included // files are siblings, @@ -178,16 +175,16 @@ fn submod_path<'a>( Some(_) => DirectoryOwnership::Owned { relative: None }, _ => DirectoryOwnership::UnownedViaMod, }; - return Ok(ModulePathSuccess { directory_ownership, path }); + return Ok(ModulePathSuccess { ownership, path }); } - let relative = match directory_ownership { + let relative = match ownership { DirectoryOwnership::Owned { relative } => relative, DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None, }; let ModulePath { path_exists, name, result } = default_submod_path(sess, id, relative, dir_path); - match directory_ownership { + match ownership { DirectoryOwnership::Owned { .. } => Ok(result?), DirectoryOwnership::UnownedViaBlock => { let _ = result.map_err(|mut err| err.cancel()); @@ -300,11 +297,11 @@ pub fn default_submod_path<'a>( let result = match (default_exists, secondary_exists) { (true, false) => Ok(ModulePathSuccess { path: default_path, - directory_ownership: DirectoryOwnership::Owned { relative: Some(id) }, + ownership: DirectoryOwnership::Owned { relative: Some(id) }, }), (false, true) => Ok(ModulePathSuccess { path: secondary_path, - directory_ownership: DirectoryOwnership::Owned { relative: None }, + ownership: DirectoryOwnership::Owned { relative: None }, }), (false, false) => { let mut err = struct_span_err!( diff --git a/src/test/ui/mod/mod_file_disambig.rs b/src/test/ui/mod/mod_file_disambig.rs index ef203ef082b22..7b182421d34e3 100644 --- a/src/test/ui/mod/mod_file_disambig.rs +++ b/src/test/ui/mod/mod_file_disambig.rs @@ -2,4 +2,5 @@ mod mod_file_disambig_aux; //~ ERROR file for module `mod_file_disambig_aux` fou fn main() { assert_eq!(mod_file_aux::bar(), 10); + //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` } diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr index 2b77d866fb30b..230bfa79916df 100644 --- a/src/test/ui/mod/mod_file_disambig.stderr +++ b/src/test/ui/mod/mod_file_disambig.stderr @@ -6,6 +6,13 @@ LL | mod mod_file_disambig_aux; | = help: delete or rename one of them to remove the ambiguity -error: aborting due to previous error +error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` + --> $DIR/mod_file_disambig.rs:4:16 + | +LL | assert_eq!(mod_file_aux::bar(), 10); + | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0584`. +Some errors have detailed explanations: E0433, E0584. +For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/parser/circular_modules_main.rs b/src/test/ui/parser/circular_modules_main.rs index b85003bf0910f..1ae36a1f7605e 100644 --- a/src/test/ui/parser/circular_modules_main.rs +++ b/src/test/ui/parser/circular_modules_main.rs @@ -6,5 +6,5 @@ pub fn hi_str() -> String { } fn main() { - circular_modules_hello::say_hello(); + circular_modules_hello::say_hello(); //~ ERROR cannot find function `say_hello` in module } diff --git a/src/test/ui/parser/circular_modules_main.stderr b/src/test/ui/parser/circular_modules_main.stderr index 33865fb7bca95..ca84f2d285403 100644 --- a/src/test/ui/parser/circular_modules_main.stderr +++ b/src/test/ui/parser/circular_modules_main.stderr @@ -4,5 +4,17 @@ error: circular modules: $DIR/circular_modules_hello.rs -> $DIR/circular_modules LL | mod circular_modules_hello; | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0425]: cannot find function `say_hello` in module `circular_modules_hello` + --> $DIR/circular_modules_main.rs:9:29 + | +LL | circular_modules_hello::say_hello(); + | ^^^^^^^^^ not found in `circular_modules_hello` + | +help: possible candidate is found in another module, you can import it into scope + | +LL | use circular_modules_hello::say_hello; + | + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/parser/mod_file_not_exist.rs b/src/test/ui/parser/mod_file_not_exist.rs index 71fbc7aea45eb..aee778d1013a9 100644 --- a/src/test/ui/parser/mod_file_not_exist.rs +++ b/src/test/ui/parser/mod_file_not_exist.rs @@ -5,4 +5,5 @@ mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` fn main() { assert_eq!(mod_file_aux::bar(), 10); + //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr index db3ea04ac7655..c298c51c4f870 100644 --- a/src/test/ui/parser/mod_file_not_exist.stderr +++ b/src/test/ui/parser/mod_file_not_exist.stderr @@ -6,6 +6,13 @@ LL | mod not_a_real_file; | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error: aborting due to previous error +error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` + --> $DIR/mod_file_not_exist.rs:7:16 + | +LL | assert_eq!(mod_file_aux::bar(), 10); + | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0583`. +Some errors have detailed explanations: E0433, E0583. +For more information about an error, try `rustc --explain E0433`. From 16d444a9b5cce83b7da88d19fc9cca5c162900f2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 12:33:15 +0100 Subject: [PATCH 21/36] extract parse_external_module --- src/librustc_parse/parser/module.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 8f99d88b8e47a..0701b733076a6 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -44,12 +44,8 @@ impl<'a> Parser<'a> { let id = self.parse_ident()?; let (module, mut inner_attrs) = if self.eat(&token::Semi) { if in_cfg && self.recurse_into_file_modules { - // This mod is in an external file. Let's go get it! let dir = &self.directory; - submod_path(self.sess, id, &attrs, dir.ownership, &dir.path) - .and_then(|r| eval_src_mod(self.sess, self.cfg_mods, r.path, r.ownership, id)) - .map_err(|mut err| err.emit()) - .unwrap_or_default() + parse_external_module(self.sess, self.cfg_mods, id, dir.ownership, &dir.path, attrs) } else { Default::default() } @@ -99,6 +95,20 @@ impl<'a> Parser<'a> { } } +fn parse_external_module( + sess: &ParseSess, + cfg_mods: bool, + id: ast::Ident, + ownership: DirectoryOwnership, + dir_path: &Path, + attrs: &[Attribute], +) -> (Mod, Vec) { + submod_path(sess, id, &attrs, ownership, dir_path) + .and_then(|r| eval_src_mod(sess, cfg_mods, r.path, r.ownership, id)) + .map_err(|mut err| err.emit()) + .unwrap_or_default() +} + /// Reads a module from a source file. fn eval_src_mod<'a>( sess: &'a ParseSess, From a1f99538650691c8b7fb2a0816ced86956b14766 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 13:29:37 +0100 Subject: [PATCH 22/36] extract error_on_circular_module --- src/librustc_parse/parser/module.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 0701b733076a6..66faf295b7232 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -118,15 +118,7 @@ fn eval_src_mod<'a>( id: ast::Ident, ) -> PResult<'a, (Mod, Vec)> { let mut included_mod_stack = sess.included_mod_stack.borrow_mut(); - if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { - let mut err = String::from("circular modules: "); - for p in &included_mod_stack[i..] { - err.push_str(&p.to_string_lossy()); - err.push_str(" -> "); - } - err.push_str(&path.to_string_lossy()); - return Err(sess.span_diagnostic.struct_span_err(id.span, &err[..])); - } + error_on_circular_module(sess, id.span, &path, &included_mod_stack)?; included_mod_stack.push(path.clone()); drop(included_mod_stack); @@ -140,6 +132,24 @@ fn eval_src_mod<'a>( Ok(module) } +fn error_on_circular_module<'a>( + sess: &'a ParseSess, + span: Span, + path: &Path, + included_mod_stack: &[PathBuf], +) -> PResult<'a, ()> { + if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { + let mut err = String::from("circular modules: "); + for p in &included_mod_stack[i..] { + err.push_str(&p.to_string_lossy()); + err.push_str(" -> "); + } + err.push_str(&path.to_string_lossy()); + return Err(sess.span_diagnostic.struct_span_err(span, &err[..])); + } + Ok(()) +} + pub fn push_directory( id: Ident, attrs: &[Attribute], From 97fa2bd29755bd2338b281c14000cf3d99698242 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 13:36:20 +0100 Subject: [PATCH 23/36] outline modules: parse -> expand. --- src/librustc_builtin_macros/source_util.rs | 5 +- src/librustc_expand/expand.rs | 77 +++++++++------ src/librustc_expand/mbe/macro_rules.rs | 37 +++----- src/librustc_parse/config.rs | 9 -- src/librustc_parse/lib.rs | 20 ++-- src/librustc_parse/parser/mod.rs | 33 +------ src/librustc_parse/parser/module.rs | 105 ++++++++++----------- src/librustc_parse/parser/stmt.rs | 10 +- 8 files changed, 116 insertions(+), 180 deletions(-) diff --git a/src/librustc_builtin_macros/source_util.rs b/src/librustc_builtin_macros/source_util.rs index 5ad72a7443dd2..662bbe6a287a3 100644 --- a/src/librustc_builtin_macros/source_util.rs +++ b/src/librustc_builtin_macros/source_util.rs @@ -5,7 +5,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; use rustc_expand::base::{self, *}; use rustc_expand::panictry; -use rustc_parse::{self, new_sub_parser_from_file, parser::Parser, DirectoryOwnership}; +use rustc_parse::{self, new_sub_parser_from_file, parser::Parser}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_span::symbol::Symbol; use rustc_span::{self, Pos, Span}; @@ -108,8 +108,7 @@ pub fn expand_include<'cx>( return DummyResult::any(sp); } }; - let directory_ownership = DirectoryOwnership::Owned { relative: None }; - let p = new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp); + let p = new_sub_parser_from_file(cx.parse_sess(), &file, None, sp); struct ExpandResult<'a> { p: Parser<'a>, diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 38df430c28966..bd929f89de034 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -18,10 +18,10 @@ use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; use rustc_parse::configure; -use rustc_parse::parser::module; +use rustc_parse::parser::module::{parse_external_mod, push_directory}; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; -use rustc_parse::DirectoryOwnership; +use rustc_parse::{Directory, DirectoryOwnership}; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; @@ -1367,8 +1367,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_items(); } + let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck. + let ident = item.ident; + match item.kind { ast::ItemKind::MacCall(..) => { + item.attrs = attrs; self.check_attributes(&item.attrs); item.and_then(|item| match item.kind { ItemKind::MacCall(mac) => self @@ -1380,45 +1384,56 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { _ => unreachable!(), }) } - ast::ItemKind::Mod(ast::Mod { inner, inline, .. }) - if item.ident != Ident::invalid() => - { - let orig_directory_ownership = self.cx.current_expansion.directory_ownership; + ast::ItemKind::Mod(ref mut old_mod @ ast::Mod { .. }) if ident != Ident::invalid() => { + let sess = self.cx.parse_sess; + let orig_ownership = self.cx.current_expansion.directory_ownership; let mut module = (*self.cx.current_expansion.module).clone(); - module.mod_path.push(item.ident); - - if inline { - module::push_directory( - item.ident, - &item.attrs, - &mut self.cx.current_expansion.directory_ownership, - &mut module.directory, - ); + + let pushed = &mut false; // Record `parse_external_mod` pushing so we can pop. + let dir = Directory { ownership: orig_ownership, path: module.directory }; + let Directory { ownership, path } = if old_mod.inline { + // Inline `mod foo { ... }`, but we still need to push directories. + item.attrs = attrs; + push_directory(ident, &item.attrs, dir) } else { - let path = self.cx.parse_sess.source_map().span_to_unmapped_path(inner); - let mut path = match path { - FileName::Real(path) => path, - other => PathBuf::from(other.to_string()), - }; - let directory_ownership = match path.file_name().unwrap().to_str() { - Some("mod.rs") => DirectoryOwnership::Owned { relative: None }, - Some(_) => DirectoryOwnership::Owned { relative: Some(item.ident) }, - None => DirectoryOwnership::UnownedViaMod, + // We have an outline `mod foo;` so we need to parse the file. + let (new_mod, dir) = parse_external_mod(sess, ident, dir, &mut attrs, pushed); + *old_mod = new_mod; + item.attrs = attrs; + // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure. + item = match self.configure(item) { + Some(node) => node, + None => { + if *pushed { + sess.included_mod_stack.borrow_mut().pop(); + } + return Default::default(); + } }; - path.pop(); - module.directory = path; - self.cx.current_expansion.directory_ownership = directory_ownership; - } + dir + }; + // Set the module info before we flat map. + self.cx.current_expansion.directory_ownership = ownership; + module.directory = path; + module.mod_path.push(ident); let orig_module = mem::replace(&mut self.cx.current_expansion.module, Rc::new(module)); + let result = noop_flat_map_item(item, self); + + // Restore the module info. self.cx.current_expansion.module = orig_module; - self.cx.current_expansion.directory_ownership = orig_directory_ownership; + self.cx.current_expansion.directory_ownership = orig_ownership; + if *pushed { + sess.included_mod_stack.borrow_mut().pop(); + } result } - - _ => noop_flat_map_item(item, self), + _ => { + item.attrs = attrs; + noop_flat_map_item(item, self) + } } } diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 3cad3ff55d910..e75547916cefb 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -1,4 +1,4 @@ -use crate::base::{DummyResult, ExpansionData, ExtCtxt, MacResult, TTMacroExpander}; +use crate::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; use crate::base::{SyntaxExtension, SyntaxExtensionKind}; use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind}; use crate::mbe; @@ -18,7 +18,6 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder, FatalError}; use rustc_feature::Features; use rustc_parse::parser::Parser; -use rustc_parse::Directory; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; @@ -182,6 +181,8 @@ fn generic_extension<'cx>( lhses: &[mbe::TokenTree], rhses: &[mbe::TokenTree], ) -> Box { + let sess = cx.parse_sess; + if cx.trace_macros() { let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(arg.clone())); trace_macros_note(&mut cx.expansions, sp, msg); @@ -209,7 +210,7 @@ fn generic_extension<'cx>( // hacky, but speeds up the `html5ever` benchmark significantly. (Issue // 68836 suggests a more comprehensive but more complex change to deal with // this situation.) - let parser = parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone()); + let parser = parser_from_cx(sess, arg.clone()); for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers @@ -222,14 +223,13 @@ fn generic_extension<'cx>( // This is used so that if a matcher is not `Success(..)`ful, // then the spans which became gated when parsing the unsuccessful matcher // are not recorded. On the first `Success(..)`ful matcher, the spans are merged. - let mut gated_spans_snapshot = - mem::take(&mut *cx.parse_sess.gated_spans.spans.borrow_mut()); + let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut()); match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) { Success(named_matches) => { // The matcher was `Success(..)`ful. // Merge the gated spans from parsing the matcher with the pre-existing ones. - cx.parse_sess.gated_spans.merge(gated_spans_snapshot); + sess.gated_spans.merge(gated_spans_snapshot); let rhs = match rhses[i] { // ignore delimiters @@ -258,11 +258,7 @@ fn generic_extension<'cx>( trace_macros_note(&mut cx.expansions, sp, msg); } - let directory = Directory { - path: cx.current_expansion.module.directory.clone(), - ownership: cx.current_expansion.directory_ownership, - }; - let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false, None); + let mut p = Parser::new(cx.parse_sess(), tts, false, None); p.root_module_name = cx.current_expansion.module.mod_path.last().map(|id| id.to_string()); p.last_type_ascription = cx.current_expansion.prior_type_ascription; @@ -289,7 +285,7 @@ fn generic_extension<'cx>( // The matcher was not `Success(..)`ful. // Restore to the state before snapshotting and maybe try again. - mem::swap(&mut gated_spans_snapshot, &mut cx.parse_sess.gated_spans.spans.borrow_mut()); + mem::swap(&mut gated_spans_snapshot, &mut sess.gated_spans.spans.borrow_mut()); } drop(parser); @@ -309,8 +305,7 @@ fn generic_extension<'cx>( mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], _ => continue, }; - let parser = parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone()); - match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) { + match parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt) { Success(_) => { if comma_span.is_dummy() { err.note("you might be missing a comma"); @@ -392,7 +387,7 @@ pub fn compile_declarative_macro( ), ]; - let parser = Parser::new(sess, body, None, true, true, rustc_parse::MACRO_ARGUMENTS); + let parser = Parser::new(sess, body, true, rustc_parse::MACRO_ARGUMENTS); let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) { Success(m) => m, Failure(token, msg) => { @@ -1209,16 +1204,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { } } -fn parser_from_cx<'cx>( - current_expansion: &'cx ExpansionData, - sess: &'cx ParseSess, - tts: TokenStream, -) -> Parser<'cx> { - let directory = Directory { - path: current_expansion.module.directory.clone(), - ownership: current_expansion.directory_ownership, - }; - Parser::new(sess, tts, Some(directory), true, true, rustc_parse::MACRO_ARGUMENTS) +fn parser_from_cx<'cx>(sess: &'cx ParseSess, tts: TokenStream) -> Parser<'cx> { + Parser::new(sess, tts, true, rustc_parse::MACRO_ARGUMENTS) } /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs index d209da866e17c..c611f24942012 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_parse/config.rs @@ -538,12 +538,3 @@ impl<'a> MutVisitor for StripUnconfigured<'a> { fn is_cfg(attr: &Attribute) -> bool { attr.check_name(sym::cfg) } - -/// Process the potential `cfg` attributes on a module. -/// Also determine if the module should be included in this configuration. -pub fn process_configure_mod(sess: &ParseSess, cfg_mods: bool, attrs: &mut Vec) -> bool { - // Don't perform gated feature checking. - let mut strip_unconfigured = StripUnconfigured { sess, features: None }; - strip_unconfigured.process_cfg_attrs(attrs); - !cfg_mods || strip_unconfigured.in_cfg(&attrs) -} diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 884499ff2dd48..bcaae02942e29 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -3,6 +3,7 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] +#![feature(try_blocks)] use rustc_ast::ast; use rustc_ast::token::{self, Nonterminal}; @@ -119,10 +120,7 @@ pub fn maybe_new_parser_from_source_str( name: FileName, source: String, ) -> Result, Vec> { - let mut parser = - maybe_source_file_to_parser(sess, sess.source_map().new_source_file(name, source))?; - parser.recurse_into_file_modules = false; - Ok(parser) + maybe_source_file_to_parser(sess, sess.source_map().new_source_file(name, source)) } /// Creates a new parser, handling errors as appropriate if the file doesn't exist. @@ -146,12 +144,10 @@ pub fn maybe_new_parser_from_file<'a>( pub fn new_sub_parser_from_file<'a>( sess: &'a ParseSess, path: &Path, - directory_ownership: DirectoryOwnership, module_name: Option, sp: Span, ) -> Parser<'a> { let mut p = source_file_to_parser(sess, file_to_source_file(sess, path, Some(sp))); - p.directory.ownership = directory_ownership; p.root_module_name = module_name; p } @@ -257,7 +253,7 @@ pub fn stream_to_parser<'a>( stream: TokenStream, subparser_name: Option<&'static str>, ) -> Parser<'a> { - Parser::new(sess, stream, None, true, false, subparser_name) + Parser::new(sess, stream, false, subparser_name) } /// Given a stream, the `ParseSess` and the base directory, produces a parser. @@ -271,12 +267,8 @@ pub fn stream_to_parser<'a>( /// The main usage of this function is outside of rustc, for those who uses /// librustc_ast as a library. Please do not remove this function while refactoring /// just because it is not used in rustc codebase! -pub fn stream_to_parser_with_base_dir( - sess: &ParseSess, - stream: TokenStream, - base_dir: Directory, -) -> Parser<'_> { - Parser::new(sess, stream, Some(base_dir), true, false, None) +pub fn stream_to_parser_with_base_dir(sess: &ParseSess, stream: TokenStream) -> Parser<'_> { + Parser::new(sess, stream, false, None) } /// Runs the given subparser `f` on the tokens of the given `attr`'s item. @@ -286,7 +278,7 @@ pub fn parse_in<'a, T>( name: &'static str, mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, T> { - let mut parser = Parser::new(sess, tts, None, false, false, Some(name)); + let mut parser = Parser::new(sess, tts, false, Some(name)); let result = f(&mut parser)?; if parser.token != token::Eof { parser.unexpected()?; diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 40dc9275b32a5..f4862a6c87b73 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -13,7 +13,6 @@ mod stmt; use diagnostics::Error; use crate::lexer::UnmatchedBrace; -use crate::{Directory, DirectoryOwnership}; use log::debug; use rustc_ast::ast::DUMMY_NODE_ID; @@ -28,11 +27,9 @@ use rustc_ast::util::comments::{doc_comment_style, strip_doc_comment_decoration} use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_session::parse::ParseSess; -use rustc_span::source_map::respan; +use rustc_span::source_map::{respan, Span, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::{FileName, Span, DUMMY_SP}; -use std::path::PathBuf; use std::{cmp, mem, slice}; bitflags::bitflags! { @@ -93,11 +90,6 @@ pub struct Parser<'a> { /// The previous token. pub prev_token: Token, restrictions: Restrictions, - /// Used to determine the path to externally loaded source files. - pub(super) directory: Directory, - /// `true` to parse sub-modules in other files. - // Public for rustfmt usage. - pub recurse_into_file_modules: bool, /// Name of the root module this parser originated from. If `None`, then the /// name is not known. This does not change while the parser is descending /// into modules, and sub-parsers have new values for this name. @@ -105,9 +97,6 @@ pub struct Parser<'a> { expected_tokens: Vec, token_cursor: TokenCursor, desugar_doc_comments: bool, - /// `true` we should configure out of line modules as we parse. - // Public for rustfmt usage. - pub cfg_mods: bool, /// This field is used to keep track of how many left angle brackets we have seen. This is /// required in order to detect extra leading left angle brackets (`<` characters) and error /// appropriately. @@ -355,8 +344,6 @@ impl<'a> Parser<'a> { pub fn new( sess: &'a ParseSess, tokens: TokenStream, - directory: Option, - recurse_into_file_modules: bool, desugar_doc_comments: bool, subparser_name: Option<&'static str>, ) -> Self { @@ -365,11 +352,6 @@ impl<'a> Parser<'a> { token: Token::dummy(), prev_token: Token::dummy(), restrictions: Restrictions::empty(), - recurse_into_file_modules, - directory: Directory { - path: PathBuf::new(), - ownership: DirectoryOwnership::Owned { relative: None }, - }, root_module_name: None, expected_tokens: Vec::new(), token_cursor: TokenCursor { @@ -377,7 +359,6 @@ impl<'a> Parser<'a> { stack: Vec::new(), }, desugar_doc_comments, - cfg_mods: true, unmatched_angle_bracket_count: 0, max_angle_bracket_count: 0, unclosed_delims: Vec::new(), @@ -389,18 +370,6 @@ impl<'a> Parser<'a> { // Make parser point to the first token. parser.bump(); - if let Some(directory) = directory { - parser.directory = directory; - } else if !parser.token.span.is_dummy() { - if let Some(FileName::Real(path)) = - &sess.source_map().lookup_char_pos(parser.token.span.lo()).file.unmapped_path - { - if let Some(directory_path) = path.parent() { - parser.directory.path = directory_path.to_path_buf(); - } - } - } - parser } diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 66faf295b7232..695afafdd824c 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -1,7 +1,7 @@ use super::item::ItemInfo; use super::Parser; -use crate::{new_sub_parser_from_file, DirectoryOwnership}; +use crate::{new_sub_parser_from_file, Directory, DirectoryOwnership}; use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod}; use rustc_ast::attr; @@ -39,25 +39,12 @@ impl<'a> Parser<'a> { /// Parses a `mod { ... }` or `mod ;` item. pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { - let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs); - let id = self.parse_ident()?; let (module, mut inner_attrs) = if self.eat(&token::Semi) { - if in_cfg && self.recurse_into_file_modules { - let dir = &self.directory; - parse_external_module(self.sess, self.cfg_mods, id, dir.ownership, &dir.path, attrs) - } else { - Default::default() - } + Default::default() } else { - let old_directory = self.directory.clone(); - push_directory(id, &attrs, &mut self.directory.ownership, &mut self.directory.path); - self.expect(&token::OpenDelim(token::Brace))?; - let module = self.parse_mod(&token::CloseDelim(token::Brace))?; - - self.directory = old_directory; - module + self.parse_mod(&token::CloseDelim(token::Brace))? }; attrs.append(&mut inner_attrs); Ok((id, ItemKind::Mod(module))) @@ -95,41 +82,45 @@ impl<'a> Parser<'a> { } } -fn parse_external_module( +pub fn parse_external_mod( sess: &ParseSess, - cfg_mods: bool, - id: ast::Ident, - ownership: DirectoryOwnership, - dir_path: &Path, - attrs: &[Attribute], -) -> (Mod, Vec) { - submod_path(sess, id, &attrs, ownership, dir_path) - .and_then(|r| eval_src_mod(sess, cfg_mods, r.path, r.ownership, id)) - .map_err(|mut err| err.emit()) - .unwrap_or_default() -} - -/// Reads a module from a source file. -fn eval_src_mod<'a>( - sess: &'a ParseSess, - cfg_mods: bool, - path: PathBuf, - dir_ownership: DirectoryOwnership, id: ast::Ident, -) -> PResult<'a, (Mod, Vec)> { - let mut included_mod_stack = sess.included_mod_stack.borrow_mut(); - error_on_circular_module(sess, id.span, &path, &included_mod_stack)?; - included_mod_stack.push(path.clone()); - drop(included_mod_stack); - - let mut p0 = - new_sub_parser_from_file(sess, &path, dir_ownership, Some(id.to_string()), id.span); - p0.cfg_mods = cfg_mods; - let mut module = p0.parse_mod(&token::Eof)?; - module.0.inline = false; + Directory { mut ownership, path }: Directory, + attrs: &mut Vec, + pop_mod_stack: &mut bool, +) -> (Mod, Directory) { + // We bail on the first error, but that error does not cause a fatal error... (1) + let result: PResult<'_, _> = try { + // Extract the file path and the new ownership. + let mp = submod_path(sess, id, &attrs, ownership, &path)?; + ownership = mp.ownership; + + // Ensure file paths are acyclic. + let mut included_mod_stack = sess.included_mod_stack.borrow_mut(); + error_on_circular_module(sess, id.span, &mp.path, &included_mod_stack)?; + included_mod_stack.push(mp.path.clone()); + *pop_mod_stack = true; // We have pushed, so notify caller. + drop(included_mod_stack); + + // Actually parse the external file as amodule. + let mut p0 = new_sub_parser_from_file(sess, &mp.path, Some(id.to_string()), id.span); + let mut module = p0.parse_mod(&token::Eof)?; + module.0.inline = false; + module + }; + // (1) ...instead, we return a dummy module. + let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default(); + attrs.append(&mut new_attrs); + + // Extract the directory path for submodules of `module`. + let path = sess.source_map().span_to_unmapped_path(module.inner); + let mut path = match path { + FileName::Real(path) => path, + other => PathBuf::from(other.to_string()), + }; + path.pop(); - sess.included_mod_stack.borrow_mut().pop(); - Ok(module) + (module, Directory { ownership, path }) } fn error_on_circular_module<'a>( @@ -153,12 +144,11 @@ fn error_on_circular_module<'a>( pub fn push_directory( id: Ident, attrs: &[Attribute], - dir_ownership: &mut DirectoryOwnership, - dir_path: &mut PathBuf, -) { - if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { - dir_path.push(&*path.as_str()); - *dir_ownership = DirectoryOwnership::Owned { relative: None }; + Directory { mut ownership, mut path }: Directory, +) -> Directory { + if let Some(filename) = attr::first_attr_value_str_by_name(attrs, sym::path) { + path.push(&*filename.as_str()); + ownership = DirectoryOwnership::Owned { relative: None }; } else { // We have to push on the current module name in the case of relative // paths in order to ensure that any additional module paths from inline @@ -166,14 +156,15 @@ pub fn push_directory( // // For example, a `mod z { ... }` inside `x/y.rs` should set the current // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`. - if let DirectoryOwnership::Owned { relative } = dir_ownership { + if let DirectoryOwnership::Owned { relative } = &mut ownership { if let Some(ident) = relative.take() { // Remove the relative offset. - dir_path.push(&*ident.as_str()); + path.push(&*ident.as_str()); } } - dir_path.push(&*id.as_str()); + path.push(&*id.as_str()); } + Directory { ownership, path } } fn submod_path<'a>( diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index 4359823be0890..d40597d8fcb0c 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -5,7 +5,6 @@ use super::pat::GateOr; use super::path::PathStyle; use super::{BlockMode, Parser, Restrictions, SemiColonMode}; use crate::maybe_whole; -use crate::DirectoryOwnership; use rustc_ast::ast; use rustc_ast::ast::{AttrStyle, AttrVec, Attribute, MacCall, MacStmtStyle}; @@ -54,7 +53,7 @@ impl<'a> Parser<'a> { // that starts like a path (1 token), but it fact not a path. // Also, we avoid stealing syntax from `parse_item_`. self.parse_stmt_path_start(lo, attrs)? - } else if let Some(item) = self.parse_stmt_item(attrs.clone())? { + } else if let Some(item) = self.parse_item_common(attrs.clone(), false, true, |_| true)? { // FIXME: Bad copy of attrs self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) } else if self.eat(&token::Semi) { @@ -72,13 +71,6 @@ impl<'a> Parser<'a> { Ok(Some(stmt)) } - fn parse_stmt_item(&mut self, attrs: Vec) -> PResult<'a, Option> { - let old = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); - let item = self.parse_item_common(attrs, false, true, |_| true)?; - self.directory.ownership = old; - Ok(item) - } - fn parse_stmt_path_start(&mut self, lo: Span, attrs: Vec) -> PResult<'a, Stmt> { let path = self.parse_path(PathStyle::Expr)?; From fb540a94057b63d4152c4c815b2ca5dc5ab0d882 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 21:50:01 +0100 Subject: [PATCH 24/36] parse: module parsing -> item.rs --- src/librustc_parse/parser/item.rs | 69 ++++++++++++++++++++++++++--- src/librustc_parse/parser/module.rs | 62 +------------------------- 2 files changed, 66 insertions(+), 65 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index e927bcd07e2cd..d0da8e6c7c11e 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -4,14 +4,18 @@ use super::{FollowedByType, Parser, PathStyle}; use crate::maybe_whole; -use rustc_ast::ast::{self, Async, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; -use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind}; -use rustc_ast::ast::{BindingMode, Block, FnDecl, FnSig, MacArgs, MacCall, MacDelimiter, Param}; -use rustc_ast::ast::{Const, Defaultness, IsAuto, PathSegment, Unsafe, UseTree, UseTreeKind}; +use rustc_ast::ast::{self, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; +use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind, Mod}; +use rustc_ast::ast::{ + Async, Const, Defaultness, IsAuto, PathSegment, Unsafe, UseTree, UseTreeKind, +}; +use rustc_ast::ast::{ + BindingMode, Block, FnDecl, FnSig, MacArgs, MacCall, MacDelimiter, Param, SelfKind, +}; use rustc_ast::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData}; use rustc_ast::ast::{FnHeader, ForeignItem, Mutability, SelfKind, Visibility, VisibilityKind}; use rustc_ast::ptr::P; -use rustc_ast::token; +use rustc_ast::token::{self, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, PResult, StashKey}; @@ -23,6 +27,61 @@ use log::debug; use std::convert::TryFrom; use std::mem; +impl<'a> Parser<'a> { + /// Parses a source module as a crate. This is the main entry point for the parser. + pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> { + let lo = self.token.span; + let (module, attrs) = self.parse_mod(&token::Eof)?; + let span = lo.to(self.token.span); + let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`. + Ok(ast::Crate { attrs, module, span, proc_macros }) + } + + /// Parses a `mod { ... }` or `mod ;` item. + pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { + let id = self.parse_ident()?; + let (module, mut inner_attrs) = if self.eat(&token::Semi) { + Default::default() + } else { + self.expect(&token::OpenDelim(token::Brace))?; + self.parse_mod(&token::CloseDelim(token::Brace))? + }; + attrs.append(&mut inner_attrs); + Ok((id, ItemKind::Mod(module))) + } + + /// Parses the contents of a module (inner attributes followed by module items). + pub fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec)> { + let lo = self.token.span; + let attrs = self.parse_inner_attributes()?; + let module = self.parse_mod_items(term, lo)?; + Ok((module, attrs)) + } + + /// Given a termination token, parses all of the items in a module. + fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> { + let mut items = vec![]; + while let Some(item) = self.parse_item()? { + items.push(item); + self.maybe_consume_incorrect_semicolon(&items); + } + + if !self.eat(term) { + let token_str = super::token_descr(&self.token); + if !self.maybe_consume_incorrect_semicolon(&items) { + let msg = &format!("expected item, found {}", token_str); + let mut err = self.struct_span_err(self.token.span, msg); + err.span_label(self.token.span, "expected item"); + return Err(err); + } + } + + let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span }; + + Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) + } +} + pub(super) type ItemInfo = (Ident, ItemKind); impl<'a> Parser<'a> { diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 695afafdd824c..2c752bd9f0af7 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -1,11 +1,8 @@ -use super::item::ItemInfo; -use super::Parser; - use crate::{new_sub_parser_from_file, Directory, DirectoryOwnership}; -use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod}; +use rustc_ast::ast::{self, Attribute, Ident, Mod}; use rustc_ast::attr; -use rustc_ast::token::{self, TokenKind}; +use rustc_ast::token; use rustc_errors::{struct_span_err, PResult}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FileName, Span}; @@ -27,61 +24,6 @@ pub struct ModulePathSuccess { pub ownership: DirectoryOwnership, } -impl<'a> Parser<'a> { - /// Parses a source module as a crate. This is the main entry point for the parser. - pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> { - let lo = self.token.span; - let (module, attrs) = self.parse_mod(&token::Eof)?; - let span = lo.to(self.token.span); - let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`. - Ok(ast::Crate { attrs, module, span, proc_macros }) - } - - /// Parses a `mod { ... }` or `mod ;` item. - pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { - let id = self.parse_ident()?; - let (module, mut inner_attrs) = if self.eat(&token::Semi) { - Default::default() - } else { - self.expect(&token::OpenDelim(token::Brace))?; - self.parse_mod(&token::CloseDelim(token::Brace))? - }; - attrs.append(&mut inner_attrs); - Ok((id, ItemKind::Mod(module))) - } - - /// Parses the contents of a module (inner attributes followed by module items). - fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec)> { - let lo = self.token.span; - let attrs = self.parse_inner_attributes()?; - let module = self.parse_mod_items(term, lo)?; - Ok((module, attrs)) - } - - /// Given a termination token, parses all of the items in a module. - fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> { - let mut items = vec![]; - while let Some(item) = self.parse_item()? { - items.push(item); - self.maybe_consume_incorrect_semicolon(&items); - } - - if !self.eat(term) { - let token_str = super::token_descr(&self.token); - if !self.maybe_consume_incorrect_semicolon(&items) { - let msg = &format!("expected item, found {}", token_str); - let mut err = self.struct_span_err(self.token.span, msg); - err.span_label(self.token.span, "expected item"); - return Err(err); - } - } - - let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span }; - - Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) - } -} - pub fn parse_external_mod( sess: &ParseSess, id: ast::Ident, From e2cd4d0bfa723c0df9f68d8d3a7531ca5d7d5f3b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 22:10:37 +0100 Subject: [PATCH 25/36] move Directory -> parser::module --- src/librustc_expand/base.rs | 3 ++- src/librustc_expand/expand.rs | 5 +++-- src/librustc_parse/lib.rs | 18 +----------------- src/librustc_parse/parser/module.rs | 21 ++++++++++++++++++--- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 2d27fe09f98c8..6f42e707c3535 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -10,7 +10,8 @@ use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; -use rustc_parse::{self, parser, DirectoryOwnership, MACRO_ARGUMENTS}; +use rustc_parse::parser::module::DirectoryOwnership; +use rustc_parse::{self, parser, MACRO_ARGUMENTS}; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind}; diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index bd929f89de034..12528400aa054 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -18,10 +18,11 @@ use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; use rustc_parse::configure; -use rustc_parse::parser::module::{parse_external_mod, push_directory}; +use rustc_parse::parser::module::{ + parse_external_mod, push_directory, Directory, DirectoryOwnership, +}; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; -use rustc_parse::{Directory, DirectoryOwnership}; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index bcaae02942e29..70aa8c0074ae9 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -14,7 +14,7 @@ use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::str; use log::info; @@ -29,22 +29,6 @@ pub mod validate_attr; #[macro_use] pub mod config; -#[derive(Clone)] -pub struct Directory { - pub path: PathBuf, - pub ownership: DirectoryOwnership, -} - -#[derive(Copy, Clone)] -pub enum DirectoryOwnership { - Owned { - // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`. - relative: Option, - }, - UnownedViaBlock, - UnownedViaMod, -} - // 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 diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 2c752bd9f0af7..e45a26bd441a5 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -1,8 +1,7 @@ -use crate::{new_sub_parser_from_file, Directory, DirectoryOwnership}; +use crate::new_sub_parser_from_file; use rustc_ast::ast::{self, Attribute, Ident, Mod}; -use rustc_ast::attr; -use rustc_ast::token; +use rustc_ast::{attr, token}; use rustc_errors::{struct_span_err, PResult}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FileName, Span}; @@ -10,6 +9,22 @@ use rustc_span::symbol::sym; use std::path::{self, Path, PathBuf}; +#[derive(Clone)] +pub struct Directory { + pub path: PathBuf, + pub ownership: DirectoryOwnership, +} + +#[derive(Copy, Clone)] +pub enum DirectoryOwnership { + Owned { + // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`. + relative: Option, + }, + UnownedViaBlock, + UnownedViaMod, +} + /// Information about the path to a module. // Public for rustfmt usage. pub struct ModulePath<'a> { From e8301574b8314be82c53205b7ef97e5c2df19eb9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 22:21:37 +0100 Subject: [PATCH 26/36] {rustc_parse::parser -> rustc_expand}::module --- src/librustc_expand/base.rs | 2 +- src/librustc_expand/expand.rs | 4 +--- src/librustc_expand/lib.rs | 2 ++ src/{librustc_parse/parser => librustc_expand}/module.rs | 7 +++---- src/librustc_parse/parser/mod.rs | 2 -- 5 files changed, 7 insertions(+), 10 deletions(-) rename src/{librustc_parse/parser => librustc_expand}/module.rs (99%) diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 6f42e707c3535..ba11eb95620e9 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -1,4 +1,5 @@ use crate::expand::{self, AstFragment, Invocation}; +use crate::module::DirectoryOwnership; use rustc_ast::ast::{self, Attribute, Name, NodeId, PatKind}; use rustc_ast::mut_visit::{self, MutVisitor}; @@ -10,7 +11,6 @@ use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; -use rustc_parse::parser::module::DirectoryOwnership; use rustc_parse::{self, parser, MACRO_ARGUMENTS}; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 12528400aa054..f31f8a0c4424e 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -2,6 +2,7 @@ use crate::base::*; use crate::config::StripUnconfigured; use crate::hygiene::{ExpnData, ExpnId, ExpnKind, SyntaxContext}; use crate::mbe::macro_rules::annotate_err_with_kind; +use crate::module::{parse_external_mod, push_directory, Directory, DirectoryOwnership}; use crate::placeholders::{placeholder, PlaceholderExpander}; use crate::proc_macro::collect_derives; @@ -18,9 +19,6 @@ use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; use rustc_parse::configure; -use rustc_parse::parser::module::{ - parse_external_mod, push_directory, Directory, DirectoryOwnership, -}; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; diff --git a/src/librustc_expand/lib.rs b/src/librustc_expand/lib.rs index f119c956ced04..98d644eb77af4 100644 --- a/src/librustc_expand/lib.rs +++ b/src/librustc_expand/lib.rs @@ -4,6 +4,7 @@ #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] #![feature(proc_macro_span)] +#![feature(try_blocks)] extern crate proc_macro as pm; @@ -34,6 +35,7 @@ crate use rustc_span::hygiene; pub mod base; pub mod build; pub mod expand; +pub mod module; pub use rustc_parse::config; pub mod proc_macro; diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_expand/module.rs similarity index 99% rename from src/librustc_parse/parser/module.rs rename to src/librustc_expand/module.rs index e45a26bd441a5..1d4c767b84fa3 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_expand/module.rs @@ -1,8 +1,7 @@ -use crate::new_sub_parser_from_file; - use rustc_ast::ast::{self, Attribute, Ident, Mod}; use rustc_ast::{attr, token}; use rustc_errors::{struct_span_err, PResult}; +use rustc_parse::new_sub_parser_from_file; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FileName, Span}; use rustc_span::symbol::sym; @@ -39,7 +38,7 @@ pub struct ModulePathSuccess { pub ownership: DirectoryOwnership, } -pub fn parse_external_mod( +crate fn parse_external_mod( sess: &ParseSess, id: ast::Ident, Directory { mut ownership, path }: Directory, @@ -98,7 +97,7 @@ fn error_on_circular_module<'a>( Ok(()) } -pub fn push_directory( +crate fn push_directory( id: Ident, attrs: &[Attribute], Directory { mut ownership, mut path }: Directory, diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index f4862a6c87b73..bb6793d08aa27 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -1,8 +1,6 @@ pub mod attr; mod expr; mod item; -pub mod module; -pub use module::{ModulePath, ModulePathSuccess}; mod pat; mod path; mod ty; From c16f0d3f4da2c5ca2fdd891c467ca157c1354d1d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 22:32:25 +0100 Subject: [PATCH 27/36] {rustc_parse -> rustc_expand}::config --- src/{librustc_parse => librustc_expand}/config.rs | 14 +++----------- src/librustc_expand/expand.rs | 2 +- src/librustc_expand/lib.rs | 4 +++- src/librustc_parse/lib.rs | 2 -- src/librustc_parse/validate_attr.rs | 2 +- 5 files changed, 8 insertions(+), 16 deletions(-) rename src/{librustc_parse => librustc_expand}/config.rs (97%) diff --git a/src/librustc_parse/config.rs b/src/librustc_expand/config.rs similarity index 97% rename from src/librustc_parse/config.rs rename to src/librustc_expand/config.rs index c611f24942012..72c09f35dfa55 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_expand/config.rs @@ -1,14 +1,5 @@ -//! Process the potential `cfg` attributes on a module. -//! Also determine if the module should be included in this configuration. -//! -//! This module properly belongs in rustc_expand, but for now it's tied into -//! parsing, so we leave it here to avoid complicated out-of-line dependencies. -//! -//! A principled solution to this wrong location would be to implement [#64197]. -//! -//! [#64197]: https://github.com/rust-lang/rust/issues/64197 - -use crate::{parse_in, validate_attr}; +//! Conditional compilation stripping. + use rustc_ast::ast::{self, AttrItem, Attribute, MetaItem}; use rustc_ast::attr::HasAttrs; use rustc_ast::mut_visit::*; @@ -21,6 +12,7 @@ use rustc_feature::{Feature, Features, State as FeatureState}; use rustc_feature::{ ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES, }; +use rustc_parse::{parse_in, validate_attr}; use rustc_session::parse::{feature_err, ParseSess}; use rustc_span::edition::{Edition, ALL_EDITIONS}; use rustc_span::symbol::{sym, Symbol}; diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index f31f8a0c4424e..f2c68923027e6 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -1,5 +1,6 @@ use crate::base::*; use crate::config::StripUnconfigured; +use crate::configure; use crate::hygiene::{ExpnData, ExpnId, ExpnKind, SyntaxContext}; use crate::mbe::macro_rules::annotate_err_with_kind; use crate::module::{parse_external_mod, push_directory, Directory, DirectoryOwnership}; @@ -18,7 +19,6 @@ use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; -use rustc_parse::configure; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; diff --git a/src/librustc_expand/lib.rs b/src/librustc_expand/lib.rs index 98d644eb77af4..0320a275e5d20 100644 --- a/src/librustc_expand/lib.rs +++ b/src/librustc_expand/lib.rs @@ -1,3 +1,4 @@ +#![feature(bool_to_option)] #![feature(cow_is_borrowed)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] @@ -34,9 +35,10 @@ pub use mbe::macro_rules::compile_declarative_macro; crate use rustc_span::hygiene; pub mod base; pub mod build; +#[macro_use] +pub mod config; pub mod expand; pub mod module; -pub use rustc_parse::config; pub mod proc_macro; crate mod mbe; diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 70aa8c0074ae9..a23f74a8894f2 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -26,8 +26,6 @@ pub mod parser; use parser::{emit_unclosed_delims, make_unclosed_delims_error, Parser}; pub mod lexer; pub mod validate_attr; -#[macro_use] -pub mod config; // A bunch of utility functions of the form `parse__from_` // where includes crate, expr, item, stmt, tts, and one that diff --git a/src/librustc_parse/validate_attr.rs b/src/librustc_parse/validate_attr.rs index 029aa5ed2baea..2512878ec65be 100644 --- a/src/librustc_parse/validate_attr.rs +++ b/src/librustc_parse/validate_attr.rs @@ -57,7 +57,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta }) } -crate fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) { +pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) { if let ast::MacDelimiter::Parenthesis = delim { return; } From 24543957ce663430dd59aebd550f190ea9802791 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 22:48:24 +0100 Subject: [PATCH 28/36] add test for stripped nested outline module --- .../ui/parser/stripped-nested-outline-mod-pass.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/test/ui/parser/stripped-nested-outline-mod-pass.rs diff --git a/src/test/ui/parser/stripped-nested-outline-mod-pass.rs b/src/test/ui/parser/stripped-nested-outline-mod-pass.rs new file mode 100644 index 0000000000000..1b4669a439ffe --- /dev/null +++ b/src/test/ui/parser/stripped-nested-outline-mod-pass.rs @@ -0,0 +1,13 @@ +// Expansion drives parsing, so conditional compilation will strip +// out outline modules and we will never attempt parsing them. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +mod foo { + mod bar { + mod baz; // This was an error before. + } +} From ed9d81ed77e837ca1a2cd07dc489f895d60b1951 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 9 Mar 2020 10:35:35 +0100 Subject: [PATCH 29/36] parser/expand: minor cleanup --- src/librustc_expand/mbe/macro_rules.rs | 4 ++-- src/librustc_parse/lib.rs | 15 --------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index e75547916cefb..5e219f0d4794b 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -258,7 +258,7 @@ fn generic_extension<'cx>( trace_macros_note(&mut cx.expansions, sp, msg); } - let mut p = Parser::new(cx.parse_sess(), tts, false, None); + let mut p = Parser::new(sess, tts, false, None); p.root_module_name = cx.current_expansion.module.mod_path.last().map(|id| id.to_string()); p.last_type_ascription = cx.current_expansion.prior_type_ascription; @@ -1204,7 +1204,7 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { } } -fn parser_from_cx<'cx>(sess: &'cx ParseSess, tts: TokenStream) -> Parser<'cx> { +fn parser_from_cx(sess: &ParseSess, tts: TokenStream) -> Parser<'_> { Parser::new(sess, tts, true, rustc_parse::MACRO_ARGUMENTS) } diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index a23f74a8894f2..c31cc1b4c9f00 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -238,21 +238,6 @@ pub fn stream_to_parser<'a>( Parser::new(sess, stream, false, subparser_name) } -/// Given a stream, the `ParseSess` and the base directory, produces a parser. -/// -/// Use this function when you are creating a parser from the token stream -/// and also care about the current working directory of the parser (e.g., -/// you are trying to resolve modules defined inside a macro invocation). -/// -/// # Note -/// -/// The main usage of this function is outside of rustc, for those who uses -/// librustc_ast as a library. Please do not remove this function while refactoring -/// just because it is not used in rustc codebase! -pub fn stream_to_parser_with_base_dir(sess: &ParseSess, stream: TokenStream) -> Parser<'_> { - Parser::new(sess, stream, false, None) -} - /// Runs the given subparser `f` on the tokens of the given `attr`'s item. pub fn parse_in<'a, T>( sess: &'a ParseSess, From 9741bb6c3c9e201cfd679040a8813167029d0262 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 9 Mar 2020 11:16:00 +0100 Subject: [PATCH 30/36] tweak outline module parsing spans --- src/librustc_expand/expand.rs | 9 ++--- src/librustc_expand/module.rs | 40 ++++++++++--------- src/librustc_parse/parser/item.rs | 2 +- .../directory_ownership/macro-expanded-mod.rs | 4 +- .../macro-expanded-mod.stderr | 9 ++++- .../non-inline-mod-restriction.stderr | 4 +- src/test/ui/error-codes/E0583.stderr | 4 +- .../invalid-module-declaration.stderr | 4 +- .../missing_non_modrs_mod.stderr | 4 +- .../missing_non_modrs_mod_inline.stderr | 4 +- src/test/ui/mod/mod_file_disambig.stderr | 4 +- .../ui/parser/circular_modules_main.stderr | 4 +- src/test/ui/parser/issue-5806.stderr | 4 +- src/test/ui/parser/mod_file_not_exist.stderr | 4 +- .../ui/parser/mod_file_with_path_attr.stderr | 4 +- 15 files changed, 55 insertions(+), 49 deletions(-) diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index f2c68923027e6..4e84964436004 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -1368,6 +1368,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck. let ident = item.ident; + let span = item.span; match item.kind { ast::ItemKind::MacCall(..) => { @@ -1375,10 +1376,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.check_attributes(&item.attrs); item.and_then(|item| match item.kind { ItemKind::MacCall(mac) => self - .collect( - AstFragmentKind::Items, - InvocationKind::Bang { mac, span: item.span }, - ) + .collect(AstFragmentKind::Items, InvocationKind::Bang { mac, span }) .make_items(), _ => unreachable!(), }) @@ -1396,7 +1394,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { push_directory(ident, &item.attrs, dir) } else { // We have an outline `mod foo;` so we need to parse the file. - let (new_mod, dir) = parse_external_mod(sess, ident, dir, &mut attrs, pushed); + let (new_mod, dir) = + parse_external_mod(sess, ident, span, dir, &mut attrs, pushed); *old_mod = new_mod; item.attrs = attrs; // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure. diff --git a/src/librustc_expand/module.rs b/src/librustc_expand/module.rs index 1d4c767b84fa3..2d5e4d4e8894d 100644 --- a/src/librustc_expand/module.rs +++ b/src/librustc_expand/module.rs @@ -41,6 +41,7 @@ pub struct ModulePathSuccess { crate fn parse_external_mod( sess: &ParseSess, id: ast::Ident, + span: Span, // The span to blame on errors. Directory { mut ownership, path }: Directory, attrs: &mut Vec, pop_mod_stack: &mut bool, @@ -48,18 +49,18 @@ crate fn parse_external_mod( // We bail on the first error, but that error does not cause a fatal error... (1) let result: PResult<'_, _> = try { // Extract the file path and the new ownership. - let mp = submod_path(sess, id, &attrs, ownership, &path)?; + let mp = submod_path(sess, id, span, &attrs, ownership, &path)?; ownership = mp.ownership; // Ensure file paths are acyclic. let mut included_mod_stack = sess.included_mod_stack.borrow_mut(); - error_on_circular_module(sess, id.span, &mp.path, &included_mod_stack)?; + error_on_circular_module(sess, span, &mp.path, &included_mod_stack)?; included_mod_stack.push(mp.path.clone()); *pop_mod_stack = true; // We have pushed, so notify caller. drop(included_mod_stack); // Actually parse the external file as amodule. - let mut p0 = new_sub_parser_from_file(sess, &mp.path, Some(id.to_string()), id.span); + let mut p0 = new_sub_parser_from_file(sess, &mp.path, Some(id.to_string()), span); let mut module = p0.parse_mod(&token::Eof)?; module.0.inline = false; module @@ -126,6 +127,7 @@ crate fn push_directory( fn submod_path<'a>( sess: &'a ParseSess, id: ast::Ident, + span: Span, attrs: &[Attribute], ownership: DirectoryOwnership, dir_path: &Path, @@ -150,54 +152,53 @@ fn submod_path<'a>( DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None, }; let ModulePath { path_exists, name, result } = - default_submod_path(sess, id, relative, dir_path); + default_submod_path(sess, id, span, relative, dir_path); match ownership { DirectoryOwnership::Owned { .. } => Ok(result?), DirectoryOwnership::UnownedViaBlock => { let _ = result.map_err(|mut err| err.cancel()); - error_decl_mod_in_block(sess, id.span, path_exists, &name) + error_decl_mod_in_block(sess, span, path_exists, &name) } DirectoryOwnership::UnownedViaMod => { let _ = result.map_err(|mut err| err.cancel()); - error_cannot_declare_mod_here(sess, id.span, path_exists, &name) + error_cannot_declare_mod_here(sess, span, path_exists, &name) } } } fn error_decl_mod_in_block<'a, T>( sess: &'a ParseSess, - id_sp: Span, + span: Span, path_exists: bool, name: &str, ) -> PResult<'a, T> { let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute"; - let mut err = sess.span_diagnostic.struct_span_err(id_sp, msg); + let mut err = sess.span_diagnostic.struct_span_err(span, msg); if path_exists { let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name); - err.span_note(id_sp, &msg); + err.span_note(span, &msg); } Err(err) } fn error_cannot_declare_mod_here<'a, T>( sess: &'a ParseSess, - id_sp: Span, + span: Span, path_exists: bool, name: &str, ) -> PResult<'a, T> { let mut err = - sess.span_diagnostic.struct_span_err(id_sp, "cannot declare a new module at this location"); - if !id_sp.is_dummy() { - if let FileName::Real(src_path) = sess.source_map().span_to_filename(id_sp) { + sess.span_diagnostic.struct_span_err(span, "cannot declare a new module at this location"); + if !span.is_dummy() { + if let FileName::Real(src_path) = sess.source_map().span_to_filename(span) { if let Some(stem) = src_path.file_stem() { let mut dest_path = src_path.clone(); dest_path.set_file_name(stem); dest_path.push("mod.rs"); err.span_note( - id_sp, + span, &format!( - "maybe move this module `{}` to its own \ - directory via `{}`", + "maybe move this module `{}` to its own directory via `{}`", src_path.display(), dest_path.display() ), @@ -207,7 +208,7 @@ fn error_cannot_declare_mod_here<'a, T>( } if path_exists { err.span_note( - id_sp, + span, &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name), ); } @@ -237,6 +238,7 @@ pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option( sess: &'a ParseSess, id: ast::Ident, + span: Span, relative: Option, dir_path: &Path, ) -> ModulePath<'a> { @@ -273,7 +275,7 @@ pub fn default_submod_path<'a>( (false, false) => { let mut err = struct_span_err!( sess.span_diagnostic, - id.span, + span, E0583, "file not found for module `{}`", mod_name, @@ -288,7 +290,7 @@ pub fn default_submod_path<'a>( (true, true) => { let mut err = struct_span_err!( sess.span_diagnostic, - id.span, + span, E0584, "file for module `{}` found at both {} and {}", mod_name, diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index d0da8e6c7c11e..873b7e93c6f6b 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -38,7 +38,7 @@ impl<'a> Parser<'a> { } /// Parses a `mod { ... }` or `mod ;` item. - pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { + fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { let id = self.parse_ident()?; let (module, mut inner_attrs) = if self.eat(&token::Semi) { Default::default() diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.rs b/src/test/ui/directory_ownership/macro-expanded-mod.rs index 1066a2ba71209..9cb159603a8c5 100644 --- a/src/test/ui/directory_ownership/macro-expanded-mod.rs +++ b/src/test/ui/directory_ownership/macro-expanded-mod.rs @@ -2,7 +2,7 @@ macro_rules! mod_decl { ($i:ident) => { - mod $i; + mod $i; //~ ERROR Cannot declare a non-inline module inside a block }; } @@ -11,5 +11,5 @@ mod macro_expanded_mod_helper { } fn main() { - mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block + mod_decl!(foo); } diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.stderr b/src/test/ui/directory_ownership/macro-expanded-mod.stderr index d9d8a8ffed751..f90419247c92b 100644 --- a/src/test/ui/directory_ownership/macro-expanded-mod.stderr +++ b/src/test/ui/directory_ownership/macro-expanded-mod.stderr @@ -1,8 +1,13 @@ error: Cannot declare a non-inline module inside a block unless it has a path attribute - --> $DIR/macro-expanded-mod.rs:14:15 + --> $DIR/macro-expanded-mod.rs:5:9 | +LL | mod $i; + | ^^^^^^^ +... LL | mod_decl!(foo); - | ^^^ + | --------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr b/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr index 46acc7e66d8b8..d034942ca5d4c 100644 --- a/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr +++ b/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr @@ -1,8 +1,8 @@ error: Cannot declare a non-inline module inside a block unless it has a path attribute - --> $DIR/non-inline-mod-restriction.rs:4:9 + --> $DIR/non-inline-mod-restriction.rs:4:5 | LL | mod foo; - | ^^^ + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0583.stderr b/src/test/ui/error-codes/E0583.stderr index 5d47b633e78db..dbe700355957b 100644 --- a/src/test/ui/error-codes/E0583.stderr +++ b/src/test/ui/error-codes/E0583.stderr @@ -1,8 +1,8 @@ error[E0583]: file not found for module `module_that_doesnt_exist` - --> $DIR/E0583.rs:1:5 + --> $DIR/E0583.rs:1:1 | LL | mod module_that_doesnt_exist; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs" diff --git a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr index 5d2cdaef1a761..52296042eb4a7 100644 --- a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr +++ b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr @@ -1,8 +1,8 @@ error[E0583]: file not found for module `baz` - --> $DIR/auxiliary/foo/bar.rs:1:9 + --> $DIR/auxiliary/foo/bar.rs:1:1 | LL | pub mod baz; - | ^^^ + | ^^^^^^^^^^^^ | = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs" diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr index e8d997e6de091..91b3fe15c4be7 100644 --- a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr +++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr @@ -1,8 +1,8 @@ error[E0583]: file not found for module `missing` - --> $DIR/foo.rs:4:5 + --> $DIR/foo.rs:4:1 | LL | mod missing; - | ^^^^^^^ + | ^^^^^^^^^^^^ | = help: to create the module `missing`, create file "$DIR/foo/missing.rs" diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr index b2b0f8b466a04..f519de46c767f 100644 --- a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr +++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr @@ -1,8 +1,8 @@ error[E0583]: file not found for module `missing` - --> $DIR/foo_inline.rs:4:9 + --> $DIR/foo_inline.rs:4:5 | LL | mod missing; - | ^^^^^^^ + | ^^^^^^^^^^^^ | = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs" diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr index 230bfa79916df..490633a3fb0ab 100644 --- a/src/test/ui/mod/mod_file_disambig.stderr +++ b/src/test/ui/mod/mod_file_disambig.stderr @@ -1,8 +1,8 @@ error[E0584]: file for module `mod_file_disambig_aux` found at both mod_file_disambig_aux.rs and mod_file_disambig_aux/mod.rs - --> $DIR/mod_file_disambig.rs:1:5 + --> $DIR/mod_file_disambig.rs:1:1 | LL | mod mod_file_disambig_aux; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: delete or rename one of them to remove the ambiguity diff --git a/src/test/ui/parser/circular_modules_main.stderr b/src/test/ui/parser/circular_modules_main.stderr index ca84f2d285403..90f81c64835b7 100644 --- a/src/test/ui/parser/circular_modules_main.stderr +++ b/src/test/ui/parser/circular_modules_main.stderr @@ -1,8 +1,8 @@ error: circular modules: $DIR/circular_modules_hello.rs -> $DIR/circular_modules_main.rs -> $DIR/circular_modules_hello.rs - --> $DIR/circular_modules_main.rs:2:5 + --> $DIR/circular_modules_main.rs:2:1 | LL | mod circular_modules_hello; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `say_hello` in module `circular_modules_hello` --> $DIR/circular_modules_main.rs:9:29 diff --git a/src/test/ui/parser/issue-5806.stderr b/src/test/ui/parser/issue-5806.stderr index 6cf902ca86e79..bdb5c91ff91eb 100644 --- a/src/test/ui/parser/issue-5806.stderr +++ b/src/test/ui/parser/issue-5806.stderr @@ -1,8 +1,8 @@ error: couldn't read $DIR/../parser: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) - --> $DIR/issue-5806.rs:5:5 + --> $DIR/issue-5806.rs:5:1 | LL | mod foo; - | ^^^ + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr index c298c51c4f870..087ae9fe3e016 100644 --- a/src/test/ui/parser/mod_file_not_exist.stderr +++ b/src/test/ui/parser/mod_file_not_exist.stderr @@ -1,8 +1,8 @@ error[E0583]: file not found for module `not_a_real_file` - --> $DIR/mod_file_not_exist.rs:3:5 + --> $DIR/mod_file_not_exist.rs:3:1 | LL | mod not_a_real_file; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" diff --git a/src/test/ui/parser/mod_file_with_path_attr.stderr b/src/test/ui/parser/mod_file_with_path_attr.stderr index 004b5d7963a1d..cd1add73d5840 100644 --- a/src/test/ui/parser/mod_file_with_path_attr.stderr +++ b/src/test/ui/parser/mod_file_with_path_attr.stderr @@ -1,8 +1,8 @@ error: couldn't read $DIR/not_a_real_file.rs: $FILE_NOT_FOUND_MSG (os error 2) - --> $DIR/mod_file_with_path_attr.rs:4:5 + --> $DIR/mod_file_with_path_attr.rs:4:1 | LL | mod m; - | ^ + | ^^^^^^ error: aborting due to previous error From 48b8ecce62e16ae221ef52f38658607a50251a50 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 10 Mar 2020 07:21:40 +0100 Subject: [PATCH 31/36] use pretty-compare-only in a test --- src/test/pretty/issue-12590-a.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/pretty/issue-12590-a.rs b/src/test/pretty/issue-12590-a.rs index 1a9e85c42d8fb..ca1fef83cffc5 100644 --- a/src/test/pretty/issue-12590-a.rs +++ b/src/test/pretty/issue-12590-a.rs @@ -1,4 +1,5 @@ // pp-exact +// pretty-compare-only // The next line should not be expanded From 998b33ee0d37ea719717e4d6bed2a1f6cef0d071 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 16 Mar 2020 00:43:37 +0100 Subject: [PATCH 32/36] fix pre-expansion linting infra --- src/libpanic_unwind/emcc.rs | 2 -- src/libpanic_unwind/gcc.rs | 2 -- src/libpanic_unwind/seh.rs | 1 - .../proc_macro_harness.rs | 2 +- .../standard_library_imports.rs | 2 +- src/librustc_builtin_macros/test_harness.rs | 2 +- src/librustc_expand/base.rs | 6 ++++- src/librustc_expand/expand.rs | 15 ++++++++++-- src/librustc_interface/passes.rs | 23 +++++++++++-------- src/librustc_lint/early.rs | 18 ++++----------- .../change_symbol_export_status.rs | 6 ++--- .../auxiliary/linkage-visibility.rs | 12 ++++------ .../lint/lint-pre-expansion-extern-module.rs | 7 ++++++ .../lint-pre-expansion-extern-module.stderr | 10 ++++++++ .../lint_pre_expansion_extern_module_aux.rs | 3 +++ 15 files changed, 67 insertions(+), 44 deletions(-) create mode 100644 src/test/ui/lint/lint-pre-expansion-extern-module.rs create mode 100644 src/test/ui/lint/lint-pre-expansion-extern-module.stderr create mode 100644 src/test/ui/lint/lint_pre_expansion_extern_module_aux.rs diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs index c7144fe16cdda..a0bdb1481c6b2 100644 --- a/src/libpanic_unwind/emcc.rs +++ b/src/libpanic_unwind/emcc.rs @@ -6,8 +6,6 @@ //! Emscripten's runtime always implements those APIs and does not //! implement libunwind. -#![allow(private_no_mangle_fns)] - use alloc::boxed::Box; use core::any::Any; use core::mem; diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 9c032b30341e9..1622442a5eb45 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -36,8 +36,6 @@ //! Once stack has been unwound down to the handler frame level, unwinding stops //! and the last personality routine transfers control to the catch block. -#![allow(private_no_mangle_fns)] - use alloc::boxed::Box; use core::any::Any; diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs index c294fe26327d7..10b765a5b411b 100644 --- a/src/libpanic_unwind/seh.rs +++ b/src/libpanic_unwind/seh.rs @@ -45,7 +45,6 @@ //! [llvm]: http://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions #![allow(nonstandard_style)] -#![allow(private_no_mangle_fns)] use alloc::boxed::Box; use core::any::Any; diff --git a/src/librustc_builtin_macros/proc_macro_harness.rs b/src/librustc_builtin_macros/proc_macro_harness.rs index 179b013342633..71622a3b7e657 100644 --- a/src/librustc_builtin_macros/proc_macro_harness.rs +++ b/src/librustc_builtin_macros/proc_macro_harness.rs @@ -59,7 +59,7 @@ pub fn inject( handler: &rustc_errors::Handler, ) -> ast::Crate { let ecfg = ExpansionConfig::default("proc_macro".to_string()); - let mut cx = ExtCtxt::new(sess, ecfg, resolver); + let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); let mut collect = CollectProcMacros { macros: Vec::new(), diff --git a/src/librustc_builtin_macros/standard_library_imports.rs b/src/librustc_builtin_macros/standard_library_imports.rs index 30403f6dc41c1..f48fd6df9c98b 100644 --- a/src/librustc_builtin_macros/standard_library_imports.rs +++ b/src/librustc_builtin_macros/standard_library_imports.rs @@ -39,7 +39,7 @@ pub fn inject( let call_site = DUMMY_SP.with_call_site_ctxt(expn_id); let ecfg = ExpansionConfig::default("std_lib_injection".to_string()); - let cx = ExtCtxt::new(sess, ecfg, resolver); + let cx = ExtCtxt::new(sess, ecfg, resolver, None); // .rev() to preserve ordering above in combination with insert(0, ...) for &name in names.iter().rev() { diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs index 15997a27fadf2..b87767f4a4127 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/src/librustc_builtin_macros/test_harness.rs @@ -202,7 +202,7 @@ fn generate_test_harness( let mut econfig = ExpansionConfig::default("test".to_string()); econfig.features = Some(features); - let ext_cx = ExtCtxt::new(sess, econfig, resolver); + let ext_cx = ExtCtxt::new(sess, econfig, resolver, None); let expn_id = ext_cx.resolver.expansion_for_ast_pass( DUMMY_SP, diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index ba11eb95620e9..2c68eac73fe1f 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -923,6 +923,8 @@ pub struct ExtCtxt<'a> { pub resolver: &'a mut dyn Resolver, pub current_expansion: ExpansionData, pub expansions: FxHashMap>, + /// Called directly after having parsed an external `mod foo;` in expansion. + pub(super) extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>, } impl<'a> ExtCtxt<'a> { @@ -930,12 +932,14 @@ impl<'a> ExtCtxt<'a> { parse_sess: &'a ParseSess, ecfg: expand::ExpansionConfig<'a>, resolver: &'a mut dyn Resolver, + extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>, ) -> ExtCtxt<'a> { ExtCtxt { parse_sess, ecfg, - root_path: PathBuf::new(), resolver, + extern_mod_loaded, + root_path: PathBuf::new(), current_expansion: ExpansionData { id: ExpnId::root(), depth: 0, diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 4e84964436004..fce3fe0f2d02b 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -1396,8 +1396,19 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { // We have an outline `mod foo;` so we need to parse the file. let (new_mod, dir) = parse_external_mod(sess, ident, span, dir, &mut attrs, pushed); - *old_mod = new_mod; - item.attrs = attrs; + + let krate = ast::Crate { + span: new_mod.inner, + module: new_mod, + attrs, + proc_macros: vec![], + }; + if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded { + extern_mod_loaded(&krate); + } + + *old_mod = krate.module; + item.attrs = krate.attrs; // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure. item = match self.configure(item) { Some(node) => node, diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 4fe7a06e5609e..93f0beaa48be8 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -210,14 +210,7 @@ pub fn register_plugins<'a>( Ok((krate, Lrc::new(lint_store))) } -fn configure_and_expand_inner<'a>( - sess: &'a Session, - lint_store: &'a LintStore, - mut krate: ast::Crate, - crate_name: &str, - resolver_arenas: &'a ResolverArenas<'a>, - metadata_loader: &'a MetadataLoaderDyn, -) -> Result<(ast::Crate, Resolver<'a>)> { +fn pre_expansion_lint(sess: &Session, lint_store: &LintStore, krate: &ast::Crate) { sess.time("pre_AST_expansion_lint_checks", || { rustc_lint::check_ast_crate( sess, @@ -228,6 +221,17 @@ fn configure_and_expand_inner<'a>( rustc_lint::BuiltinCombinedPreExpansionLintPass::new(), ); }); +} + +fn configure_and_expand_inner<'a>( + sess: &'a Session, + lint_store: &'a LintStore, + mut krate: ast::Crate, + crate_name: &str, + resolver_arenas: &'a ResolverArenas<'a>, + metadata_loader: &'a MetadataLoaderDyn, +) -> Result<(ast::Crate, Resolver<'a>)> { + pre_expansion_lint(sess, lint_store, &krate); let mut resolver = Resolver::new(sess, &krate, crate_name, metadata_loader, &resolver_arenas); rustc_builtin_macros::register_builtin_macros(&mut resolver, sess.edition()); @@ -291,7 +295,8 @@ fn configure_and_expand_inner<'a>( ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) }; - let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver); + let extern_mod_loaded = |k: &ast::Crate| pre_expansion_lint(sess, lint_store, k); + let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver, Some(&extern_mod_loaded)); // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); diff --git a/src/librustc_lint/early.rs b/src/librustc_lint/early.rs index a5da960d8881c..34da29c974777 100644 --- a/src/librustc_lint/early.rs +++ b/src/librustc_lint/early.rs @@ -18,7 +18,7 @@ use crate::context::{EarlyContext, LintContext, LintStore}; use crate::passes::{EarlyLintPass, EarlyLintPassObject}; use rustc_ast::ast; use rustc_ast::visit as ast_visit; -use rustc_session::lint::{LintBuffer, LintPass}; +use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_session::Session; use rustc_span::Span; @@ -37,13 +37,7 @@ struct EarlyContextAndPass<'a, T: EarlyLintPass> { impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { fn check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { - let rustc_session::lint::BufferedEarlyLint { - span, - msg, - node_id: _, - lint_id, - diagnostic, - } = early_lint; + let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint; self.context.lookup_with_diagnostics( lint_id.lint, Some(span), @@ -326,11 +320,9 @@ pub fn check_ast_crate( lint_buffer: Option, builtin_lints: T, ) { - let mut passes: Vec<_> = if pre_expansion { - lint_store.pre_expansion_passes.iter().map(|p| (p)()).collect() - } else { - lint_store.early_passes.iter().map(|p| (p)()).collect() - }; + let passes = + if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes }; + let mut passes: Vec<_> = passes.iter().map(|p| (p)()).collect(); let mut buffered = lint_buffer.unwrap_or_default(); if !sess.opts.debugging_opts.no_interleave_lints { diff --git a/src/test/incremental/change_symbol_export_status.rs b/src/test/incremental/change_symbol_export_status.rs index f3de46d99ddc0..9b3b381d6210a 100644 --- a/src/test/incremental/change_symbol_export_status.rs +++ b/src/test/incremental/change_symbol_export_status.rs @@ -2,10 +2,8 @@ // compile-flags: -Zquery-dep-graph #![feature(rustc_attrs)] -#![allow(private_no_mangle_fns)] - -#![rustc_partition_codegened(module="change_symbol_export_status-mod1", cfg="rpass2")] -#![rustc_partition_reused(module="change_symbol_export_status-mod2", cfg="rpass2")] +#![rustc_partition_codegened(module = "change_symbol_export_status-mod1", cfg = "rpass2")] +#![rustc_partition_reused(module = "change_symbol_export_status-mod2", cfg = "rpass2")] // This test case makes sure that a change in symbol visibility is detected by // our dependency tracking. We do this by changing a module's visibility to diff --git a/src/test/ui-fulldeps/auxiliary/linkage-visibility.rs b/src/test/ui-fulldeps/auxiliary/linkage-visibility.rs index 8917693d45eeb..837ed1f002fc9 100644 --- a/src/test/ui-fulldeps/auxiliary/linkage-visibility.rs +++ b/src/test/ui-fulldeps/auxiliary/linkage-visibility.rs @@ -2,16 +2,14 @@ #![feature(rustc_private)] -// We're testing linkage visibility; the compiler warns us, but we want to -// do the runtime check that these functions aren't exported. -#![allow(private_no_mangle_fns)] - extern crate rustc_metadata; use rustc_metadata::dynamic_lib::DynamicLibrary; #[no_mangle] -pub fn foo() { bar(); } +pub fn foo() { + bar(); +} pub fn foo2() { fn bar2() { @@ -21,11 +19,11 @@ pub fn foo2() { } #[no_mangle] -fn bar() { } +fn bar() {} #[allow(dead_code)] #[no_mangle] -fn baz() { } +fn baz() {} pub fn test() { let lib = DynamicLibrary::open(None).unwrap(); diff --git a/src/test/ui/lint/lint-pre-expansion-extern-module.rs b/src/test/ui/lint/lint-pre-expansion-extern-module.rs new file mode 100644 index 0000000000000..30e2ed8b7a623 --- /dev/null +++ b/src/test/ui/lint/lint-pre-expansion-extern-module.rs @@ -0,0 +1,7 @@ +// check-pass +// compile-flags: -W rust-2018-compatibility +// error-pattern: `try` is a keyword in the 2018 edition + +fn main() {} + +mod lint_pre_expansion_extern_module_aux; diff --git a/src/test/ui/lint/lint-pre-expansion-extern-module.stderr b/src/test/ui/lint/lint-pre-expansion-extern-module.stderr new file mode 100644 index 0000000000000..c683a3fa670ae --- /dev/null +++ b/src/test/ui/lint/lint-pre-expansion-extern-module.stderr @@ -0,0 +1,10 @@ +warning: `try` is a keyword in the 2018 edition + --> $DIR/lint_pre_expansion_extern_module_aux.rs:3:8 + | +LL | pub fn try() {} + | ^^^ help: you can use a raw identifier to stay compatible: `r#try` + | + = note: `-W keyword-idents` implied by `-W rust-2018-compatibility` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + diff --git a/src/test/ui/lint/lint_pre_expansion_extern_module_aux.rs b/src/test/ui/lint/lint_pre_expansion_extern_module_aux.rs new file mode 100644 index 0000000000000..71dec40ea44f0 --- /dev/null +++ b/src/test/ui/lint/lint_pre_expansion_extern_module_aux.rs @@ -0,0 +1,3 @@ +// ignore-test: not a test + +pub fn try() {} From 5cc4e941b36fd300c6a289da32fc42022ae55d27 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 16 Mar 2020 00:56:27 +0100 Subject: [PATCH 33/36] fix rebase fallout --- src/librustc_parse/parser/item.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 873b7e93c6f6b..9d70f606f3ef4 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -6,14 +6,11 @@ use crate::maybe_whole; use rustc_ast::ast::{self, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind, Mod}; -use rustc_ast::ast::{ - Async, Const, Defaultness, IsAuto, PathSegment, Unsafe, UseTree, UseTreeKind, -}; -use rustc_ast::ast::{ - BindingMode, Block, FnDecl, FnSig, MacArgs, MacCall, MacDelimiter, Param, SelfKind, -}; +use rustc_ast::ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; +use rustc_ast::ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind}; use rustc_ast::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData}; -use rustc_ast::ast::{FnHeader, ForeignItem, Mutability, SelfKind, Visibility, VisibilityKind}; +use rustc_ast::ast::{FnHeader, ForeignItem, PathSegment, Visibility, VisibilityKind}; +use rustc_ast::ast::{MacArgs, MacCall, MacDelimiter}; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; From 442e5ff982433ca23f47234a6d7e16358b26505e Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Mon, 16 Mar 2020 21:24:47 -0400 Subject: [PATCH 34/36] Small fixes in documentation typo fix + markdown fix for consistency --- src/librustc_mir/interpret/eval_context.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 482c143a73ee2..450e6b2e2d611 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -98,10 +98,10 @@ pub enum StackPopCleanup { /// Jump to the next block in the caller, or cause UB if None (that's a function /// that may never return). Also store layout of return place so /// we can validate it at that layout. - /// `ret` stores the block we jump to on a normal return, while 'unwind' - /// stores the block used for cleanup during unwinding + /// `ret` stores the block we jump to on a normal return, while `unwind` + /// stores the block used for cleanup during unwinding. Goto { ret: Option, unwind: Option }, - /// Just do nohing: Used by Main and for the box_alloc hook in miri. + /// Just do nothing: Used by Main and for the `box_alloc` hook in miri. /// `cleanup` says whether locals are deallocated. Static computation /// wants them leaked to intern what they need (and just throw away /// the entire `ecx` when it is done). From 194de274d32215bba9364a6185ee8b9896c95295 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 16 Mar 2020 19:09:54 -0700 Subject: [PATCH 35/36] Update books --- src/doc/embedded-book | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/embedded-book b/src/doc/embedded-book index b81ffb7a6f4c5..d22a9c487c780 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit b81ffb7a6f4c5aaed92786e770e99db116aa4ebd +Subproject commit d22a9c487c78095afc4584f1d9b4ec43529d713c diff --git a/src/doc/reference b/src/doc/reference index 559e09caa9661..e2f11fe4d6a5e 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 559e09caa9661043744cf7af7bd88432d966f743 +Subproject commit e2f11fe4d6a5ecb471c70323197da43c70cb96b6 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index db57f899ea2a5..cb369ae95ca36 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit db57f899ea2a56a544c8d280cbf033438666273d +Subproject commit cb369ae95ca36b841960182d26f6d5d9b2e3cc18 From 8b0698bc838a67769d37f514ff8fe100b6e46ebb Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 17 Mar 2020 04:39:22 +0100 Subject: [PATCH 36/36] --bless windows test --- src/test/ui/parser/mod_file_not_exist.rs | 2 +- src/test/ui/parser/mod_file_not_exist_windows.rs | 1 + .../ui/parser/mod_file_not_exist_windows.stderr | 13 ++++++++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/test/ui/parser/mod_file_not_exist.rs b/src/test/ui/parser/mod_file_not_exist.rs index aee778d1013a9..f4a27b52ec5b4 100644 --- a/src/test/ui/parser/mod_file_not_exist.rs +++ b/src/test/ui/parser/mod_file_not_exist.rs @@ -1,7 +1,7 @@ // ignore-windows mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` -//~^ HELP to create the module `not_a_real_file`, create file " +//~^ HELP to create the module `not_a_real_file`, create file fn main() { assert_eq!(mod_file_aux::bar(), 10); diff --git a/src/test/ui/parser/mod_file_not_exist_windows.rs b/src/test/ui/parser/mod_file_not_exist_windows.rs index 97cadab675f51..4b7d7a02bbe78 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.rs +++ b/src/test/ui/parser/mod_file_not_exist_windows.rs @@ -5,4 +5,5 @@ mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` fn main() { assert_eq!(mod_file_aux::bar(), 10); + //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist_windows.stderr b/src/test/ui/parser/mod_file_not_exist_windows.stderr index a58db80f73d7d..690f38bb8a970 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.stderr +++ b/src/test/ui/parser/mod_file_not_exist_windows.stderr @@ -2,10 +2,17 @@ error[E0583]: file not found for module `not_a_real_file` --> $DIR/mod_file_not_exist_windows.rs:3:5 | LL | mod not_a_real_file; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error: aborting due to previous error +error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` + --> $DIR/mod_file_not_exist_windows.rs:7:16 + | +LL | assert_eq!(mod_file_aux::bar(), 10); + | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0583`. +Some errors have detailed explanations: E0433, E0583. +For more information about an error, try `rustc --explain E0433`.