//! Lints in the Rust compiler.
//!
//! This contains lints which can feasibly be implemented as their own
-//! AST visitor. Also see `rustc::lint::builtin`, which contains the
-//! definitions of lints that are emitted directly inside the main
-//! compiler.
+//! 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!()`.
//! Then add code to emit the new lint in the appropriate circumstances.
//! 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::lint::builtin`, not here).
+//! `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
//! `late_lint_methods!` invocation in `lib.rs`.
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
-use rustc::hir::map::Map;
-use rustc::lint::LintDiagnosticBuilder;
-use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
use rustc_ast::ast::{self, Expr};
use rustc_ast::attr::{self, HasAttrs};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_hir::def_id::DefId;
use rustc_hir::{GenericParamKind, PatKind};
use rustc_hir::{HirIdSet, Node};
-use rustc_infer::traits::misc::can_type_implement_copy;
+use rustc_middle::lint::LintDiagnosticBuilder;
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint::FutureIncompatibleInfo;
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{BytePos, Span};
+use rustc_target::abi::VariantIdx;
+use rustc_trait_selection::traits::misc::can_type_implement_copy;
use crate::nonstandard_style::{method_context, MethodLateContext};
use log::debug;
use std::fmt::Write;
-// hardwired lints from librustc
+// hardwired lints from librustc_middle
pub use rustc_session::lint::builtin::*;
declare_lint! {
if let ast::LitKind::Bool(true) = lit.kind {
if !lit.span.from_expansion() {
let msg = "denote infinite loops with `loop { ... }`";
- let condition_span = cx.sess.source_map().def_span(e.span);
+ let condition_span = cx.sess.source_map().guess_head_span(e.span);
cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
lint.build(msg)
.span_suggestion_short(
impl BoxPointers {
fn check_heap_type(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) {
- for leaf_ty in ty.walk() {
- if leaf_ty.is_box() {
- cx.struct_span_lint(BOX_POINTERS, span, |lint| {
- lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit()
- });
+ for leaf in ty.walk() {
+ if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
+ if leaf_ty.is_box() {
+ cx.struct_span_lint(BOX_POINTERS, span, |lint| {
+ lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit()
+ });
+ }
}
}
}
})
}
- _ => return,
+ _ => {}
}
}
id: Option<hir::HirId>,
attrs: &[ast::Attribute],
sp: Span,
+ article: &'static str,
desc: &'static str,
) {
// If we're building a test harness, then warning about
let has_doc = attrs.iter().any(|a| has_doc(a));
if !has_doc {
- cx.struct_span_lint(MISSING_DOCS, cx.tcx.sess.source_map().def_span(sp), |lint| {
- lint.build(&format!("missing documentation for {}", desc)).emit()
- });
+ cx.struct_span_lint(
+ MISSING_DOCS,
+ cx.tcx.sess.source_map().guess_head_span(sp),
+ |lint| {
+ lint.build(&format!("missing documentation for {} {}", article, desc)).emit()
+ },
+ );
}
}
}
}
fn check_crate(&mut self, cx: &LateContext<'_, '_>, krate: &hir::Crate<'_>) {
- self.check_missing_docs_attrs(cx, None, &krate.attrs, krate.span, "crate");
+ self.check_missing_docs_attrs(cx, None, &krate.item.attrs, krate.item.span, "the", "crate");
for macro_def in krate.exported_macros {
let has_doc = macro_def.attrs.iter().any(|a| has_doc(a));
if !has_doc {
cx.struct_span_lint(
MISSING_DOCS,
- cx.tcx.sess.source_map().def_span(macro_def.span),
+ cx.tcx.sess.source_map().guess_head_span(macro_def.span),
|lint| lint.build("missing documentation for macro").emit(),
);
}
}
fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
- let desc = match it.kind {
- hir::ItemKind::Fn(..) => "a function",
- hir::ItemKind::Mod(..) => "a module",
- hir::ItemKind::Enum(..) => "an enum",
- hir::ItemKind::Struct(..) => "a struct",
- hir::ItemKind::Union(..) => "a union",
+ match it.kind {
hir::ItemKind::Trait(.., trait_item_refs) => {
// Issue #11592: traits are always considered exported, even when private.
if let hir::VisibilityKind::Inherited = it.vis.node {
}
return;
}
- "a trait"
}
- hir::ItemKind::TyAlias(..) => "a type alias",
hir::ItemKind::Impl { of_trait: Some(ref trait_ref), items, .. } => {
// If the trait is private, add the impl items to `private_traits` so they don't get
// reported for missing docs.
let real_trait = trait_ref.path.res.def_id();
if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(real_trait) {
- match cx.tcx.hir().find(hir_id) {
- Some(Node::Item(item)) => {
- if let hir::VisibilityKind::Inherited = item.vis.node {
- for impl_item_ref in items {
- self.private_traits.insert(impl_item_ref.id.hir_id);
- }
+ if let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) {
+ if let hir::VisibilityKind::Inherited = item.vis.node {
+ for impl_item_ref in items {
+ self.private_traits.insert(impl_item_ref.id.hir_id);
}
}
- _ => {}
}
}
return;
}
- hir::ItemKind::Const(..) => "a constant",
- hir::ItemKind::Static(..) => "a static",
+
+ hir::ItemKind::TyAlias(..)
+ | hir::ItemKind::Fn(..)
+ | hir::ItemKind::Mod(..)
+ | hir::ItemKind::Enum(..)
+ | hir::ItemKind::Struct(..)
+ | hir::ItemKind::Union(..)
+ | hir::ItemKind::Const(..)
+ | hir::ItemKind::Static(..) => {}
+
_ => return,
};
- self.check_missing_docs_attrs(cx, Some(it.hir_id), &it.attrs, it.span, desc);
+ let def_id = cx.tcx.hir().local_def_id(it.hir_id);
+ let (article, desc) = cx.tcx.article_and_description(def_id);
+
+ self.check_missing_docs_attrs(cx, Some(it.hir_id), &it.attrs, it.span, article, desc);
}
fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, trait_item: &hir::TraitItem<'_>) {
return;
}
- let desc = match trait_item.kind {
- hir::TraitItemKind::Const(..) => "an associated constant",
- hir::TraitItemKind::Method(..) => "a trait method",
- hir::TraitItemKind::Type(..) => "an associated type",
- };
+ let def_id = cx.tcx.hir().local_def_id(trait_item.hir_id);
+ let (article, desc) = cx.tcx.article_and_description(def_id);
self.check_missing_docs_attrs(
cx,
Some(trait_item.hir_id),
&trait_item.attrs,
trait_item.span,
+ article,
desc,
);
}
return;
}
- let desc = match impl_item.kind {
- hir::ImplItemKind::Const(..) => "an associated constant",
- hir::ImplItemKind::Method(..) => "a method",
- hir::ImplItemKind::TyAlias(_) => "an associated type",
- hir::ImplItemKind::OpaqueTy(_) => "an associated `impl Trait` type",
- };
+ let def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
+ let (article, desc) = cx.tcx.article_and_description(def_id);
self.check_missing_docs_attrs(
cx,
Some(impl_item.hir_id),
&impl_item.attrs,
impl_item.span,
+ article,
desc,
);
}
fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, sf: &hir::StructField<'_>) {
if !sf.is_positional() {
- self.check_missing_docs_attrs(cx, Some(sf.hir_id), &sf.attrs, sf.span, "a struct field")
+ self.check_missing_docs_attrs(
+ cx,
+ Some(sf.hir_id),
+ &sf.attrs,
+ sf.span,
+ "a",
+ "struct field",
+ )
}
}
fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant<'_>) {
- self.check_missing_docs_attrs(cx, Some(v.id), &v.attrs, v.span, "a variant");
+ self.check_missing_docs_attrs(cx, Some(v.id), &v.attrs, v.span, "a", "variant");
}
}
impl EarlyLintPass for AnonymousParameters {
fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
- match it.kind {
- ast::AssocItemKind::Fn(_, ref sig, _, _) => {
- for arg in sig.decl.inputs.iter() {
- match arg.pat.kind {
- ast::PatKind::Ident(_, ident, None) => {
- if ident.name == kw::Invalid {
- cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
- let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span);
-
- let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
- (snip.as_str(), Applicability::MachineApplicable)
- } else {
- ("<type>", Applicability::HasPlaceholders)
- };
+ if let ast::AssocItemKind::Fn(_, ref sig, _, _) = it.kind {
+ for arg in sig.decl.inputs.iter() {
+ if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
+ if ident.name == kw::Invalid {
+ cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
+ let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span);
+
+ let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
+ (snip.as_str(), Applicability::MachineApplicable)
+ } else {
+ ("<type>", Applicability::HasPlaceholders)
+ };
- lint.build(
- "anonymous parameters are deprecated and will be \
+ lint.build(
+ "anonymous parameters are deprecated and will be \
removed in the next edition.",
- )
- .span_suggestion(
- arg.pat.span,
- "try naming the parameter or explicitly \
+ )
+ .span_suggestion(
+ arg.pat.span,
+ "try naming the parameter or explicitly \
ignoring it",
- format!("_: {}", ty_snip),
- appl,
- )
- .emit();
- })
- }
- }
- _ => (),
+ format!("_: {}", ty_snip),
+ appl,
+ )
+ .emit();
+ })
}
}
}
- _ => (),
}
}
}
ast::StmtKind::Empty
| ast::StmtKind::Semi(_)
| ast::StmtKind::Expr(_)
- | ast::StmtKind::Mac(_) => return,
+ | ast::StmtKind::MacCall(_) => return,
};
warn_if_doc(cx, stmt.span, kind, stmt.kind.attrs());
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes {
fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) {
use rustc_target::spec::abi::Abi::RustIntrinsic;
-
- match get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.kind, &ty2.kind)) {
- Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) => {
- if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
- let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \
+ if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) =
+ get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.kind, &ty2.kind))
+ {
+ if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
+ let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \
consider instead using an UnsafeCell";
- cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| {
- lint.build(msg).emit()
- });
- }
+ cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| lint.build(msg).emit());
}
- _ => (),
}
fn get_transmute_from_to<'a, 'tcx>(
if span.from_expansion() {
applicability = Applicability::MaybeIncorrect;
}
- let def_span = cx.tcx.sess.source_map().def_span(span);
+ let def_span = cx.tcx.sess.source_map().guess_head_span(span);
cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
let mut err = lint.build(&format!("unreachable `pub` {}", what));
let replacement = if cx.tcx.features().crate_visibility_modifier {
err: &'a mut DiagnosticBuilder<'db>,
}
impl<'a, 'db, 'v> Visitor<'v> for WalkAssocTypes<'a, 'db> {
- type Map = Map<'v>;
+ type Map = intravisit::ErasedMap<'v>;
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
+ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
intravisit::NestedVisitorMap::None
}
);
fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) {
- let def_id = cx.tcx.hir().body_owner_def_id(body_id);
+ let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
// trigger the query once for all constants since that will already report the errors
// FIXME: Use ensure here
let _ = cx.tcx.const_eval_poly(def_id);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'tcx>) {
- use rustc::ty::fold::TypeFoldable;
- use rustc::ty::Predicate::*;
+ use rustc_middle::ty::fold::TypeFoldable;
+ use rustc_middle::ty::Predicate::*;
if cx.tcx.features().trivial_bounds {
let def_id = cx.tcx.hir().local_def_id(item.hir_id);
}
pub struct UnnameableTestItems {
- boundary: hir::HirId, // HirId of the item under which things are not nameable
+ boundary: Option<hir::HirId>, // HirId of the item under which things are not nameable
items_nameable: bool,
}
impl UnnameableTestItems {
pub fn new() -> Self {
- Self { boundary: hir::DUMMY_HIR_ID, items_nameable: true }
+ Self { boundary: None, items_nameable: true }
}
}
if let hir::ItemKind::Mod(..) = it.kind {
} else {
self.items_nameable = false;
- self.boundary = it.hir_id;
+ self.boundary = Some(it.hir_id);
}
return;
}
}
fn check_item_post(&mut self, _cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
- if !self.items_nameable && self.boundary == it.hir_id {
+ if !self.items_nameable && self.boundary == Some(it.hir_id) {
self.items_nameable = true;
}
}
fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) {
self.check_tokens(cx, mac_def.body.inner_tokens());
}
- fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) {
+ fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
self.check_tokens(cx, mac.args.inner_tokens());
}
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) {
inferred_outlives: &[ty::Region<'tcx>],
infer_static: bool,
) -> Vec<(usize, Span)> {
- use rustc::middle::resolve_lifetime::Region;
+ use rustc_middle::middle::resolve_lifetime::Region;
bounds
.iter()
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>) {
- use rustc::middle::resolve_lifetime::Region;
+ use rustc_middle::middle::resolve_lifetime::Region;
let infer_static = cx.tcx.features().infer_static_outlives_requirements;
let def_id = cx.tcx.hir().local_def_id(item.hir_id);
ty: Ty<'tcx>,
init: InitKind,
) -> Option<InitError> {
- use rustc::ty::TyKind::*;
+ use rustc_middle::ty::TyKind::*;
match ty.kind {
// Primitive types that don't like 0 as a value.
Ref(..) => Some(("references must be non-null".to_string(), None)),