diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast_lowering/src/path.rs | 19 | ||||
| -rw-r--r-- | compiler/rustc_ast_passes/messages.ftl | 2 | ||||
| -rw-r--r-- | compiler/rustc_ast_passes/src/ast_validation.rs | 46 | ||||
| -rw-r--r-- | compiler/rustc_ast_passes/src/errors.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_error_codes/src/error_codes/E0667.md | 6 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs | 154 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/builtin.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/context.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/early.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/late.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lib.rs | 12 |
12 files changed, 113 insertions, 214 deletions
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 258655de486..6a0f03c8b31 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -34,7 +34,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { modifiers: Option<ast::TraitBoundModifiers>, ) -> hir::QPath<'hir> { let qself_position = qself.as_ref().map(|q| q.position); - let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); + let qself = qself + .as_ref() + // Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`. + .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))); let partial_res = self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); @@ -75,6 +78,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { None }; + // Only permit `impl Trait` in the final segment. E.g., we permit `Option<impl Trait>`, + // `option::Option<T>::Xyz<impl Trait>` and reject `option::Option<impl Trait>::Xyz`. + let itctx = |i| { + if i + 1 == p.segments.len() { + itctx + } else { + ImplTraitContext::Disallowed(ImplTraitPosition::Path) + } + }; + let path_span_lo = p.span.shrink_to_lo(); let proj_start = p.segments.len() - unresolved_segments; let path = self.arena.alloc(hir::Path { @@ -121,7 +134,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, generic_args_mode, - itctx, + itctx(i), bound_modifier_allowed_features.clone(), ) }, @@ -185,7 +198,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, generic_args_mode, - itctx, + itctx(i), None, )); let qpath = hir::QPath::TypeRelative(ty, hir_segment); diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 92acaaa5f36..d81fd53938b 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -146,8 +146,6 @@ ast_passes_generic_before_constraints = generic arguments must come before the f ast_passes_generic_default_trailing = generic parameters with a default must be trailing -ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters - ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed .help = remove one of these features diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1d149e91b85..0a4f86d4822 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -80,10 +80,6 @@ struct AstValidator<'a> { disallow_tilde_const: Option<TildeConstReason>, - /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item` - /// or `Foo::Bar<impl Trait>` - is_impl_trait_banned: bool, - /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. extern_mod_safety: Option<Safety>, @@ -123,12 +119,6 @@ impl<'a> AstValidator<'a> { self.extern_mod_safety = old; } - fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.is_impl_trait_banned, true); - f(self); - self.is_impl_trait_banned = old; - } - fn with_tilde_const( &mut self, disallowed: Option<TildeConstReason>, @@ -213,37 +203,6 @@ impl<'a> AstValidator<'a> { .with_tilde_const(Some(TildeConstReason::TraitObject), |this| { visit::walk_ty(this, t) }), - TyKind::Path(qself, path) => { - // We allow these: - // - `Option<impl Trait>` - // - `option::Option<impl Trait>` - // - `option::Option<T>::Foo<impl Trait>` - // - // But not these: - // - `<impl Trait>::Foo` - // - `option::Option<impl Trait>::Foo`. - // - // To implement this, we disallow `impl Trait` from `qself` - // (for cases like `<impl Trait>::Foo>`) - // but we allow `impl Trait` in `GenericArgs` - // iff there are no more PathSegments. - if let Some(qself) = qself { - // `impl Trait` in `qself` is always illegal - self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty)); - } - - // Note that there should be a call to visit_path here, - // so if any logic is added to process `Path`s a call to it should be - // added both in visit_path and here. This code mirrors visit::walk_path. - for (i, segment) in path.segments.iter().enumerate() { - // Allow `impl Trait` iff we're on the final path segment - if i == path.segments.len() - 1 { - self.visit_path_segment(segment); - } else { - self.with_banned_impl_trait(|this| this.visit_path_segment(segment)); - } - } - } _ => visit::walk_ty(self, t), } } @@ -737,10 +696,6 @@ impl<'a> AstValidator<'a> { } } TyKind::ImplTrait(_, bounds) => { - if self.is_impl_trait_banned { - self.dcx().emit_err(errors::ImplTraitPath { span: ty.span }); - } - if let Some(outer_impl_trait_sp) = self.outer_impl_trait { self.dcx().emit_err(errors::NestedImplTrait { span: ty.span, @@ -1729,7 +1684,6 @@ pub fn check_crate( has_proc_macro_decls: false, outer_impl_trait: None, disallow_tilde_const: Some(TildeConstReason::Item), - is_impl_trait_banned: false, extern_mod_safety: None, lint_buffer: lints, }; diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 4ca1acde1e2..8c3ac9864ed 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -419,13 +419,6 @@ pub(crate) struct TraitObjectBound { } #[derive(Diagnostic)] -#[diag(ast_passes_impl_trait_path, code = E0667)] -pub(crate) struct ImplTraitPath { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(ast_passes_nested_impl_trait, code = E0666)] pub(crate) struct NestedImplTrait { #[primary_span] diff --git a/compiler/rustc_error_codes/src/error_codes/E0667.md b/compiler/rustc_error_codes/src/error_codes/E0667.md index 0709a24c433..339bc068610 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0667.md +++ b/compiler/rustc_error_codes/src/error_codes/E0667.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + `impl Trait` is not allowed in path parameters. Erroneous code example: -```compile_fail,E0667 +```ignore (removed error code) fn some_fn(mut x: impl Iterator) -> <impl Iterator>::Item { // error! x.next().unwrap() } @@ -11,7 +13,7 @@ fn some_fn(mut x: impl Iterator) -> <impl Iterator>::Item { // error! You cannot use `impl Trait` in path parameters. If you want something equivalent, you can do this instead: -``` +```ignore (removed error code) fn some_fn<T: Iterator>(mut x: T) -> T::Item { // ok! x.next().unwrap() } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 95e07244a6b..f7daef3e80c 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -33,18 +33,12 @@ use crate::errors; #[extension(trait RegionExt)] impl ResolvedArg { - fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { - debug!("ResolvedArg::early: def_id={:?}", param.def_id); - (param.def_id, ResolvedArg::EarlyBound(param.def_id)) + fn early(param: &GenericParam<'_>) -> ResolvedArg { + ResolvedArg::EarlyBound(param.def_id) } - fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { - let depth = ty::INNERMOST; - debug!( - "ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}", - idx, param, depth, param.def_id, - ); - (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id)) + fn late(idx: u32, param: &GenericParam<'_>) -> ResolvedArg { + ResolvedArg::LateBound(ty::INNERMOST, idx, param.def_id) } fn id(&self) -> Option<LocalDefId> { @@ -282,24 +276,33 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou fn late_arg_as_bound_arg<'tcx>( tcx: TyCtxt<'tcx>, - arg: &ResolvedArg, param: &GenericParam<'tcx>, ) -> ty::BoundVariableKind { - match arg { - ResolvedArg::LateBound(_, _, def_id) => { - let def_id = def_id.to_def_id(); - let name = tcx.item_name(def_id); - match param.kind { - GenericParamKind::Lifetime { .. } => { - ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) - } - GenericParamKind::Type { .. } => { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) - } - GenericParamKind::Const { .. } => ty::BoundVariableKind::Const, - } + let def_id = param.def_id.to_def_id(); + let name = tcx.item_name(def_id); + match param.kind { + GenericParamKind::Lifetime { .. } => { + ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) } - _ => bug!("{:?} is not a late argument", arg), + GenericParamKind::Type { .. } => { + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) + } + GenericParamKind::Const { .. } => ty::BoundVariableKind::Const, + } +} + +/// Turn a [`ty::GenericParamDef`] into a bound arg. Generally, this should only +/// be used when turning early-bound vars into late-bound vars when lowering +/// return type notation. +fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVariableKind { + match param.kind { + ty::GenericParamDefKind::Lifetime => { + ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(param.def_id, param.name)) + } + ty::GenericParamDefKind::Type { .. } => { + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) + } + ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, } } @@ -360,10 +363,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = FxIndexMap::default(); let binders_iter = trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - bound_vars.insert(pair.0, pair.1); - r + let arg = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param); + bound_vars.insert(param.def_id, arg); + late_arg_as_bound_arg(self.tcx, param) }); binders.extend(binders_iter); @@ -458,9 +460,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .iter() .enumerate() .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - (pair, r) + ( + (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), + late_arg_as_bound_arg(self.tcx, param), + ) }) .unzip(); @@ -492,8 +495,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let mut bound_vars = FxIndexMap::default(); debug!(?opaque.generics.params); for param in opaque.generics.params { - let (def_id, reg) = ResolvedArg::early(param); - bound_vars.insert(def_id, reg); + let arg = ResolvedArg::early(param); + bound_vars.insert(param.def_id, arg); } let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id); @@ -618,9 +621,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .iter() .enumerate() .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - (pair, r) + ( + (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), + late_arg_as_bound_arg(self.tcx, param), + ) }) .unzip(); @@ -870,9 +874,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .iter() .enumerate() .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - (pair, r) + ( + (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), + late_arg_as_bound_arg(self.tcx, param), + ) }) .unzip(); @@ -1052,19 +1057,21 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = generics .params .iter() - .map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if self.tcx.is_late_bound(param.hir_id) { - let late_bound_idx = named_late_bound_vars; - named_late_bound_vars += 1; - ResolvedArg::late(late_bound_idx, param) - } else { + .map(|param| { + (param.def_id, match param.kind { + GenericParamKind::Lifetime { .. } => { + if self.tcx.is_late_bound(param.hir_id) { + let late_bound_idx = named_late_bound_vars; + named_late_bound_vars += 1; + ResolvedArg::late(late_bound_idx, param) + } else { + ResolvedArg::early(param) + } + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { ResolvedArg::early(param) } - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - ResolvedArg::early(param) - } + }) }) .collect(); @@ -1075,11 +1082,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { matches!(param.kind, GenericParamKind::Lifetime { .. }) && self.tcx.is_late_bound(param.hir_id) }) - .enumerate() - .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - late_arg_as_bound_arg(self.tcx, &pair.1, param) - }) + .map(|param| late_arg_as_bound_arg(self.tcx, param)) .collect(); self.record_late_bound_vars(hir_id, binders); let scope = Scope::Binder { @@ -1096,7 +1099,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { where F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>), { - let bound_vars = generics.params.iter().map(ResolvedArg::early).collect(); + let bound_vars = + generics.params.iter().map(|param| (param.def_id, ResolvedArg::early(param))).collect(); self.record_late_bound_vars(hir_id, vec![]); let scope = Scope::Binder { hir_id, @@ -1639,17 +1643,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { constraint.ident, ty::AssocKind::Fn, ) { - bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).own_params.iter().map( - |param| match param.kind { - ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( - ty::BoundRegionKind::BrNamed(param.def_id, param.name), - ), - ty::GenericParamDefKind::Type { .. } => ty::BoundVariableKind::Ty( - ty::BoundTyKind::Param(param.def_id, param.name), - ), - ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, - }, - )); + bound_vars.extend( + self.tcx + .generics_of(assoc_fn.def_id) + .own_params + .iter() + .map(|param| generic_param_def_as_bound_arg(param)), + ); bound_vars.extend( self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars(), ); @@ -1968,17 +1968,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // Append the early-bound vars on the function, and then the late-bound ones. // We actually turn type parameters into higher-ranked types here, but we // deny them later in HIR lowering. - bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| { - match param.kind { - ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( - ty::BoundRegionKind::BrNamed(param.def_id, param.name), - ), - ty::GenericParamDefKind::Type { .. } => { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) - } - ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, - } - })); + bound_vars.extend( + self.tcx + .generics_of(item_def_id) + .own_params + .iter() + .map(|param| generic_param_def_as_bound_arg(param)), + ); bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars()); // SUBTLE: Stash the old bound vars onto the *item segment* before appending diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 863c077a9e0..cfd1241ad69 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1203,15 +1203,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.emit() } else if let Err(reported) = qself_ty.error_reported() { reported - } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() { - // `<impl Trait as OtherTrait>::Assoc` makes no sense. - struct_span_code_err!( - self.dcx(), - tcx.def_span(alias_ty.def_id), - E0667, - "`impl Trait` is not allowed in path parameters" - ) - .emit() // Already reported in an earlier stage. } else { self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 3ee4980a948..dbb8c667532 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -4,21 +4,14 @@ //! AST visitor. Also see `rustc_session::lint::builtin`, which contains the //! definitions of lints that are emitted directly inside the main compiler. //! -//! To add a new lint to rustc, declare it here using `declare_lint!()`. +//! To add a new lint to rustc, declare it here using [`declare_lint!`]. //! Then add code to emit the new lint in the appropriate circumstances. -//! You can do that in an existing `LintPass` if it makes sense, or in a -//! new `LintPass`, or using `Session::add_lint` elsewhere in the -//! compiler. Only do the latter if the check can't be written cleanly as a -//! `LintPass` (also, note that such lints will need to be defined in -//! `rustc_session::lint::builtin`, not here). //! -//! If you define a new `EarlyLintPass`, you will also need to add it to the -//! `add_early_builtin!` or `add_early_builtin_with_new!` invocation in -//! `lib.rs`. Use the former for unit-like structs and the latter for structs -//! with a `pub fn new()`. +//! If you define a new [`EarlyLintPass`], you will also need to add it to the +//! [`crate::early_lint_methods!`] invocation in `lib.rs`. //! -//! If you define a new `LateLintPass`, you will also need to add it to the -//! `late_lint_methods!` invocation in `lib.rs`. +//! If you define a new [`LateLintPass`], you will also need to add it to the +//! [`crate::late_lint_methods!`] invocation in `lib.rs`. use std::fmt::Write; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 39f90a8e9ed..4af1fd1baf9 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1,18 +1,7 @@ -//! Implementation of lint checking. +//! Basic types for managing and implementing lints. //! -//! The lint checking is mostly consolidated into one pass which runs -//! after all other analyses. Throughout compilation, lint warnings -//! can be added via the `add_lint` method on the Session structure. This -//! requires a span and an ID of the node that the lint is being added to. The -//! lint isn't actually emitted at that time because it is unknown what the -//! actual lint level at that location is. -//! -//! To actually emit lint warnings/errors, a separate pass is used. -//! A context keeps track of the current state of all lint levels. -//! Upon entering a node of the ast which can modify the lint settings, the -//! previous lint state is pushed onto a stack and the ast is then recursed -//! upon. As the ast is traversed, this keeps track of the current lint level -//! for all lint attributes. +//! See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for an +//! overview of how lints are implemented. use std::cell::Cell; use std::{iter, slice}; @@ -52,9 +41,6 @@ type LateLintPassFactory = dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync; /// Information about the registered lints. -/// -/// This is basically the subset of `Context` that we can -/// build early in the compile pipeline. pub struct LintStore { /// Registered lints. lints: Vec<&'static Lint>, diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index e2247d3a1f6..acccff77a10 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -1,18 +1,8 @@ -//! Implementation of lint checking. +//! Implementation of the early lint pass. //! -//! The lint checking is mostly consolidated into one pass which runs -//! after all other analyses. Throughout compilation, lint warnings -//! can be added via the `add_lint` method on the Session structure. This -//! requires a span and an ID of the node that the lint is being added to. The -//! lint isn't actually emitted at that time because it is unknown what the -//! actual lint level at that location is. -//! -//! To actually emit lint warnings/errors, a separate pass is used. -//! A context keeps track of the current state of all lint levels. -//! Upon entering a node of the ast which can modify the lint settings, the -//! previous lint state is pushed onto a stack and the ast is then recursed -//! upon. As the ast is traversed, this keeps track of the current lint level -//! for all lint attributes. +//! The early lint pass works on AST nodes after macro expansion and name +//! resolution, just before AST lowering. These lints are for purely +//! syntactical lints. use rustc_ast::ptr::P; use rustc_ast::visit::{self as ast_visit, Visitor, walk_list}; diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 9b1877599ba..9d35ce19b57 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -1,18 +1,7 @@ -//! Implementation of lint checking. +//! Implementation of the late lint pass. //! -//! The lint checking is mostly consolidated into one pass which runs -//! after all other analyses. Throughout compilation, lint warnings -//! can be added via the `add_lint` method on the Session structure. This -//! requires a span and an ID of the node that the lint is being added to. The -//! lint isn't actually emitted at that time because it is unknown what the -//! actual lint level at that location is. -//! -//! To actually emit lint warnings/errors, a separate pass is used. -//! A context keeps track of the current state of all lint levels. -//! Upon entering a node of the ast which can modify the lint settings, the -//! previous lint state is pushed onto a stack and the ast is then recursed -//! upon. As the ast is traversed, this keeps track of the current lint level -//! for all lint attributes. +//! The late lint pass Works on HIR nodes, towards the end of analysis (after +//! borrow checking, etc.). These lints have full type information available. use std::any::Any; use std::cell::Cell; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 5389860e23b..d950b1ff5ec 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -6,20 +6,14 @@ //! other phases of the compiler, which are generally required to hold in order //! to compile the program at all. //! -//! Most lints can be written as [LintPass] instances. These run after +//! Most lints can be written as [`LintPass`] instances. These run after //! all other analyses. The `LintPass`es built into rustc are defined //! within [rustc_session::lint::builtin], //! which has further comments on how to add such a lint. //! rustc can also load external lint plugins, as is done for Clippy. //! -//! Some of rustc's lints are defined elsewhere in the compiler and work by -//! calling `add_lint()` on the overall `Session` object. This works when -//! it happens before the main lint pass, which emits the lints stored by -//! `add_lint()`. To emit lints after the main lint pass (from codegen, for -//! example) requires more effort. See `emit_lint` and `GatherNodeLevels` -//! in `context.rs`. -//! -//! Some code also exists in [rustc_session::lint], [rustc_middle::lint]. +//! See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for an +//! overview of how lints are implemented. //! //! ## Note //! |
