From d1a541e34290364681550e82fe606d21c7235345 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 14 Feb 2021 11:31:33 +0100 Subject: [PATCH 01/14] Add tests for Atomic*::fetch_{min,max} --- library/core/tests/atomic.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index 2d1e4496aeef7..762642aecdab6 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -59,6 +59,24 @@ fn uint_xor() { assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f); } +#[test] +fn uint_min() { + let x = AtomicUsize::new(0xf731); + assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0x137f); + assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f); + assert_eq!(x.load(SeqCst), 0x137f); +} + +#[test] +fn uint_max() { + let x = AtomicUsize::new(0x137f); + assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); + assert_eq!(x.load(SeqCst), 0xf731); + assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0xf731); +} + #[test] fn int_and() { let x = AtomicIsize::new(0xf731); @@ -87,6 +105,24 @@ fn int_xor() { assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f); } +#[test] +fn int_min() { + let x = AtomicIsize::new(0xf731); + assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0x137f); + assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f); + assert_eq!(x.load(SeqCst), 0x137f); +} + +#[test] +fn int_max() { + let x = AtomicIsize::new(0x137f); + assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); + assert_eq!(x.load(SeqCst), 0xf731); + assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0xf731); +} + static S_FALSE: AtomicBool = AtomicBool::new(false); static S_TRUE: AtomicBool = AtomicBool::new(true); static S_INT: AtomicIsize = AtomicIsize::new(0); From c28d86c53b94e475fc3ea707c3289acce253f091 Mon Sep 17 00:00:00 2001 From: Gus Wynn Date: Thu, 28 Jan 2021 18:16:52 -0800 Subject: [PATCH 02/14] name async generators something more human friendly in type error diagnostics --- compiler/rustc_hir/src/hir.rs | 23 ++++++++- .../src/infer/error_reporting/mod.rs | 16 +++--- .../infer/error_reporting/need_type_info.rs | 2 +- compiler/rustc_middle/src/ty/error.rs | 6 +-- .../src/traits/error_reporting/mod.rs | 4 +- .../rustc_typeck/src/check/method/suggest.rs | 4 +- src/test/ui/async-await/generator-desc.rs | 16 ++++++ src/test/ui/async-await/generator-desc.stderr | 49 +++++++++++++++++++ 8 files changed, 103 insertions(+), 17 deletions(-) create mode 100644 src/test/ui/async-await/generator-desc.rs create mode 100644 src/test/ui/async-await/generator-desc.stderr diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 35170fa7c1d02..e5829b1c4f713 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1274,7 +1274,7 @@ impl Body<'hir> { } /// The type of source expression that caused this generator to be created. -#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)] +#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)] pub enum GeneratorKind { /// An explicit `async` block or the body of an async function. Async(AsyncGeneratorKind), @@ -1292,12 +1292,21 @@ impl fmt::Display for GeneratorKind { } } +impl GeneratorKind { + pub fn descr(&self) -> &'static str { + match self { + GeneratorKind::Async(ask) => ask.descr(), + GeneratorKind::Gen => "generator", + } + } +} + /// In the case of a generator created as part of an async construct, /// which kind of async construct caused it to be created? /// /// This helps error messages but is also used to drive coercions in /// type-checking (see #60424). -#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)] +#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)] pub enum AsyncGeneratorKind { /// An explicit `async` block written by the user. Block, @@ -1319,6 +1328,16 @@ impl fmt::Display for AsyncGeneratorKind { } } +impl AsyncGeneratorKind { + pub fn descr(&self) -> &'static str { + match self { + AsyncGeneratorKind::Block => "`async` block", + AsyncGeneratorKind::Closure => "`async` closure body", + AsyncGeneratorKind::Fn => "`async fn` body", + } + } +} + #[derive(Copy, Clone, Debug)] pub enum BodyOwnerKind { /// Functions and methods. diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index c39daea0811e0..893fe343fdd19 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1509,7 +1509,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if let Some((kind, def_id)) = TyCategory::from_ty(t) { + if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: // @@ -1582,11 +1582,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; if let Some((expected, found)) = expected_found { let expected_label = match exp_found { - Mismatch::Variable(ef) => ef.expected.prefix_string(), + Mismatch::Variable(ef) => ef.expected.prefix_string(self.tcx), Mismatch::Fixed(s) => s.into(), }; let found_label = match exp_found { - Mismatch::Variable(ef) => ef.found.prefix_string(), + Mismatch::Variable(ef) => ef.found.prefix_string(self.tcx), Mismatch::Fixed(s) => s.into(), }; let exp_found = match exp_found { @@ -2436,7 +2436,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { pub enum TyCategory { Closure, Opaque, - Generator, + Generator(hir::GeneratorKind), Foreign, } @@ -2445,16 +2445,18 @@ impl TyCategory { match self { Self::Closure => "closure", Self::Opaque => "opaque type", - Self::Generator => "generator", + Self::Generator(gk) => gk.descr(), Self::Foreign => "foreign type", } } - pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> { + pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> { match *ty.kind() { ty::Closure(def_id, _) => Some((Self::Closure, def_id)), ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), - ty::Generator(def_id, ..) => Some((Self::Generator, def_id)), + ty::Generator(def_id, ..) => { + Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id)) + } ty::Foreign(def_id) => Some((Self::Foreign, def_id)), _ => None, } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index bd43d3c01e218..e7de11fffdea0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -383,7 +383,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { InferenceDiagnosticsData { name: s, span: None, - kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string() }, + kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) }, parent: None, } } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index c211f07bed8c2..5625264911aac 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -264,7 +264,7 @@ impl<'tcx> ty::TyS<'tcx> { } } ty::Closure(..) => "closure".into(), - ty::Generator(..) => "generator".into(), + ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), ty::GeneratorWitness(..) => "generator witness".into(), ty::Tuple(..) => "tuple".into(), ty::Infer(ty::TyVar(_)) => "inferred type".into(), @@ -282,7 +282,7 @@ impl<'tcx> ty::TyS<'tcx> { } } - pub fn prefix_string(&self) -> Cow<'static, str> { + pub fn prefix_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> { match *self.kind() { ty::Infer(_) | ty::Error(_) @@ -308,7 +308,7 @@ impl<'tcx> ty::TyS<'tcx> { ty::FnPtr(_) => "fn pointer".into(), ty::Dynamic(..) => "trait object".into(), ty::Closure(..) => "closure".into(), - ty::Generator(..) => "generator".into(), + ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), ty::GeneratorWitness(..) => "generator witness".into(), ty::Tuple(..) => "tuple".into(), ty::Placeholder(..) => "higher-ranked type".into(), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index a42a05c5f0284..7b00a828a974f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1366,8 +1366,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { Some(t) => Some(t), None => { let ty = parent_trait_ref.skip_binder().self_ty(); - let span = - TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id)); + let span = TyCategory::from_ty(self.tcx, ty) + .map(|(_, def_id)| self.tcx.def_span(def_id)); Some((ty.to_string(), span)) } } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index d49c7cae8222b..09a15df97a2d1 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -390,7 +390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "no {} named `{}` found for {} `{}` in the current scope", item_kind, item_name, - actual.prefix_string(), + actual.prefix_string(self.tcx), ty_str, ); if let Mode::MethodCall = mode { @@ -728,7 +728,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|(_, path)| path) .collect::>() .join("\n"); - let actual_prefix = actual.prefix_string(); + let actual_prefix = actual.prefix_string(self.tcx); err.set_primary_message(&format!( "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied" )); diff --git a/src/test/ui/async-await/generator-desc.rs b/src/test/ui/async-await/generator-desc.rs new file mode 100644 index 0000000000000..5008120166711 --- /dev/null +++ b/src/test/ui/async-await/generator-desc.rs @@ -0,0 +1,16 @@ +// edition:2018 +#![feature(async_closure)] +use std::future::Future; + +async fn one() {} +async fn two() {} + +fn fun>(f1: F, f2: F) {} +fn main() { + fun(async {}, async {}); + //~^ ERROR mismatched types + fun(one(), two()); + //~^ ERROR mismatched types + fun((async || {})(), (async || {})()); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/async-await/generator-desc.stderr b/src/test/ui/async-await/generator-desc.stderr new file mode 100644 index 0000000000000..b85926c7a03c0 --- /dev/null +++ b/src/test/ui/async-await/generator-desc.stderr @@ -0,0 +1,49 @@ +error[E0308]: mismatched types + --> $DIR/generator-desc.rs:10:25 + | +LL | fun(async {}, async {}); + | -- ^^ expected `async` block, found a different `async` block + | | + | the expected `async` block + | + = note: expected `async` block `[static generator@$DIR/generator-desc.rs:10:15: 10:17]` + found `async` block `[static generator@$DIR/generator-desc.rs:10:25: 10:27]` + +error[E0308]: mismatched types + --> $DIR/generator-desc.rs:12:16 + | +LL | async fn one() {} + | - the `Output` of this `async fn`'s expected opaque type +LL | async fn two() {} + | - the `Output` of this `async fn`'s found opaque type +... +LL | fun(one(), two()); + | ^^^^^ expected opaque type, found a different opaque type + | + = note: expected opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:5:16>) + found opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:6:16>) + = help: consider `await`ing on both `Future`s + = note: distinct uses of `impl Trait` result in different opaque types + +error[E0308]: mismatched types + --> $DIR/generator-desc.rs:14:26 + | +LL | fun((async || {})(), (async || {})()); + | -- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body + | | + | the expected `async` closure body + | + ::: $SRC_DIR/core/src/future/mod.rs:LL:COL + | +LL | pub const fn from_generator(gen: T) -> impl Future + | ------------------------------- + | | + | the expected opaque type + | the found opaque type + | + = note: expected opaque type `impl Future` (`async` closure body) + found opaque type `impl Future` (`async` closure body) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. From dfdadad228e0885d43ced8117978c77d6973f05e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 16 Feb 2021 09:45:27 +0100 Subject: [PATCH 03/14] Ignore Atomic*::fetch_{min,max} tests on ARM --- library/core/tests/atomic.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index 762642aecdab6..901b752502dd8 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -60,6 +60,7 @@ fn uint_xor() { } #[test] +#[cfg(not(target_arch = "arm"))] // Missing intrinsic in compiler-builtins fn uint_min() { let x = AtomicUsize::new(0xf731); assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); @@ -69,6 +70,7 @@ fn uint_min() { } #[test] +#[cfg(not(target_arch = "arm"))] // Missing intrinsic in compiler-builtins fn uint_max() { let x = AtomicUsize::new(0x137f); assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); @@ -106,6 +108,7 @@ fn int_xor() { } #[test] +#[cfg(not(target_arch = "arm"))] // Missing intrinsic in compiler-builtins fn int_min() { let x = AtomicIsize::new(0xf731); assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); @@ -115,6 +118,7 @@ fn int_min() { } #[test] +#[cfg(not(target_arch = "arm"))] // Missing intrinsic in compiler-builtins fn int_max() { let x = AtomicIsize::new(0x137f); assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); From 4fa9e08e3dc10acdb322490d5ac24e937c0f43f5 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 17 Feb 2021 10:01:29 +0100 Subject: [PATCH 04/14] Enable the tests on Arm Linux too --- library/core/tests/atomic.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index 901b752502dd8..b735957666fc5 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -60,7 +60,7 @@ fn uint_xor() { } #[test] -#[cfg(not(target_arch = "arm"))] // Missing intrinsic in compiler-builtins +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins fn uint_min() { let x = AtomicUsize::new(0xf731); assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); @@ -70,7 +70,7 @@ fn uint_min() { } #[test] -#[cfg(not(target_arch = "arm"))] // Missing intrinsic in compiler-builtins +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins fn uint_max() { let x = AtomicUsize::new(0x137f); assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); @@ -108,7 +108,7 @@ fn int_xor() { } #[test] -#[cfg(not(target_arch = "arm"))] // Missing intrinsic in compiler-builtins +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins fn int_min() { let x = AtomicIsize::new(0xf731); assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); @@ -118,7 +118,7 @@ fn int_min() { } #[test] -#[cfg(not(target_arch = "arm"))] // Missing intrinsic in compiler-builtins +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins fn int_max() { let x = AtomicIsize::new(0x137f); assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); From 3eb454aabe63fdf04155c6943fa13f25d840ea84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 17 Feb 2021 20:44:00 -0800 Subject: [PATCH 05/14] Do not ICE when evaluating locals' types of invalid `yield` When a `yield` is outside of a generator, check its value regardless to avoid an ICE while trying to get all locals' types in writeback. Fix #78653. --- compiler/rustc_typeck/src/check/expr.rs | 2 ++ .../yield-outside-generator-issue-78653.rs | 7 +++++++ ...yield-outside-generator-issue-78653.stderr | 21 +++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 src/test/ui/generator/yield-outside-generator-issue-78653.rs create mode 100644 src/test/ui/generator/yield-outside-generator-issue-78653.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index fa09c26c800ae..32bf0ab7e8533 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2081,6 +2081,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => { self.tcx.sess.emit_err(YieldExprOutsideOfGenerator { span: expr.span }); + // Avoid expressions without types during writeback (#78653). + self.check_expr(value); self.tcx.mk_unit() } } diff --git a/src/test/ui/generator/yield-outside-generator-issue-78653.rs b/src/test/ui/generator/yield-outside-generator-issue-78653.rs new file mode 100644 index 0000000000000..4e8050c81b0d3 --- /dev/null +++ b/src/test/ui/generator/yield-outside-generator-issue-78653.rs @@ -0,0 +1,7 @@ +#![feature(generators)] + +fn main() { + yield || for i in 0 { } + //~^ ERROR yield expression outside of generator literal + //~| ERROR `{integer}` is not an iterator +} diff --git a/src/test/ui/generator/yield-outside-generator-issue-78653.stderr b/src/test/ui/generator/yield-outside-generator-issue-78653.stderr new file mode 100644 index 0000000000000..f0c7cb0e5d50c --- /dev/null +++ b/src/test/ui/generator/yield-outside-generator-issue-78653.stderr @@ -0,0 +1,21 @@ +error[E0627]: yield expression outside of generator literal + --> $DIR/yield-outside-generator-issue-78653.rs:4:5 + | +LL | yield || for i in 0 { } + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `{integer}` is not an iterator + --> $DIR/yield-outside-generator-issue-78653.rs:4:23 + | +LL | yield || for i in 0 { } + | ^ `{integer}` is not an iterator + | + = help: the trait `Iterator` is not implemented for `{integer}` + = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` + = note: required because of the requirements on the impl of `IntoIterator` for `{integer}` + = note: required by `into_iter` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0627. +For more information about an error, try `rustc --explain E0277`. From eb65f15c7800930c3f74288974689d9884e51ba0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 14 Feb 2021 21:14:12 +0300 Subject: [PATCH 06/14] ast: Stop using `Mod` in `Crate` Crate root is sufficiently different from `mod` items, at least at syntactic level. Also remove customization point for "`mod` item or crate root" from AST visitors. --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast/src/mut_visit.rs | 27 ++++----- compiler/rustc_ast/src/visit.rs | 13 +---- compiler/rustc_ast_lowering/src/item.rs | 57 +++++++------------ compiler/rustc_ast_lowering/src/lib.rs | 4 +- compiler/rustc_ast_passes/src/node_count.rs | 4 -- compiler/rustc_ast_pretty/src/pprust/state.rs | 17 +++--- .../src/proc_macro_harness.rs | 2 +- .../src/standard_library_imports.rs | 4 +- .../rustc_builtin_macros/src/test_harness.rs | 10 +++- compiler/rustc_expand/src/config.rs | 2 +- compiler/rustc_expand/src/expand.rs | 38 +++++-------- compiler/rustc_expand/src/module.rs | 5 +- compiler/rustc_expand/src/mut_visit/tests.rs | 8 +-- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_lint/src/early.rs | 7 --- compiler/rustc_lint/src/passes.rs | 2 - compiler/rustc_parse/src/parser/item.rs | 31 +++------- compiler/rustc_passes/src/hir_stats.rs | 10 ---- compiler/rustc_resolve/src/lib.rs | 38 ++++++++----- .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- src/test/ui/issues/issue-49040.stderr | 6 +- 23 files changed, 114 insertions(+), 179 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index cd0ad2b0150be..b01e8ccd67779 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -486,8 +486,8 @@ pub struct WhereEqPredicate { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Crate { - pub module: Mod, pub attrs: Vec, + pub items: Vec>, pub span: Span, /// The order of items in the HIR is unrelated to the order of /// items in the AST. However, we generate proc macro harnesses diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 024d9687f3119..5333da07aa082 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -170,10 +170,6 @@ pub trait MutVisitor: Sized { noop_visit_ty_constraint(t, self); } - fn visit_mod(&mut self, m: &mut Mod) { - noop_visit_mod(m, self); - } - fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) { noop_visit_foreign_mod(nm, self); } @@ -917,7 +913,11 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { vis.visit_generics(generics); visit_opt(body, |body| vis.visit_block(body)); } - ItemKind::Mod(m) => vis.visit_mod(m), + ItemKind::Mod(m) => { + let Mod { inner, unsafety: _, items, inline: _ } = m; + vis.visit_span(inner); + items.flat_map_in_place(|item| vis.flat_map_item(item)); + } ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), ItemKind::GlobalAsm(_ga) => {} ItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => { @@ -998,14 +998,10 @@ pub fn noop_visit_fn_header(header: &mut FnHeader, vis: &mut T) { vis.visit_asyncness(asyncness); } -pub fn noop_visit_mod(module: &mut Mod, vis: &mut T) { - let Mod { inner, unsafety: _, items, inline: _ } = module; - vis.visit_span(inner); - items.flat_map_in_place(|item| vis.flat_map_item(item)); -} - +// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible, +// or make crate visiting first class if necessary. pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { - visit_clobber(krate, |Crate { module, attrs, span, proc_macros }| { + visit_clobber(krate, |Crate { attrs, items, span, proc_macros }| { let item_vis = Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None }; let item = P(Item { @@ -1014,19 +1010,18 @@ pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { id: DUMMY_NODE_ID, vis: item_vis, span, - kind: ItemKind::Mod(module), + kind: ItemKind::Mod(Mod { inner: span, unsafety: Unsafe::No, items, inline: true }), tokens: None, }); let items = vis.flat_map_item(item); let len = items.len(); if len == 0 { - let module = Mod { inner: span, unsafety: Unsafe::No, items: vec![], inline: true }; - Crate { module, attrs: vec![], span, proc_macros } + Crate { attrs: vec![], items: vec![], span, proc_macros } } else if len == 1 { let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner(); match kind { - ItemKind::Mod(module) => Crate { module, attrs, span, proc_macros }, + ItemKind::Mod(module) => Crate { attrs, items: module.items, span, proc_macros }, _ => panic!("visitor converted a module to not a module"), } } else { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index c37d4cd9f7936..3fa53bb391fde 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -74,7 +74,7 @@ impl<'a> FnKind<'a> { /// Each method of the `Visitor` trait is a hook to be potentially /// overridden. Each method's default implementation recursively visits /// the substructure of the input via the corresponding `walk` method; -/// e.g., the `visit_mod` method by default calls `visit::walk_mod`. +/// e.g., the `visit_item` method by default calls `visit::walk_item`. /// /// If you want to ensure that your code handles every variant /// explicitly, you need to override each method. (And you also need @@ -87,9 +87,6 @@ pub trait Visitor<'ast>: Sized { fn visit_ident(&mut self, ident: Ident) { walk_ident(self, ident); } - fn visit_mod(&mut self, m: &'ast Mod, _s: Span, _attrs: &[Attribute], _n: NodeId) { - walk_mod(self, m); - } fn visit_foreign_item(&mut self, i: &'ast ForeignItem) { walk_foreign_item(self, i) } @@ -238,14 +235,10 @@ pub fn walk_ident<'a, V: Visitor<'a>>(visitor: &mut V, ident: Ident) { } pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) { - visitor.visit_mod(&krate.module, krate.span, &krate.attrs, CRATE_NODE_ID); + walk_list!(visitor, visit_item, &krate.items); walk_list!(visitor, visit_attribute, &krate.attrs); } -pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, module: &'a Mod) { - walk_list!(visitor, visit_item, &module.items); -} - pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) { for attr in local.attrs.iter() { visitor.visit_attribute(attr); @@ -297,7 +290,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref()); visitor.visit_fn(kind, item.span, item.id) } - ItemKind::Mod(ref module) => visitor.visit_mod(module, item.span, &item.attrs, item.id), + ItemKind::Mod(ref module) => walk_list!(visitor, visit_item, &module.items), ItemKind::ForeignMod(ref foreign_module) => { walk_list!(visitor, visit_foreign_item, &foreign_module.items); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index cad2a21d1a4a7..5bdf0fd50ae62 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -15,11 +15,11 @@ use rustc_span::source_map::{respan, DesugaringKind}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use rustc_target::spec::abi; - use smallvec::{smallvec, SmallVec}; -use std::collections::BTreeSet; use tracing::debug; +use std::mem; + pub(super) struct ItemLowerer<'a, 'lowering, 'hir> { pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>, } @@ -34,25 +34,6 @@ impl ItemLowerer<'_, '_, '_> { } impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { - fn visit_mod(&mut self, m: &'a Mod, _s: Span, _attrs: &[Attribute], n: NodeId) { - let def_id = self.lctx.lower_node_id(n).expect_owner(); - - self.lctx.modules.insert( - def_id, - hir::ModuleItems { - items: BTreeSet::new(), - trait_items: BTreeSet::new(), - impl_items: BTreeSet::new(), - foreign_items: BTreeSet::new(), - }, - ); - - let old = self.lctx.current_module; - self.lctx.current_module = def_id; - visit::walk_mod(self, m); - self.lctx.current_module = old; - } - fn visit_item(&mut self, item: &'a Item) { let mut item_hir_id = None; self.lctx.with_hir_id_owner(item.id, |lctx| { @@ -67,10 +48,18 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { if let Some(hir_id) = item_hir_id { self.lctx.with_parent_item_lifetime_defs(hir_id, |this| { let this = &mut ItemLowerer { lctx: this }; - if let ItemKind::Impl(box ImplKind { ref of_trait, .. }) = item.kind { - this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); - } else { - visit::walk_item(this, item); + match item.kind { + ItemKind::Mod(..) => { + let def_id = this.lctx.lower_node_id(item.id).expect_owner(); + let old_current_module = + mem::replace(&mut this.lctx.current_module, def_id); + visit::walk_item(this, item); + this.lctx.current_module = old_current_module; + } + ItemKind::Impl(box ImplKind { ref of_trait, .. }) => { + this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); + } + _ => visit::walk_item(this, item), } }); } @@ -94,13 +83,13 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { let hir_item = lctx.lower_trait_item(item); let id = hir_item.trait_item_id(); lctx.trait_items.insert(id, hir_item); - lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id); + lctx.modules.entry(lctx.current_module).or_default().trait_items.insert(id); } AssocCtxt::Impl => { let hir_item = lctx.lower_impl_item(item); let id = hir_item.impl_item_id(); lctx.impl_items.insert(id, hir_item); - lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id); + lctx.modules.entry(lctx.current_module).or_default().impl_items.insert(id); } }); @@ -113,7 +102,7 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { let hir_item = lctx.lower_foreign_item(item); let id = hir_item.foreign_item_id(); lctx.foreign_items.insert(id, hir_item); - lctx.modules.get_mut(&lctx.current_module).unwrap().foreign_items.insert(id); + lctx.modules.entry(lctx.current_module).or_default().foreign_items.insert(id); }); visit::walk_foreign_item(self, item); @@ -157,7 +146,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T, ) -> T { - let old_in_scope_lifetimes = std::mem::replace(&mut self.in_scope_lifetimes, vec![]); + let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]); // this vector is only used when walking over impl headers, // input types, and the like, and should not be non-empty in @@ -172,12 +161,10 @@ impl<'hir> LoweringContext<'_, 'hir> { res } - pub(super) fn lower_mod(&mut self, m: &Mod) -> hir::Mod<'hir> { + pub(super) fn lower_mod(&mut self, items: &[P], inner: Span) -> hir::Mod<'hir> { hir::Mod { - inner: m.inner, - item_ids: self - .arena - .alloc_from_iter(m.items.iter().flat_map(|x| self.lower_item_id(x))), + inner, + item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_id(x))), } } @@ -327,7 +314,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ItemKind::Fn(sig, generics, body_id) }) } - ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)), + ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(&m.items, m.inner)), ItemKind::ForeignMod(ref fm) => { if fm.abi.is_none() { self.maybe_lint_missing_abi(span, id, abi::Abi::C); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9d0b2cd5c675d..05b417effd491 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -560,7 +560,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c); visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c); - let module = self.lower_mod(&c.module); + let module = self.lower_mod(&c.items, c.span); let attrs = self.lower_attrs(&c.attrs); let body_ids = body_ids(&self.bodies); let proc_macros = @@ -608,7 +608,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId { let id = hir::ItemId { def_id: item.def_id }; self.items.insert(id, item); - self.modules.get_mut(&self.current_module).unwrap().items.insert(id); + self.modules.entry(self.current_module).or_default().items.insert(id); id } diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index 2971fa435c8dc..fb7e0d3450fde 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -20,10 +20,6 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_ident(self, ident); } - fn visit_mod(&mut self, m: &Mod, _s: Span, _a: &[Attribute], _n: NodeId) { - self.count += 1; - walk_mod(self, m) - } fn visit_foreign_item(&mut self, i: &ForeignItem) { self.count += 1; walk_foreign_item(self, i) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 180402c24fb7b..bd9c209b65989 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -132,7 +132,10 @@ pub fn print_crate<'a>( } } - s.print_mod(&krate.module, &krate.attrs); + s.print_inner_attributes(&krate.attrs); + for item in &krate.items { + s.print_item(item); + } s.print_remaining_comments(); s.ann.post(&mut s, AnnNode::Crate(krate)); s.s.eof() @@ -891,13 +894,6 @@ impl<'a> State<'a> { self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span) } - pub fn print_mod(&mut self, _mod: &ast::Mod, attrs: &[ast::Attribute]) { - self.print_inner_attributes(attrs); - for item in &_mod.items { - self.print_item(item); - } - } - crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) { self.print_inner_attributes(attrs); for item in &nmod.items { @@ -1149,7 +1145,10 @@ impl<'a> State<'a> { if _mod.inline || self.is_expanded { self.nbsp(); self.bopen(); - self.print_mod(_mod, &item.attrs); + self.print_inner_attributes(&item.attrs); + for item in &_mod.items { + self.print_item(item); + } self.bclose(item.span); } else { self.s.word(";"); diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 7582d9805390e..71bbae1161b4b 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -91,7 +91,7 @@ pub fn inject( } let decls = mk_decls(&mut krate, &mut cx, ¯os); - krate.module.items.push(decls); + krate.items.push(decls); krate } diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 91566ec1ef245..3a81d076dc52f 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -44,7 +44,7 @@ pub fn inject( // .rev() to preserve ordering above in combination with insert(0, ...) for &name in names.iter().rev() { let ident = if rust_2018 { Ident::new(name, span) } else { Ident::new(name, call_site) }; - krate.module.items.insert( + krate.items.insert( 0, cx.item( span, @@ -79,7 +79,7 @@ pub fn inject( })), ); - krate.module.items.insert(0, use_item); + krate.items.insert(0, use_item); krate } diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 4ac22be3c275d..8c5431a47db83 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -89,7 +89,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { noop_visit_crate(c, self); // Create a main function to run our tests - c.module.items.push(mk_main(&mut self.cx)); + c.items.push(mk_main(&mut self.cx)); } fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { @@ -103,9 +103,13 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { // We don't want to recurse into anything other than mods, since // mods or tests inside of functions will break things - if let ast::ItemKind::Mod(mut module) = item.kind { + if let ast::ItemKind::Mod(..) = item.kind { let tests = mem::take(&mut self.tests); - noop_visit_mod(&mut module, self); + noop_visit_item_kind(&mut item.kind, self); + let module = match item.kind { + ast::ItemKind::Mod(module) => module, + _ => unreachable!(), + }; let mut tests = mem::replace(&mut self.tests, tests); if !tests.is_empty() { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index b07bce94870c1..ad04fa9a95816 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -209,7 +209,7 @@ pub fn features(sess: &Session, mut krate: ast::Crate) -> (ast::Crate, Features) None => { // The entire crate is unconfigured. krate.attrs = Vec::new(); - krate.module.items = Vec::new(); + krate.items = Vec::new(); Features::default() } Some(attrs) => { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index f23e3b9f7471a..c570cc1ff350b 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -350,6 +350,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { MacroExpander { cx, monotonic } } + // FIXME: Avoid visiting the crate as a `Mod` item, + // make crate a first class expansion target instead. pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { let mut module = ModuleData { mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)], @@ -362,12 +364,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.root_path = module.directory.clone(); self.cx.current_expansion.module = Rc::new(module); - let orig_mod_span = krate.module.inner; - let krate_item = AstFragment::Items(smallvec![P(ast::Item { attrs: krate.attrs, span: krate.span, - kind: ast::ItemKind::Mod(krate.module), + kind: ast::ItemKind::Mod(ast::Mod { + inner: krate.span, + unsafety: Unsafe::No, + items: krate.items, + inline: true + }), ident: Ident::invalid(), id: ast::DUMMY_NODE_ID, vis: ast::Visibility { @@ -381,26 +386,16 @@ impl<'a, 'b> MacroExpander<'a, 'b> { match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) { Some(ast::Item { attrs, kind: ast::ItemKind::Mod(module), .. }) => { krate.attrs = attrs; - krate.module = module; + krate.items = module.items; } None => { // Resolution failed so we return an empty expansion krate.attrs = vec![]; - krate.module = ast::Mod { - inner: orig_mod_span, - unsafety: Unsafe::No, - items: vec![], - inline: true, - }; + krate.items = vec![]; } Some(ast::Item { span, kind, .. }) => { krate.attrs = vec![]; - krate.module = ast::Mod { - inner: orig_mod_span, - unsafety: Unsafe::No, - items: vec![], - inline: true, - }; + krate.items = vec![]; self.cx.span_err( span, &format!( @@ -1284,7 +1279,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { push_directory(&self.cx.sess, 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( + let (ast::Mod { unsafety, inline, items, inner }, dir) = parse_external_mod( &self.cx.sess, ident, span, @@ -1294,17 +1289,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { pushed, ); - let krate = ast::Crate { - span: new_mod.inner, - module: new_mod, - attrs, - proc_macros: vec![], - }; + let krate = ast::Crate { attrs, items, span: inner, proc_macros: vec![] }; if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded { extern_mod_loaded(&krate, ident); } - *old_mod = krate.module; + *old_mod = ast::Mod { unsafety, inline, items: krate.items, inner }; item.attrs = krate.attrs; // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure. item = match self.configure(item) { diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 171cb3fa8e6e9..d63625fea465c 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -62,9 +62,8 @@ crate fn parse_external_mod( // Actually parse the external file as a module. let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)); - let mut module = parser.parse_mod(&token::Eof, unsafety)?; - module.0.inline = false; - module + let (inner_attrs, items, inner) = parser.parse_mod(&token::Eof)?; + (Mod { unsafety, inline: false, items, inner }, inner_attrs) }; // (1) ...instead, we return a dummy module. let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_else(|_| { diff --git a/compiler/rustc_expand/src/mut_visit/tests.rs b/compiler/rustc_expand/src/mut_visit/tests.rs index be0300bad98bd..7e7155ad27876 100644 --- a/compiler/rustc_expand/src/mut_visit/tests.rs +++ b/compiler/rustc_expand/src/mut_visit/tests.rs @@ -7,8 +7,8 @@ use rustc_span::symbol::Ident; use rustc_span::with_default_session_globals; // This version doesn't care about getting comments or doc-strings in. -fn fake_print_crate(s: &mut pprust::State<'_>, krate: &ast::Crate) { - s.print_mod(&krate.module, &krate.attrs) +fn print_crate_items(krate: &ast::Crate) -> String { + krate.items.iter().map(|i| pprust::item_to_string(i)).collect::>().join(" ") } // Change every identifier to "zz". @@ -46,7 +46,7 @@ fn ident_transformation() { assert_pred!( matches_codepattern, "matches_codepattern", - pprust::to_string(|s| fake_print_crate(s, &krate)), + print_crate_items(&krate), "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string() ); }) @@ -66,7 +66,7 @@ fn ident_transformation_in_defs() { assert_pred!( matches_codepattern, "matches_codepattern", - pprust::to_string(|s| fake_print_crate(s, &krate)), + print_crate_items(&krate), "macro_rules! zz{(zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+))}".to_string() ); }) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6ac1c570cfe1b..46819041745b0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -615,7 +615,7 @@ pub struct WhereEqPredicate<'hir> { pub rhs_ty: &'hir Ty<'hir>, } -#[derive(Encodable, Debug, HashStable_Generic)] +#[derive(Default, Encodable, Debug, HashStable_Generic)] pub struct ModuleItems { // Use BTreeSets here so items are in the same order as in the // list of all items in Crate diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 231edf442eb00..cc3bf4095fdef 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -188,13 +188,6 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> run_early_pass!(self, check_ident, ident); } - fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) { - run_early_pass!(self, check_mod, m, s, n); - self.check_id(n); - ast_visit::walk_mod(self, m); - run_early_pass!(self, check_mod_post, m, s, n); - } - fn visit_local(&mut self, l: &'a ast::Local) { self.with_lint_attrs(l.id, &l.attrs, |cx| { run_early_pass!(cx, check_local, l); diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 828f283d2a95a..ffbed3a0aff2d 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -160,8 +160,6 @@ macro_rules! early_lint_methods { fn check_ident(a: Ident); fn check_crate(a: &ast::Crate); fn check_crate_post(a: &ast::Crate); - fn check_mod(a: &ast::Mod, b: Span, c: ast::NodeId); - fn check_mod_post(a: &ast::Mod, b: Span, c: ast::NodeId); fn check_foreign_item(a: &ast::ForeignItem); fn check_foreign_item_post(a: &ast::ForeignItem); fn check_item(a: &ast::Item); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index cdea82f50ede4..c0464c3edbc04 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -25,11 +25,9 @@ use tracing::debug; 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, Unsafe::No)?; - let span = lo.to(self.token.span); + let (attrs, items, span) = self.parse_mod(&token::Eof)?; let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`. - Ok(ast::Crate { attrs, module, span, proc_macros }) + Ok(ast::Crate { attrs, items, span, proc_macros }) } /// Parses a `mod { ... }` or `mod ;` item. @@ -37,35 +35,24 @@ impl<'a> Parser<'a> { let unsafety = self.parse_unsafety(); self.expect_keyword(kw::Mod)?; let id = self.parse_ident()?; - let (module, mut inner_attrs) = if self.eat(&token::Semi) { - (Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }, Vec::new()) + let ((mut inner_attrs, items, inner), inline) = if self.eat(&token::Semi) { + ((Vec::new(), Vec::new(), Span::default()), false) } else { self.expect(&token::OpenDelim(token::Brace))?; - self.parse_mod(&token::CloseDelim(token::Brace), unsafety)? + (self.parse_mod(&token::CloseDelim(token::Brace))?, true) }; attrs.append(&mut inner_attrs); - Ok((id, ItemKind::Mod(module))) + Ok((id, ItemKind::Mod(Mod { unsafety, inline, items, inner }))) } /// Parses the contents of a module (inner attributes followed by module items). pub fn parse_mod( &mut self, term: &TokenKind, - unsafety: Unsafe, - ) -> PResult<'a, (Mod, Vec)> { + ) -> PResult<'a, (Vec, Vec>, Span)> { let lo = self.token.span; let attrs = self.parse_inner_attributes()?; - let module = self.parse_mod_items(term, lo, unsafety)?; - 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, - unsafety: Unsafe, - ) -> PResult<'a, Mod> { let mut items = vec![]; while let Some(item) = self.parse_item(ForceCollect::No)? { items.push(item); @@ -82,9 +69,7 @@ impl<'a> Parser<'a> { } } - let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span }; - - Ok(Mod { inner: inner_lo.to(hi), unsafety, items, inline: true }) + Ok((attrs, items, lo.to(self.prev_token.span))) } } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index e35ad10968d33..95c91e97d26ef 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -124,11 +124,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_item(self, i) } - fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: hir::HirId) { - self.record("Mod", Id::None, m); - hir_visit::walk_mod(self, m, n) - } - fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) { self.record("ForeignItem", Id::Node(i.hir_id()), i); hir_visit::walk_foreign_item(self, i) @@ -252,11 +247,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { - fn visit_mod(&mut self, m: &'v ast::Mod, _s: Span, _a: &[ast::Attribute], _n: NodeId) { - self.record("Mod", Id::None, m); - ast_visit::walk_mod(self, m) - } - fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) { self.record("ForeignItem", Id::None, i); ast_visit::walk_foreign_item(self, i) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index bca3c7b1b03d3..8140700471991 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -11,6 +11,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(box_patterns)] #![feature(bool_to_option)] +#![feature(control_flow_enum)] #![feature(crate_visibility_modifier)] #![feature(format_args_capture)] #![feature(nll)] @@ -23,6 +24,7 @@ use Determinacy::*; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; +use rustc_ast::ptr::P; use rustc_ast::unwrap_or; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, NodeId}; @@ -59,6 +61,7 @@ use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; +use std::ops::ControlFlow; use std::{cmp, fmt, iter, ptr}; use tracing::debug; @@ -283,28 +286,21 @@ struct UsePlacementFinder { impl UsePlacementFinder { fn check(krate: &Crate, target_module: NodeId) -> (Option, bool) { let mut finder = UsePlacementFinder { target_module, span: None, found_use: false }; - visit::walk_crate(&mut finder, krate); + if let ControlFlow::Continue(..) = finder.check_mod(&krate.items, CRATE_NODE_ID) { + visit::walk_crate(&mut finder, krate); + } (finder.span, finder.found_use) } -} -impl<'tcx> Visitor<'tcx> for UsePlacementFinder { - fn visit_mod( - &mut self, - module: &'tcx ast::Mod, - _: Span, - _: &[ast::Attribute], - node_id: NodeId, - ) { + fn check_mod(&mut self, items: &[P], node_id: NodeId) -> ControlFlow<()> { if self.span.is_some() { - return; + return ControlFlow::Break(()); } if node_id != self.target_module { - visit::walk_mod(self, module); - return; + return ControlFlow::Continue(()); } // find a use statement - for item in &module.items { + for item in items { match item.kind { ItemKind::Use(..) => { // don't suggest placing a use before the prelude @@ -312,7 +308,7 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { if !item.span.from_expansion() { self.span = Some(item.span.shrink_to_lo()); self.found_use = true; - return; + return ControlFlow::Break(()); } } // don't place use before extern crate @@ -337,6 +333,18 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { } } } + ControlFlow::Continue(()) + } +} + +impl<'tcx> Visitor<'tcx> for UsePlacementFinder { + fn visit_item(&mut self, item: &'tcx ast::Item) { + if let ItemKind::Mod(module) = &item.kind { + if let ControlFlow::Break(..) = self.check_mod(&module.items, item.id) { + return; + } + } + visit::walk_item(self, item); } } diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index 02342af8dc53e..0307875c154b8 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 235f39c567b8e..d26530efe3ecd 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/issues/issue-49040.stderr b/src/test/ui/issues/issue-49040.stderr index 4134d6aa54468..56befe3a0a75d 100644 --- a/src/test/ui/issues/issue-49040.stderr +++ b/src/test/ui/issues/issue-49040.stderr @@ -7,10 +7,8 @@ LL | #![allow(unused_variables)]; error[E0601]: `main` function not found in crate `issue_49040` --> $DIR/issue-49040.rs:1:1 | -LL | / #![allow(unused_variables)]; -LL | | -LL | | fn foo() {} - | |__^ consider adding a `main` function to `$DIR/issue-49040.rs` +LL | #![allow(unused_variables)]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/issue-49040.rs` error: aborting due to 2 previous errors From 4a8816512477513f57986685738cd065e72c4908 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 17 Feb 2021 00:56:07 +0300 Subject: [PATCH 07/14] ast: Keep expansion status for out-of-line module items Also remove `ast::Mod` which is mostly redundant now --- compiler/rustc_ast/src/ast.rs | 33 +++---- compiler/rustc_ast/src/mut_visit.rs | 18 ++-- compiler/rustc_ast/src/visit.rs | 7 +- compiler/rustc_ast_lowering/src/item.rs | 7 +- .../rustc_ast_passes/src/ast_validation.rs | 6 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 42 +++++---- .../rustc_builtin_macros/src/test_harness.rs | 13 ++- compiler/rustc_expand/src/expand.rs | 90 ++++++++++--------- compiler/rustc_expand/src/module.rs | 23 +++-- compiler/rustc_expand/src/parse/tests.rs | 4 +- compiler/rustc_parse/src/parser/item.rs | 12 +-- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 6 +- .../clippy_lints/src/utils/ast_utils.rs | 9 +- 14 files changed, 147 insertions(+), 125 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b01e8ccd67779..3550055ac10d3 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2299,21 +2299,22 @@ impl FnRetTy { } } -/// Module declaration. -/// -/// E.g., `mod foo;` or `mod foo { .. }`. +#[derive(Clone, PartialEq, Encodable, Decodable, Debug)] +pub enum Inline { + Yes, + No, +} + +/// Module item kind. #[derive(Clone, Encodable, Decodable, Debug)] -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 - /// to the last token in the external file. - pub inner: Span, - /// `unsafe` keyword accepted syntactically for macro DSLs, but not - /// semantically by Rust. - pub unsafety: Unsafe, - pub items: Vec>, - /// `true` for `mod foo { .. }`; `false` for `mod foo;`. - pub inline: bool, +pub enum ModKind { + /// Module with inlined definition `mod foo { ... }`, + /// or with definition outlined to a separate file `mod foo;` and already loaded from it. + /// The inner span is from the first token past `{` to the last token until `}`, + /// or from the first to the last token in the loaded file. + Loaded(Vec>, Inline, Span), + /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it. + Unloaded, } /// Foreign module declaration. @@ -2710,7 +2711,9 @@ pub enum ItemKind { /// A module declaration (`mod`). /// /// E.g., `mod foo;` or `mod foo { .. }`. - Mod(Mod), + /// `unsafe` keyword on modules is accepted syntactically for macro DSLs, but not + /// semantically by Rust. + Mod(Unsafe, ModKind), /// An external module (`extern`). /// /// E.g., `extern {}` or `extern "C" {}`. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 5333da07aa082..c286738811ca1 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -913,11 +913,13 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { vis.visit_generics(generics); visit_opt(body, |body| vis.visit_block(body)); } - ItemKind::Mod(m) => { - let Mod { inner, unsafety: _, items, inline: _ } = m; - vis.visit_span(inner); - items.flat_map_in_place(|item| vis.flat_map_item(item)); - } + ItemKind::Mod(_unsafety, mod_kind) => match mod_kind { + ModKind::Loaded(items, _inline, inner_span) => { + vis.visit_span(inner_span); + items.flat_map_in_place(|item| vis.flat_map_item(item)); + } + ModKind::Unloaded => {} + }, ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), ItemKind::GlobalAsm(_ga) => {} ItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => { @@ -1010,7 +1012,7 @@ pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { id: DUMMY_NODE_ID, vis: item_vis, span, - kind: ItemKind::Mod(Mod { inner: span, unsafety: Unsafe::No, items, inline: true }), + kind: ItemKind::Mod(Unsafe::No, ModKind::Loaded(items, Inline::Yes, span)), tokens: None, }); let items = vis.flat_map_item(item); @@ -1021,7 +1023,9 @@ pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { } else if len == 1 { let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner(); match kind { - ItemKind::Mod(module) => Crate { attrs, items: module.items, span, proc_macros }, + ItemKind::Mod(_, ModKind::Loaded(items, ..)) => { + Crate { attrs, items, span, proc_macros } + } _ => panic!("visitor converted a module to not a module"), } } else { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 3fa53bb391fde..32b9dd46baef4 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -290,7 +290,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref()); visitor.visit_fn(kind, item.span, item.id) } - ItemKind::Mod(ref module) => walk_list!(visitor, visit_item, &module.items), + ItemKind::Mod(_unsafety, ref mod_kind) => match mod_kind { + ModKind::Loaded(items, _inline, _inner_span) => { + walk_list!(visitor, visit_item, items) + } + ModKind::Unloaded => {} + }, ItemKind::ForeignMod(ref foreign_module) => { walk_list!(visitor, visit_foreign_item, &foreign_module.items); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 5bdf0fd50ae62..8b740b7774089 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -314,7 +314,12 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ItemKind::Fn(sig, generics, body_id) }) } - ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(&m.items, m.inner)), + ItemKind::Mod(_, ref mod_kind) => match mod_kind { + ModKind::Loaded(items, _, inner_span) => { + hir::ItemKind::Mod(self.lower_mod(items, *inner_span)) + } + ModKind::Unloaded => panic!("`mod` items should have been loaded by now"), + }, ItemKind::ForeignMod(ref fm) => { if fm.abi.is_none() { self.maybe_lint_missing_abi(span, id, abi::Abi::C); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 8defd91c688d7..563bcda519065 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1054,12 +1054,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_attribute, &item.attrs); return; } - ItemKind::Mod(Mod { inline, unsafety, .. }) => { + ItemKind::Mod(unsafety, ref mod_kind) => { if let Unsafe::Yes(span) = unsafety { self.err_handler().span_err(span, "module cannot be declared unsafe"); } // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). - if !inline && !self.session.contains_name(&item.attrs, sym::path) { + if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) + && !self.session.contains_name(&item.attrs, sym::path) + { self.check_mod_file_item_asciionly(item.ident); } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index bd9c209b65989..2189e6eaa0297 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -9,7 +9,7 @@ use rustc_ast::util::classify; use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle}; use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; -use rustc_ast::{GenericArg, MacArgs}; +use rustc_ast::{GenericArg, MacArgs, ModKind}; use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; @@ -87,7 +87,6 @@ pub struct State<'a> { pub s: pp::Printer, comments: Option>, ann: &'a (dyn PpAnn + 'a), - is_expanded: bool, } crate const INDENT_UNIT: usize = 4; @@ -103,12 +102,8 @@ pub fn print_crate<'a>( is_expanded: bool, edition: Edition, ) -> String { - let mut s = State { - s: pp::mk_printer(), - comments: Some(Comments::new(sm, filename, input)), - ann, - is_expanded, - }; + let mut s = + State { s: pp::mk_printer(), comments: Some(Comments::new(sm, filename, input)), ann }; if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) { // We need to print `#![no_std]` (and its feature gate) so that @@ -856,7 +851,7 @@ impl<'a> PrintState<'a> for State<'a> { impl<'a> State<'a> { pub fn new() -> State<'a> { - State { s: pp::mk_printer(), comments: None, ann: &NoAnn, is_expanded: false } + State { s: pp::mk_printer(), comments: None, ann: &NoAnn } } // Synthesizes a comment that was not textually present in the original source @@ -1134,26 +1129,29 @@ impl<'a> State<'a> { let body = body.as_deref(); self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs); } - ast::ItemKind::Mod(ref _mod) => { + ast::ItemKind::Mod(unsafety, ref mod_kind) => { self.head(self.to_string(|s| { s.print_visibility(&item.vis); - s.print_unsafety(_mod.unsafety); + s.print_unsafety(unsafety); s.word("mod"); })); self.print_ident(item.ident); - if _mod.inline || self.is_expanded { - self.nbsp(); - self.bopen(); - self.print_inner_attributes(&item.attrs); - for item in &_mod.items { - self.print_item(item); + match mod_kind { + ModKind::Loaded(items, ..) => { + self.nbsp(); + self.bopen(); + self.print_inner_attributes(&item.attrs); + for item in items { + self.print_item(item); + } + self.bclose(item.span); + } + ModKind::Unloaded => { + self.s.word(";"); + self.end(); // end inner head-block + self.end(); // end outer head-block } - self.bclose(item.span); - } else { - self.s.word(";"); - self.end(); // end inner head-block - self.end(); // end outer head-block } } ast::ItemKind::ForeignMod(ref nmod) => { diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 8c5431a47db83..28e8259784387 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -1,10 +1,10 @@ // Code that generates a test runner to run all the tests in a crate use rustc_ast as ast; -use rustc_ast::attr; use rustc_ast::entry::EntryPointType; use rustc_ast::mut_visit::{ExpectOne, *}; use rustc_ast::ptr::P; +use rustc_ast::{attr, ModKind}; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; @@ -106,10 +106,6 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { if let ast::ItemKind::Mod(..) = item.kind { let tests = mem::take(&mut self.tests); noop_visit_item_kind(&mut item.kind, self); - let module = match item.kind { - ast::ItemKind::Mod(module) => module, - _ => unreachable!(), - }; let mut tests = mem::replace(&mut self.tests, tests); if !tests.is_empty() { @@ -117,8 +113,12 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id }; // Create an identifier that will hygienically resolve the test // case name, even in another module. + let inner_span = match item.kind { + ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span, + _ => unreachable!(), + }; let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass( - module.inner, + inner_span, AstPass::TestHarness, &[], Some(parent), @@ -130,7 +130,6 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { } self.cx.test_cases.extend(tests); } - item.kind = ast::ItemKind::Mod(module); } smallvec![P(item)] } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index c570cc1ff350b..5a4737842f0af 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -12,8 +12,8 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; -use rustc_ast::{AttrItem, AttrStyle, Block, ItemKind, LitKind, MacArgs}; -use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, NestedMetaItem}; +use rustc_ast::{AttrItem, AttrStyle, Block, Inline, ItemKind, LitKind, MacArgs}; +use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem}; use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; @@ -367,12 +367,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let krate_item = AstFragment::Items(smallvec![P(ast::Item { attrs: krate.attrs, span: krate.span, - kind: ast::ItemKind::Mod(ast::Mod { - inner: krate.span, - unsafety: Unsafe::No, - items: krate.items, - inline: true - }), + kind: ast::ItemKind::Mod( + Unsafe::No, + ModKind::Loaded(krate.items, Inline::Yes, krate.span) + ), ident: Ident::invalid(), id: ast::DUMMY_NODE_ID, vis: ast::Visibility { @@ -384,9 +382,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { })]); match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) { - Some(ast::Item { attrs, kind: ast::ItemKind::Mod(module), .. }) => { + Some(ast::Item { + attrs, + kind: ast::ItemKind::Mod(_, ModKind::Loaded(items, ..)), + .. + }) => { krate.attrs = attrs; - krate.items = module.items; + krate.items = items; } None => { // Resolution failed so we return an empty expansion @@ -809,7 +811,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> { fn visit_item(&mut self, item: &'ast ast::Item) { match &item.kind { - ast::ItemKind::Mod(module) if !module.inline => { + ast::ItemKind::Mod(_, mod_kind) + if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) => + { feature_err( self.parse_sess, sym::proc_macro_hygiene, @@ -1266,47 +1270,47 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { _ => unreachable!(), }) } - ast::ItemKind::Mod(ref mut old_mod @ ast::Mod { .. }) if ident != Ident::invalid() => { + ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => { let sess = &self.cx.sess.parse_sess; let orig_ownership = self.cx.current_expansion.directory_ownership; let mut module = (*self.cx.current_expansion.module).clone(); 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(&self.cx.sess, ident, &item.attrs, dir) - } else { - // We have an outline `mod foo;` so we need to parse the file. - let (ast::Mod { unsafety, inline, items, inner }, dir) = parse_external_mod( - &self.cx.sess, - ident, - span, - old_mod.unsafety, - dir, - &mut attrs, - pushed, - ); - - let krate = ast::Crate { attrs, items, span: inner, proc_macros: vec![] }; - if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded { - extern_mod_loaded(&krate, ident); + let Directory { ownership, path } = match mod_kind { + ModKind::Loaded(_, Inline::Yes, _) => { + // Inline `mod foo { ... }`, but we still need to push directories. + item.attrs = attrs; + push_directory(&self.cx.sess, ident, &item.attrs, dir) + } + ModKind::Loaded(_, Inline::No, _) => { + panic!("`mod` item is loaded from a file for the second time") } + ModKind::Unloaded => { + // We have an outline `mod foo;` so we need to parse the file. + let (items, inner_span, dir) = + parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed); + + let krate = + ast::Crate { attrs, items, span: inner_span, proc_macros: vec![] }; + if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded { + extern_mod_loaded(&krate, ident); + } - *old_mod = ast::Mod { unsafety, inline, items: krate.items, inner }; - item.attrs = krate.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(); + *mod_kind = ModKind::Loaded(krate.items, Inline::No, inner_span); + item.attrs = krate.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(); } - return Default::default(); - } - }; - dir + }; + dir + } }; // Set the module info before we flat map. diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index d63625fea465c..076d3b02be93f 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -1,4 +1,5 @@ -use rustc_ast::{token, Attribute, Mod, Unsafe}; +use rustc_ast::ptr::P; +use rustc_ast::{token, Attribute, Item}; use rustc_errors::{struct_span_err, PResult}; use rustc_parse::new_parser_from_file; use rustc_session::parse::ParseSess; @@ -42,11 +43,10 @@ crate fn parse_external_mod( sess: &Session, id: Ident, span: Span, // The span to blame on errors. - unsafety: Unsafe, Directory { mut ownership, path }: Directory, attrs: &mut Vec, pop_mod_stack: &mut bool, -) -> (Mod, Directory) { +) -> (Vec>, Span, 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. @@ -62,25 +62,22 @@ crate fn parse_external_mod( // Actually parse the external file as a module. let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)); - let (inner_attrs, items, inner) = parser.parse_mod(&token::Eof)?; - (Mod { unsafety, inline: false, items, inner }, inner_attrs) + let (mut inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof)?; + attrs.append(&mut inner_attrs); + (items, inner_span) }; // (1) ...instead, we return a dummy module. - let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_else(|_| { - let module = Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }; - (module, Vec::new()) - }); - attrs.append(&mut new_attrs); + let (items, inner_span) = result.map_err(|mut err| err.emit()).unwrap_or_default(); - // Extract the directory path for submodules of `module`. - let path = sess.source_map().span_to_unmapped_path(module.inner); + // Extract the directory path for submodules of the module. + let path = sess.source_map().span_to_unmapped_path(inner_span); let mut path = match path { FileName::Real(name) => name.into_local_path(), other => PathBuf::from(other.to_string()), }; path.pop(); - (module, Directory { ownership, path }) + (items, inner_span, Directory { ownership, path }) } fn error_on_circular_module<'a>( diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs index f4fcaf5c0a452..56f25ffdb0187 100644 --- a/compiler/rustc_expand/src/parse/tests.rs +++ b/compiler/rustc_expand/src/parse/tests.rs @@ -309,8 +309,8 @@ fn out_of_line_mod() { .unwrap() .unwrap(); - if let ast::ItemKind::Mod(ref m) = item.kind { - assert!(m.items.len() == 2); + if let ast::ItemKind::Mod(_, ref mod_kind) = item.kind { + assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2)); } else { panic!(); } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c0464c3edbc04..0f907859a19a6 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -35,14 +35,16 @@ impl<'a> Parser<'a> { let unsafety = self.parse_unsafety(); self.expect_keyword(kw::Mod)?; let id = self.parse_ident()?; - let ((mut inner_attrs, items, inner), inline) = if self.eat(&token::Semi) { - ((Vec::new(), Vec::new(), Span::default()), false) + let mod_kind = if self.eat(&token::Semi) { + ModKind::Unloaded } else { self.expect(&token::OpenDelim(token::Brace))?; - (self.parse_mod(&token::CloseDelim(token::Brace))?, true) + let (mut inner_attrs, items, inner_span) = + self.parse_mod(&token::CloseDelim(token::Brace))?; + attrs.append(&mut inner_attrs); + ModKind::Loaded(items, Inline::Yes, inner_span) }; - attrs.append(&mut inner_attrs); - Ok((id, ItemKind::Mod(Mod { unsafety, inline, items, inner }))) + Ok((id, ItemKind::Mod(unsafety, mod_kind))) } /// Parses the contents of a module (inner attributes followed by module items). diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index cca40a793dd00..09ab84eaeb613 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1023,7 +1023,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); } - ItemKind::Mod(_) | ItemKind::ForeignMod(_) => { + ItemKind::Mod(..) | ItemKind::ForeignMod(_) => { self.with_scope(item.id, |this| { visit::walk_item(this, item); }); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8140700471991..77fbbaa1532af 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -29,7 +29,7 @@ use rustc_ast::unwrap_or; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, NodeId}; use rustc_ast::{Crate, CRATE_NODE_ID}; -use rustc_ast::{ItemKind, Path}; +use rustc_ast::{ItemKind, ModKind, Path}; use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; @@ -339,8 +339,8 @@ impl UsePlacementFinder { impl<'tcx> Visitor<'tcx> for UsePlacementFinder { fn visit_item(&mut self, item: &'tcx ast::Item) { - if let ItemKind::Mod(module) = &item.kind { - if let ControlFlow::Break(..) = self.check_mod(&module.items, item.id) { + if let ItemKind::Mod(_, ModKind::Loaded(items, ..)) = &item.kind { + if let ControlFlow::Break(..) = self.check_mod(items, item.id) { return; } } diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs index 642326469725f..9ff7ef7cc3b55 100644 --- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs @@ -241,9 +241,12 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r)) } - (Mod(l), Mod(r)) => { - l.inline == r.inline && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_item_kind)) - } + (Mod(lu, lmk), Mod(ru, rmk)) => lu == ru && match (lmk, rmk) { + (ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) => + linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind)), + (ModKind::Unloaded, ModKind::Unloaded) => true, + _ => false, + }, (ForeignMod(l), ForeignMod(r)) => { both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r)) && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind)) From 9889e44470cbc6ae3c8e2fcfb6016ed15ed8cf51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Thu, 18 Feb 2021 17:53:09 +0300 Subject: [PATCH 08/14] Fix popping singleton paths in when generating E0433 Fixes #82156 --- compiler/rustc_resolve/src/late.rs | 11 +++++------ src/test/ui/resolve/issue-82156.rs | 3 +++ src/test/ui/resolve/issue-82156.stderr | 9 +++++++++ 3 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/resolve/issue-82156.rs create mode 100644 src/test/ui/resolve/issue-82156.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index cca40a793dd00..bf7acddde7564 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1801,7 +1801,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { crate_lint: CrateLint, ) -> PartialRes { tracing::debug!( - "smart_resolve_path_fragment(id={:?},qself={:?},path={:?}", + "smart_resolve_path_fragment(id={:?}, qself={:?}, path={:?})", id, qself, path @@ -1841,11 +1841,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Before we start looking for candidates, we have to get our hands // on the type user is trying to perform invocation on; basically: - // we're transforming `HashMap::new` into just `HashMap` - let path = if let Some((_, path)) = path.split_last() { - path - } else { - return Some(parent_err); + // we're transforming `HashMap::new` into just `HashMap`. + let path = match path.split_last() { + Some((_, path)) if !path.is_empty() => path, + _ => return Some(parent_err), }; let (mut err, candidates) = diff --git a/src/test/ui/resolve/issue-82156.rs b/src/test/ui/resolve/issue-82156.rs new file mode 100644 index 0000000000000..6215259e48657 --- /dev/null +++ b/src/test/ui/resolve/issue-82156.rs @@ -0,0 +1,3 @@ +fn main() { + super(); //~ ERROR failed to resolve: there are too many leading `super` keywords +} diff --git a/src/test/ui/resolve/issue-82156.stderr b/src/test/ui/resolve/issue-82156.stderr new file mode 100644 index 0000000000000..d53599dcce61b --- /dev/null +++ b/src/test/ui/resolve/issue-82156.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: there are too many leading `super` keywords + --> $DIR/issue-82156.rs:2:5 + | +LL | super(); + | ^^^^^ there are too many leading `super` keywords + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. From 3e7ea401cd050320bf43f3bfcb1bfa97fc3a9b35 Mon Sep 17 00:00:00 2001 From: Gus Wynn Date: Thu, 18 Feb 2021 08:17:43 -0800 Subject: [PATCH 09/14] ignore file length --- compiler/rustc_hir/src/hir.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e5829b1c4f713..658e20bcaa9db 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength use crate::def::{DefKind, Namespace, Res}; use crate::def_id::DefId; crate use crate::hir_id::HirId; From e92e5fd7878bb9f8f355149bd4d2b1430c53b58b Mon Sep 17 00:00:00 2001 From: mark Date: Sun, 7 Feb 2021 22:50:02 -0600 Subject: [PATCH 10/14] add Mutex::unlock --- library/std/src/sync/mutex.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index a01ebb316e886..ab61618dc7d7b 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -219,6 +219,26 @@ impl Mutex { data: UnsafeCell::new(t), } } + + /// Immediately drops the guard, and consequently unlocks the mutex. + /// + /// This function is equivalent to calling [`drop`] on the guard but is more self-documenting. + /// Alternately, the guard will be automatically dropped when it goes out of scope. + /// + /// ``` + /// #![feature(mutex_unlock)] + /// + /// use std::sync::Mutex; + /// let mutex = Mutex::new(0); + /// + /// let mut guard = mutex.lock().unwrap(); + /// *guard += 20; + /// Mutex::unlock(guard); + /// ``` + #[unstable(feature = "mutex_unlock", issue = "81872")] + pub fn unlock(guard: MutexGuard<'_, T>) { + drop(guard); + } } impl Mutex { From 1605af015c493c4800be9b56d7eb8d759f9a7d3c Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Thu, 18 Feb 2021 12:41:08 -0800 Subject: [PATCH 11/14] libtest: Fix unwrap panic on duplicate TestDesc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible for different tests to collide to the same TestDesc when macros are involved. That is a bug, but it didn’t cause a panic until #81367. For now, change the code to ignore this problem. Fixes #81852. Signed-off-by: Anders Kaseorg --- library/test/src/lib.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 3ff79eaea49ab..2d37fdd135eee 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -353,12 +353,13 @@ where } let mut completed_test = res.unwrap(); - let running_test = running_tests.remove(&completed_test.desc).unwrap(); - if let Some(join_handle) = running_test.join_handle { - if let Err(_) = join_handle.join() { - if let TrOk = completed_test.result { - completed_test.result = - TrFailedMsg("panicked after reporting success".to_string()); + if let Some(running_test) = running_tests.remove(&completed_test.desc) { + if let Some(join_handle) = running_test.join_handle { + if let Err(_) = join_handle.join() { + if let TrOk = completed_test.result { + completed_test.result = + TrFailedMsg("panicked after reporting success".to_string()); + } } } } From 34a94d38584f2dce45338f40d78c12f296035803 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 18 Feb 2021 13:04:05 -0800 Subject: [PATCH 12/14] Update cargo --- Cargo.lock | 2 +- src/tools/cargo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1011c0f479cb..9f43f5a8b36b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -285,7 +285,7 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da" [[package]] name = "cargo" -version = "0.52.0" +version = "0.53.0" dependencies = [ "anyhow", "atty", diff --git a/src/tools/cargo b/src/tools/cargo index ab64d1393b5b7..bf5a5d5e5d3ae 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit ab64d1393b5b77c66b6534ef5023a1b89ee7bf64 +Subproject commit bf5a5d5e5d3ae842a63bfce6d070dfd438cf6070 From 5d2a2a1caa1a12a5c445fcc99e2dee42e5a5f3d7 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 5 Dec 2020 13:12:39 -0800 Subject: [PATCH 13/14] Add explanations and suggestions to `irrefutable_let_patterns` lint --- compiler/rustc_lint_defs/src/builtin.rs | 8 ++--- .../src/thir/pattern/check_match.rs | 35 ++++++++++++++----- ...e-origin-single-variant-diagnostics.stderr | 2 ++ src/test/ui/expr/if/if-let.stderr | 16 +++++++++ .../deny-irrefutable-let-patterns.rs | 8 +++++ .../deny-irrefutable-let-patterns.stderr | 22 +++++++++--- .../ui/rfc-2294-if-let-guard/warns.stderr | 4 ++- src/test/ui/while-let.stderr | 7 ++++ 8 files changed, 83 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 8eeee19cc298a..686d09dd7fcb4 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1814,14 +1814,12 @@ declare_lint! { } declare_lint! { - /// The `irrefutable_let_patterns` lint detects detects [irrefutable - /// patterns] in [`if let`] and [`while let`] statements. - /// - /// + /// The `irrefutable_let_patterns` lint detects [irrefutable patterns] + /// in [`if let`]s, [`while let`]s, and `if let` guards. /// /// ### Example /// - /// ```rust + /// ``` /// if let _ = 123 { /// println!("always runs!"); /// } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index e928f3c5d4d09..fdecbb9478808 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -366,14 +366,31 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option< } fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) { - tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| { - let msg = match source { - hir::MatchSource::IfLetDesugar { .. } => "irrefutable `if let` pattern", - hir::MatchSource::WhileLetDesugar => "irrefutable `while let` pattern", - hir::MatchSource::IfLetGuardDesugar => "irrefutable `if let` guard", - _ => bug!(), - }; - lint.build(msg).emit() + tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source { + hir::MatchSource::IfLetDesugar { .. } => { + let mut diag = lint.build("irrefutable `if let` pattern"); + diag.note("this pattern will always match, so the `if let` is useless"); + diag.help("consider replacing the `if let` with a `let`"); + diag.emit() + } + hir::MatchSource::WhileLetDesugar => { + let mut diag = lint.build("irrefutable `while let` pattern"); + diag.note("this pattern will always match, so the loop will never exit"); + diag.help("consider instead using a `loop { ... }` with a `let` inside it"); + diag.emit() + } + hir::MatchSource::IfLetGuardDesugar => { + let mut diag = lint.build("irrefutable `if let` guard pattern"); + diag.note("this pattern will always match, so the guard is useless"); + diag.help("consider removing the guard and adding a `let` inside the match arm"); + diag.emit() + } + _ => { + bug!( + "expected `if let`, `while let`, or `if let` guard HIR match source, found {:?}", + source, + ) + } }); } @@ -387,7 +404,7 @@ fn check_if_let_guard<'p, 'tcx>( report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar); if report.non_exhaustiveness_witnesses.is_empty() { - // The match is exhaustive, i.e. the if let pattern is irrefutable. + // The match is exhaustive, i.e. the `if let` pattern is irrefutable. irrefutable_let_pattern(cx.tcx, pat.span, pat_id, hir::MatchSource::IfLetGuardDesugar) } } diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr index 5c7a56c7ceda4..8586dfd91863c 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr @@ -17,6 +17,8 @@ LL | | } | |_________^ | = note: `#[warn(irrefutable_let_patterns)]` on by default + = note: this pattern will always match, so the `if let` is useless + = help: consider replacing the `if let` with a `let` error[E0382]: use of moved value: `c` --> $DIR/closure-origin-single-variant-diagnostics.rs:25:13 diff --git a/src/test/ui/expr/if/if-let.stderr b/src/test/ui/expr/if/if-let.stderr index 468e913a773c0..c64c9093ee54a 100644 --- a/src/test/ui/expr/if/if-let.stderr +++ b/src/test/ui/expr/if/if-let.stderr @@ -10,6 +10,8 @@ LL | | }); | |_______- in this macro invocation | = note: `#[warn(irrefutable_let_patterns)]` on by default + = note: this pattern will always match, so the `if let` is useless + = help: consider replacing the `if let` with a `let` = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: irrefutable `if let` pattern @@ -23,6 +25,8 @@ LL | | println!("irrefutable pattern"); LL | | }); | |_______- in this macro invocation | + = note: this pattern will always match, so the `if let` is useless + = help: consider replacing the `if let` with a `let` = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: irrefutable `if let` pattern @@ -32,6 +36,9 @@ LL | / if let a = 1 { LL | | println!("irrefutable pattern"); LL | | } | |_____^ + | + = note: this pattern will always match, so the `if let` is useless + = help: consider replacing the `if let` with a `let` warning: irrefutable `if let` pattern --> $DIR/if-let.rs:30:5 @@ -44,6 +51,9 @@ LL | | } else { LL | | println!("else in irrefutable `if let`"); LL | | } | |_____^ + | + = note: this pattern will always match, so the `if let` is useless + = help: consider replacing the `if let` with a `let` warning: irrefutable `if let` pattern --> $DIR/if-let.rs:40:12 @@ -53,6 +63,9 @@ LL | } else if let a = 1 { LL | | println!("irrefutable pattern"); LL | | } | |_____^ + | + = note: this pattern will always match, so the `if let` is useless + = help: consider replacing the `if let` with a `let` warning: irrefutable `if let` pattern --> $DIR/if-let.rs:46:12 @@ -62,6 +75,9 @@ LL | } else if let a = 1 { LL | | println!("irrefutable pattern"); LL | | } | |_____^ + | + = note: this pattern will always match, so the `if let` is useless + = help: consider replacing the `if let` with a `let` warning: 6 warnings emitted diff --git a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs index c1cfa4695c9ee..7549eae7016b5 100644 --- a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs +++ b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs @@ -1,3 +1,6 @@ +#![feature(if_let_guard)] +#![allow(incomplete_features)] + #![deny(irrefutable_let_patterns)] fn main() { @@ -6,4 +9,9 @@ fn main() { while let _ = 5 { //~ ERROR irrefutable `while let` pattern break; } + + match 5 { + _ if let _ = 2 => {} //~ ERROR irrefutable `if let` guard pattern + _ => {} + } } diff --git a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr index 1de30f7db0698..d6926ee12eeaa 100644 --- a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr +++ b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr @@ -1,22 +1,36 @@ error: irrefutable `if let` pattern - --> $DIR/deny-irrefutable-let-patterns.rs:4:5 + --> $DIR/deny-irrefutable-let-patterns.rs:7:5 | LL | if let _ = 5 {} | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/deny-irrefutable-let-patterns.rs:1:9 + --> $DIR/deny-irrefutable-let-patterns.rs:4:9 | LL | #![deny(irrefutable_let_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this pattern will always match, so the `if let` is useless + = help: consider replacing the `if let` with a `let` error: irrefutable `while let` pattern - --> $DIR/deny-irrefutable-let-patterns.rs:6:5 + --> $DIR/deny-irrefutable-let-patterns.rs:9:5 | LL | / while let _ = 5 { LL | | break; LL | | } | |_____^ + | + = note: this pattern will always match, so the loop will never exit + = help: consider instead using a `loop { ... }` with a `let` inside it + +error: irrefutable `if let` guard pattern + --> $DIR/deny-irrefutable-let-patterns.rs:14:18 + | +LL | _ if let _ = 2 => {} + | ^ + | + = note: this pattern will always match, so the guard is useless + = help: consider removing the guard and adding a `let` inside the match arm -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.stderr b/src/test/ui/rfc-2294-if-let-guard/warns.stderr index 33fa25d32fb1b..c7627f1c3c50c 100644 --- a/src/test/ui/rfc-2294-if-let-guard/warns.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/warns.stderr @@ -1,4 +1,4 @@ -error: irrefutable `if let` guard +error: irrefutable `if let` guard pattern --> $DIR/warns.rs:7:24 | LL | Some(x) if let () = x => {} @@ -9,6 +9,8 @@ note: the lint level is defined here | LL | #[deny(irrefutable_let_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this pattern will always match, so the guard is useless + = help: consider removing the guard and adding a `let` inside the match arm error: unreachable pattern --> $DIR/warns.rs:16:25 diff --git a/src/test/ui/while-let.stderr b/src/test/ui/while-let.stderr index 6538b9fbe6f28..04e77bf9470a2 100644 --- a/src/test/ui/while-let.stderr +++ b/src/test/ui/while-let.stderr @@ -10,6 +10,8 @@ LL | | }); | |_______- in this macro invocation | = note: `#[warn(irrefutable_let_patterns)]` on by default + = note: this pattern will always match, so the loop will never exit + = help: consider instead using a `loop { ... }` with a `let` inside it = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: irrefutable `while let` pattern @@ -23,6 +25,8 @@ LL | | println!("irrefutable pattern"); LL | | }); | |_______- in this macro invocation | + = note: this pattern will always match, so the loop will never exit + = help: consider instead using a `loop { ... }` with a `let` inside it = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: irrefutable `while let` pattern @@ -33,6 +37,9 @@ LL | | println!("irrefutable pattern"); LL | | break; LL | | } | |_____^ + | + = note: this pattern will always match, so the loop will never exit + = help: consider instead using a `loop { ... }` with a `let` inside it warning: 3 warnings emitted From 755b3fc722c36d9761bf49c246b5f7c85a62380d Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Thu, 18 Feb 2021 16:15:24 +0100 Subject: [PATCH 14/14] rustdoc: Support argument files Factors out the `rustc_driver` logic that handles argument files so that rustdoc supports them as well, e.g.: rustdoc @argfile This is needed to be able to generate docs for projects that already use argument files when compiling them, e.g. projects that pass a huge number of `--cfg` arguments. The feature was stabilized for `rustc` in #66172. Signed-off-by: Miguel Ojeda --- compiler/rustc_driver/src/args.rs | 16 +++++++++++++++- compiler/rustc_driver/src/lib.rs | 14 +++----------- src/doc/rustdoc/src/command-line-arguments.md | 7 +++++++ src/librustdoc/lib.rs | 5 ++++- .../rustdoc-ui/commandline-argfile-badutf8.args | 2 ++ .../rustdoc-ui/commandline-argfile-badutf8.rs | 12 ++++++++++++ .../commandline-argfile-badutf8.stderr | 2 ++ .../rustdoc-ui/commandline-argfile-missing.rs | 15 +++++++++++++++ .../commandline-argfile-missing.stderr | 2 ++ src/test/rustdoc-ui/commandline-argfile.args | 2 ++ src/test/rustdoc-ui/commandline-argfile.rs | 13 +++++++++++++ 11 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 src/test/rustdoc-ui/commandline-argfile-badutf8.args create mode 100644 src/test/rustdoc-ui/commandline-argfile-badutf8.rs create mode 100644 src/test/rustdoc-ui/commandline-argfile-badutf8.stderr create mode 100644 src/test/rustdoc-ui/commandline-argfile-missing.rs create mode 100644 src/test/rustdoc-ui/commandline-argfile-missing.stderr create mode 100644 src/test/rustdoc-ui/commandline-argfile.args create mode 100644 src/test/rustdoc-ui/commandline-argfile.rs diff --git a/compiler/rustc_driver/src/args.rs b/compiler/rustc_driver/src/args.rs index 4f2febf04b135..01338359f1af1 100644 --- a/compiler/rustc_driver/src/args.rs +++ b/compiler/rustc_driver/src/args.rs @@ -3,7 +3,7 @@ use std::fmt; use std::fs; use std::io; -pub fn arg_expand(arg: String) -> Result, Error> { +fn arg_expand(arg: String) -> Result, Error> { if let Some(path) = arg.strip_prefix('@') { let file = match fs::read_to_string(path) { Ok(file) => file, @@ -18,6 +18,20 @@ pub fn arg_expand(arg: String) -> Result, Error> { } } +pub fn arg_expand_all(at_args: &[String]) -> Vec { + let mut args = Vec::new(); + for arg in at_args { + match arg_expand(arg.clone()) { + Ok(arg) => args.extend(arg), + Err(err) => rustc_session::early_error( + rustc_session::config::ErrorOutputType::default(), + &format!("Failed to load argument file: {}", err), + ), + } + } + args +} + #[derive(Debug)] pub enum Error { Utf8Error(Option), diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 15b984acac590..2aa20dc1e6436 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -55,7 +55,7 @@ use std::process::{self, Command, Stdio}; use std::str; use std::time::Instant; -mod args; +pub mod args; pub mod pretty; /// Exit status code used for successful compilation and help output. @@ -188,16 +188,8 @@ fn run_compiler( Box Box + Send>, >, ) -> interface::Result<()> { - let mut args = Vec::new(); - for arg in at_args { - match args::arg_expand(arg.clone()) { - Ok(arg) => args.extend(arg), - Err(err) => early_error( - ErrorOutputType::default(), - &format!("Failed to load argument file: {}", err), - ), - } - } + let args = args::arg_expand_all(at_args); + let diagnostic_output = emitter.map_or(DiagnosticOutput::Default, DiagnosticOutput::Raw); let matches = match handle_options(&args) { Some(matches) => matches, diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index 80f7851debfbd..0302fbecb6ed0 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -422,3 +422,10 @@ $ rustdoc src/lib.rs --crate-version 1.3.37 When `rustdoc` receives this flag, it will print an extra "Version (version)" into the sidebar of the crate root's docs. You can use this flag to differentiate between different versions of your library's documentation. + +## `@path`: load command-line flags from a path + +If you specify `@path` on the command-line, then it will open `path` and read +command line options from it. These options are one per line; a blank line indicates +an empty option. The file can use Unix or Windows style line endings, and must be +encoded as UTF-8. diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index c61cbf78f771a..5394d23e1c535 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -432,13 +432,16 @@ fn usage(argv0: &str) { (option.apply)(&mut options); } println!("{}", options.usage(&format!("{} [options] ", argv0))); + println!(" @path Read newline separated options from `path`\n"); println!("More information available at https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html") } /// A result type used by several functions under `main()`. type MainResult = Result<(), ErrorReported>; -fn main_args(args: &[String]) -> MainResult { +fn main_args(at_args: &[String]) -> MainResult { + let args = rustc_driver::args::arg_expand_all(at_args); + let mut options = getopts::Options::new(); for option in opts() { (option.apply)(&mut options); diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.args b/src/test/rustdoc-ui/commandline-argfile-badutf8.args new file mode 100644 index 0000000000000..c070b0c2400d8 --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile-badutf8.args @@ -0,0 +1,2 @@ +--cfg +unbroken€ \ No newline at end of file diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.rs b/src/test/rustdoc-ui/commandline-argfile-badutf8.rs new file mode 100644 index 0000000000000..e2984e3ca97ac --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile-badutf8.rs @@ -0,0 +1,12 @@ +// Check to see if we can get parameters from an @argsfile file +// +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.stderr b/src/test/rustdoc-ui/commandline-argfile-badutf8.stderr new file mode 100644 index 0000000000000..9af6fc0a518df --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile-badutf8.stderr @@ -0,0 +1,2 @@ +error: Failed to load argument file: Utf8 error in $DIR/commandline-argfile-badutf8.args + diff --git a/src/test/rustdoc-ui/commandline-argfile-missing.rs b/src/test/rustdoc-ui/commandline-argfile-missing.rs new file mode 100644 index 0000000000000..020c3ff3c7e63 --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile-missing.rs @@ -0,0 +1,15 @@ +// Check to see if we can get parameters from an @argsfile file +// +// ignore-tidy-linelength +// normalize-stderr-test: "os error \d+" -> "os error $$ERR" +// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING " +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/rustdoc-ui/commandline-argfile-missing.stderr b/src/test/rustdoc-ui/commandline-argfile-missing.stderr new file mode 100644 index 0000000000000..179ad83100419 --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile-missing.stderr @@ -0,0 +1,2 @@ +error: Failed to load argument file: IO Error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR) + diff --git a/src/test/rustdoc-ui/commandline-argfile.args b/src/test/rustdoc-ui/commandline-argfile.args new file mode 100644 index 0000000000000..972938bf6c8dd --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile.args @@ -0,0 +1,2 @@ +--cfg +unbroken \ No newline at end of file diff --git a/src/test/rustdoc-ui/commandline-argfile.rs b/src/test/rustdoc-ui/commandline-argfile.rs new file mode 100644 index 0000000000000..cc8c8722c1c35 --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// check-pass +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +}