summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_lint/src/builtin.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_lint/src/builtin.rs1049
1 files changed, 617 insertions, 432 deletions
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index bd58021f7..d425adf47 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -21,6 +21,7 @@
//! `late_lint_methods!` invocation in `lib.rs`.
use crate::{
+ errors::BuiltinEllpisisInclusiveRangePatterns,
types::{transparent_newtype_field, CItemKind},
EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
};
@@ -32,8 +33,8 @@ use rustc_ast_pretty::pprust::{self, expr_to_string};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{
- fluent, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
- LintDiagnosticBuilder, MultiSpan,
+ fluent, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, DiagnosticMessage,
+ DiagnosticStyledString, MultiSpan,
};
use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
use rustc_hir as hir;
@@ -45,8 +46,7 @@ use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::Instance;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
@@ -58,7 +58,6 @@ use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};
use crate::nonstandard_style::{method_context, MethodLateContext};
use std::fmt::Write;
-use tracing::{debug, trace};
// hardwired lints from librustc_middle
pub use rustc_session::lint::builtin::*;
@@ -98,30 +97,31 @@ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
impl EarlyLintPass for WhileTrue {
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
- if let ast::ExprKind::While(cond, _, label) = &e.kind {
- if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
- if let ast::LitKind::Bool(true) = lit.kind {
- if !lit.span.from_expansion() {
- let condition_span = e.span.with_hi(cond.span.hi());
- cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
- lint.build(fluent::lint::builtin_while_true)
- .span_suggestion_short(
- condition_span,
- fluent::lint::suggestion,
- format!(
- "{}loop",
- label.map_or_else(String::new, |label| format!(
- "{}: ",
- label.ident,
- ))
- ),
- Applicability::MachineApplicable,
- )
- .emit();
- })
- }
- }
- }
+ if let ast::ExprKind::While(cond, _, label) = &e.kind
+ && let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind
+ && let ast::LitKind::Bool(true) = lit.kind
+ && !lit.span.from_expansion()
+ {
+ let condition_span = e.span.with_hi(cond.span.hi());
+ cx.struct_span_lint(
+ WHILE_TRUE,
+ condition_span,
+ fluent::lint_builtin_while_true,
+ |lint| {
+ lint.span_suggestion_short(
+ condition_span,
+ fluent::suggestion,
+ format!(
+ "{}loop",
+ label.map_or_else(String::new, |label| format!(
+ "{}: ",
+ label.ident,
+ ))
+ ),
+ Applicability::MachineApplicable,
+ )
+ },
+ )
}
}
}
@@ -157,9 +157,12 @@ impl BoxPointers {
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(fluent::lint::builtin_box_pointers).set_arg("ty", ty).emit();
- });
+ cx.struct_span_lint(
+ BOX_POINTERS,
+ span,
+ fluent::lint_builtin_box_pointers,
+ |lint| lint.set_arg("ty", ty),
+ );
}
}
}
@@ -174,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers {
| hir::ItemKind::Enum(..)
| hir::ItemKind::Struct(..)
| hir::ItemKind::Union(..) => {
- self.check_heap_type(cx, it.span, cx.tcx.type_of(it.def_id))
+ self.check_heap_type(cx, it.span, cx.tcx.type_of(it.owner_id))
}
_ => (),
}
@@ -258,28 +261,21 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
if cx.tcx.find_field_index(ident, &variant)
== Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
{
- cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
- let binding = match binding_annot {
- hir::BindingAnnotation::Unannotated => None,
- hir::BindingAnnotation::Mutable => Some("mut"),
- hir::BindingAnnotation::Ref => Some("ref"),
- hir::BindingAnnotation::RefMut => Some("ref mut"),
- };
- let suggested_ident = if let Some(binding) = binding {
- format!("{} {}", binding, ident)
- } else {
- ident.to_string()
- };
- lint.build(fluent::lint::builtin_non_shorthand_field_patterns)
- .set_arg("ident", ident.clone())
- .span_suggestion(
+ cx.struct_span_lint(
+ NON_SHORTHAND_FIELD_PATTERNS,
+ fieldpat.span,
+ fluent::lint_builtin_non_shorthand_field_patterns,
+ |lint| {
+ let suggested_ident =
+ format!("{}{}", binding_annot.prefix_str(), ident);
+ lint.set_arg("ident", ident.clone()).span_suggestion(
fieldpat.span,
- fluent::lint::suggestion,
+ fluent::suggestion,
suggested_ident,
Applicability::MachineApplicable,
)
- .emit();
- });
+ },
+ );
}
}
}
@@ -319,14 +315,17 @@ impl UnsafeCode {
&self,
cx: &EarlyContext<'_>,
span: Span,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
// This comes from a macro that has `#[allow_internal_unsafe]`.
if span.allows_unsafe() {
return;
}
- cx.struct_span_lint(UNSAFE_CODE, span, decorate);
+ cx.struct_span_lint(UNSAFE_CODE, span, msg, decorate);
}
fn report_overridden_symbol_name(
@@ -335,8 +334,8 @@ impl UnsafeCode {
span: Span,
msg: DiagnosticMessage,
) {
- self.report_unsafe(cx, span, |lint| {
- lint.build(msg).note(fluent::lint::builtin_overridden_symbol_name).emit();
+ self.report_unsafe(cx, span, msg, |lint| {
+ lint.note(fluent::lint_builtin_overridden_symbol_name)
})
}
@@ -346,8 +345,8 @@ impl UnsafeCode {
span: Span,
msg: DiagnosticMessage,
) {
- self.report_unsafe(cx, span, |lint| {
- lint.build(msg).note(fluent::lint::builtin_overridden_symbol_section).emit();
+ self.report_unsafe(cx, span, msg, |lint| {
+ lint.note(fluent::lint_builtin_overridden_symbol_section)
})
}
}
@@ -355,8 +354,8 @@ impl UnsafeCode {
impl EarlyLintPass for UnsafeCode {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
if attr.has_name(sym::allow_internal_unsafe) {
- self.report_unsafe(cx, attr.span, |lint| {
- lint.build(fluent::lint::builtin_allow_internal_unsafe).emit();
+ self.report_unsafe(cx, attr.span, fluent::lint_builtin_allow_internal_unsafe, |lint| {
+ lint
});
}
}
@@ -365,31 +364,27 @@ impl EarlyLintPass for UnsafeCode {
if let ast::ExprKind::Block(ref blk, _) = e.kind {
// Don't warn about generated blocks; that'll just pollute the output.
if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
- self.report_unsafe(cx, blk.span, |lint| {
- lint.build(fluent::lint::builtin_unsafe_block).emit();
- });
+ self.report_unsafe(cx, blk.span, fluent::lint_builtin_unsafe_block, |lint| lint);
}
}
}
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
match it.kind {
- ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self
- .report_unsafe(cx, it.span, |lint| {
- lint.build(fluent::lint::builtin_unsafe_trait).emit();
- }),
+ ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => {
+ self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_trait, |lint| lint)
+ }
- ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self
- .report_unsafe(cx, it.span, |lint| {
- lint.build(fluent::lint::builtin_unsafe_impl).emit();
- }),
+ ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => {
+ self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_impl, |lint| lint)
+ }
ast::ItemKind::Fn(..) => {
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_no_mangle_fn,
+ fluent::lint_builtin_no_mangle_fn,
);
}
@@ -397,7 +392,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_export_name_fn,
+ fluent::lint_builtin_export_name_fn,
);
}
@@ -405,7 +400,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_section(
cx,
attr.span,
- fluent::lint::builtin_link_section_fn,
+ fluent::lint_builtin_link_section_fn,
);
}
}
@@ -415,7 +410,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_no_mangle_static,
+ fluent::lint_builtin_no_mangle_static,
);
}
@@ -423,7 +418,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_export_name_static,
+ fluent::lint_builtin_export_name_static,
);
}
@@ -431,7 +426,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_section(
cx,
attr.span,
- fluent::lint::builtin_link_section_static,
+ fluent::lint_builtin_link_section_static,
);
}
}
@@ -446,14 +441,14 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_no_mangle_method,
+ fluent::lint_builtin_no_mangle_method,
);
}
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_export_name_method,
+ fluent::lint_builtin_export_name_method,
);
}
}
@@ -471,13 +466,11 @@ impl EarlyLintPass for UnsafeCode {
{
let msg = match ctxt {
FnCtxt::Foreign => return,
- FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn,
- FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method,
- FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method,
+ FnCtxt::Free => fluent::lint_builtin_decl_unsafe_fn,
+ FnCtxt::Assoc(_) if body.is_none() => fluent::lint_builtin_decl_unsafe_method,
+ FnCtxt::Assoc(_) => fluent::lint_builtin_impl_unsafe_method,
};
- self.report_unsafe(cx, span, |lint| {
- lint.build(msg).emit();
- });
+ self.report_unsafe(cx, span, msg, |lint| lint);
}
}
}
@@ -570,7 +563,7 @@ impl MissingDoc {
// It's an option so the crate root can also use this function (it doesn't
// have a `NodeId`).
if def_id != CRATE_DEF_ID {
- if !cx.access_levels.is_exported(def_id) {
+ if !cx.effective_visibilities.is_exported(def_id) {
return;
}
}
@@ -578,12 +571,12 @@ impl MissingDoc {
let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
let has_doc = attrs.iter().any(has_doc);
if !has_doc {
- cx.struct_span_lint(MISSING_DOCS, cx.tcx.def_span(def_id), |lint| {
- lint.build(fluent::lint::builtin_missing_doc)
- .set_arg("article", article)
- .set_arg("desc", desc)
- .emit();
- });
+ cx.struct_span_lint(
+ MISSING_DOCS,
+ cx.tcx.def_span(def_id),
+ fluent::lint_builtin_missing_doc,
+ |lint| lint.set_arg("article", article).set_arg("desc", desc),
+ );
}
}
}
@@ -613,9 +606,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
match it.kind {
hir::ItemKind::Trait(..) => {
// Issue #11592: traits are always considered exported, even when private.
- if cx.tcx.visibility(it.def_id)
+ if cx.tcx.visibility(it.owner_id)
== ty::Visibility::Restricted(
- cx.tcx.parent_module_from_def_id(it.def_id).to_def_id(),
+ cx.tcx.parent_module_from_def_id(it.owner_id.def_id).to_def_id(),
)
{
return;
@@ -634,15 +627,15 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
_ => return,
};
- let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
- self.check_missing_docs_attrs(cx, it.def_id, article, desc);
+ self.check_missing_docs_attrs(cx, it.owner_id.def_id, article, desc);
}
fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
- let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id());
- self.check_missing_docs_attrs(cx, trait_item.def_id, article, desc);
+ self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, article, desc);
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
@@ -669,13 +662,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
}
}
- let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
- self.check_missing_docs_attrs(cx, impl_item.def_id, article, desc);
+ let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
+ self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, article, desc);
}
fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
- let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id());
- self.check_missing_docs_attrs(cx, foreign_item.def_id, article, desc);
+ let (article, desc) = cx.tcx.article_and_description(foreign_item.owner_id.to_def_id());
+ self.check_missing_docs_attrs(cx, foreign_item.owner_id.def_id, article, desc);
}
fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
@@ -728,7 +721,7 @@ declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS])
impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if !cx.access_levels.is_reachable(item.def_id) {
+ if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
return;
}
let (def, ty) = match item.kind {
@@ -736,21 +729,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
if !ast_generics.params.is_empty() {
return;
}
- let def = cx.tcx.adt_def(item.def_id);
+ let def = cx.tcx.adt_def(item.owner_id);
(def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
}
hir::ItemKind::Union(_, ref ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
- let def = cx.tcx.adt_def(item.def_id);
+ let def = cx.tcx.adt_def(item.owner_id);
(def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
}
hir::ItemKind::Enum(_, ref ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
- let def = cx.tcx.adt_def(item.def_id);
+ let def = cx.tcx.adt_def(item.owner_id);
(def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
}
_ => return,
@@ -759,7 +752,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
return;
}
let param_env = ty::ParamEnv::empty();
- if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) {
+ if ty.is_copy_modulo_regions(cx.tcx, param_env) {
return;
}
if can_type_implement_copy(
@@ -770,9 +763,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
)
.is_ok()
{
- cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| {
- lint.build(fluent::lint::builtin_missing_copy_impl).emit();
- })
+ cx.struct_span_lint(
+ MISSING_COPY_IMPLEMENTATIONS,
+ item.span,
+ fluent::lint_builtin_missing_copy_impl,
+ |lint| lint,
+ )
}
}
}
@@ -818,7 +814,7 @@ impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if !cx.access_levels.is_reachable(item.def_id) {
+ if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
return;
}
@@ -845,12 +841,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
debug!("{:?}", self.impling_types);
}
- if !self.impling_types.as_ref().unwrap().contains(&item.def_id) {
- cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
- lint.build(fluent::lint::builtin_missing_debug_impl)
- .set_arg("debug", cx.tcx.def_path_str(debug))
- .emit();
- });
+ if !self.impling_types.as_ref().unwrap().contains(&item.owner_id.def_id) {
+ cx.struct_span_lint(
+ MISSING_DEBUG_IMPLEMENTATIONS,
+ item.span,
+ fluent::lint_builtin_missing_debug_impl,
+ |lint| lint.set_arg("debug", cx.tcx.def_path_str(debug)),
+ );
}
}
}
@@ -918,24 +915,26 @@ impl EarlyLintPass for AnonymousParameters {
for arg in sig.decl.inputs.iter() {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
if ident.name == kw::Empty {
- 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 = 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(fluent::lint::builtin_anonymous_params)
- .span_suggestion(
+ let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
+ (snip.as_str(), Applicability::MachineApplicable)
+ } else {
+ ("<type>", Applicability::HasPlaceholders)
+ };
+ cx.struct_span_lint(
+ ANONYMOUS_PARAMETERS,
+ arg.pat.span,
+ fluent::lint_builtin_anonymous_params,
+ |lint| {
+ lint.span_suggestion(
arg.pat.span,
- fluent::lint::suggestion,
+ fluent::suggestion,
format!("_: {}", ty_snip),
appl,
)
- .emit();
- })
+ },
+ )
}
}
}
@@ -970,38 +969,44 @@ impl EarlyLintPass for DeprecatedAttr {
_,
) = gate
{
- cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
- // FIXME(davidtwco) translatable deprecated attr
- lint.build(fluent::lint::builtin_deprecated_attr_link)
- .set_arg("name", name)
- .set_arg("reason", reason)
- .set_arg("link", link)
- .span_suggestion_short(
- attr.span,
- suggestion.map(|s| s.into()).unwrap_or(
- fluent::lint::builtin_deprecated_attr_default_suggestion,
- ),
- "",
- Applicability::MachineApplicable,
- )
- .emit();
- });
+ // FIXME(davidtwco) translatable deprecated attr
+ cx.struct_span_lint(
+ DEPRECATED,
+ attr.span,
+ fluent::lint_builtin_deprecated_attr_link,
+ |lint| {
+ lint.set_arg("name", name)
+ .set_arg("reason", reason)
+ .set_arg("link", link)
+ .span_suggestion_short(
+ attr.span,
+ suggestion.map(|s| s.into()).unwrap_or(
+ fluent::lint_builtin_deprecated_attr_default_suggestion,
+ ),
+ "",
+ Applicability::MachineApplicable,
+ )
+ },
+ );
}
return;
}
}
if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
- cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
- lint.build(fluent::lint::builtin_deprecated_attr_used)
- .set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
- .span_suggestion_short(
- attr.span,
- fluent::lint::builtin_deprecated_attr_default_suggestion,
- "",
- Applicability::MachineApplicable,
- )
- .emit();
- });
+ cx.struct_span_lint(
+ DEPRECATED,
+ attr.span,
+ fluent::lint_builtin_deprecated_attr_used,
+ |lint| {
+ lint.set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
+ .span_suggestion_short(
+ attr.span,
+ fluent::lint_builtin_deprecated_attr_default_suggestion,
+ "",
+ Applicability::MachineApplicable,
+ )
+ },
+ );
}
}
}
@@ -1028,20 +1033,21 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
let span = sugared_span.take().unwrap_or(attr.span);
if is_doc_comment || attr.has_name(sym::doc) {
- cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
- let mut err = lint.build(fluent::lint::builtin_unused_doc_comment);
- err.set_arg("kind", node_kind);
- err.span_label(node_span, fluent::lint::label);
- match attr.kind {
- AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
- err.help(fluent::lint::plain_help);
- }
- AttrKind::DocComment(CommentKind::Block, _) => {
- err.help(fluent::lint::block_help);
- }
- }
- err.emit();
- });
+ cx.struct_span_lint(
+ UNUSED_DOC_COMMENTS,
+ span,
+ fluent::lint_builtin_unused_doc_comment,
+ |lint| {
+ lint.set_arg("kind", node_kind).span_label(node_span, fluent::label).help(
+ match attr.kind {
+ AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
+ fluent::plain_help
+ }
+ AttrKind::DocComment(CommentKind::Block, _) => fluent::block_help,
+ },
+ )
+ },
+ );
}
}
}
@@ -1155,18 +1161,21 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
match param.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
- cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| {
- lint.build(fluent::lint::builtin_no_mangle_generic)
- .span_suggestion_short(
+ cx.struct_span_lint(
+ NO_MANGLE_GENERIC_ITEMS,
+ span,
+ fluent::lint_builtin_no_mangle_generic,
+ |lint| {
+ lint.span_suggestion_short(
no_mangle_attr.span,
- fluent::lint::suggestion,
+ fluent::suggestion,
"",
// Use of `#[no_mangle]` suggests FFI intent; correct
// fix may be to monomorphize source by hand
Applicability::MaybeIncorrect,
)
- .emit();
- });
+ },
+ );
break;
}
}
@@ -1182,27 +1191,29 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
if cx.sess().contains_name(attrs, sym::no_mangle) {
// Const items do not refer to a particular location in memory, and therefore
// don't have anything to attach a symbol to
- cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| {
- let mut err = lint.build(fluent::lint::builtin_const_no_mangle);
-
- // account for "pub const" (#45562)
- let start = cx
- .tcx
- .sess
- .source_map()
- .span_to_snippet(it.span)
- .map(|snippet| snippet.find("const").unwrap_or(0))
- .unwrap_or(0) as u32;
- // `const` is 5 chars
- let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
- err.span_suggestion(
- const_span,
- fluent::lint::suggestion,
- "pub static",
- Applicability::MachineApplicable,
- );
- err.emit();
- });
+ cx.struct_span_lint(
+ NO_MANGLE_CONST_ITEMS,
+ it.span,
+ fluent::lint_builtin_const_no_mangle,
+ |lint| {
+ // account for "pub const" (#45562)
+ let start = cx
+ .tcx
+ .sess
+ .source_map()
+ .span_to_snippet(it.span)
+ .map(|snippet| snippet.find("const").unwrap_or(0))
+ .unwrap_or(0) as u32;
+ // `const` is 5 chars
+ let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
+ lint.span_suggestion(
+ const_span,
+ fluent::suggestion,
+ "pub static",
+ Applicability::MachineApplicable,
+ )
+ },
+ );
}
}
hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
@@ -1215,7 +1226,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
check_no_mangle_on_generic_fn(
no_mangle_attr,
Some(generics),
- cx.tcx.hir().get_generics(it.id.def_id).unwrap(),
+ cx.tcx.hir().get_generics(it.id.owner_id.def_id).unwrap(),
it.span,
);
}
@@ -1262,9 +1273,12 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
{
if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
- cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| {
- lint.build(fluent::lint::builtin_mutable_transmutes).emit();
- });
+ cx.struct_span_lint(
+ MUTABLE_TRANSMUTES,
+ expr.span,
+ fluent::lint_builtin_mutable_transmutes,
+ |lint| lint,
+ );
}
}
@@ -1312,9 +1326,12 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
if attr.has_name(sym::feature) {
if let Some(items) = attr.meta_item_list() {
for item in items {
- cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
- lint.build(fluent::lint::builtin_unstable_features).emit();
- });
+ cx.struct_span_lint(
+ UNSTABLE_FEATURES,
+ item.span(),
+ fluent::lint_builtin_unstable_features,
+ |lint| lint,
+ );
}
}
}
@@ -1368,26 +1385,26 @@ impl UnreachablePub {
exportable: bool,
) {
let mut applicability = Applicability::MachineApplicable;
- if cx.tcx.visibility(def_id).is_public() && !cx.access_levels.is_reachable(def_id) {
+ if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id)
+ {
if vis_span.from_expansion() {
applicability = Applicability::MaybeIncorrect;
}
let def_span = cx.tcx.def_span(def_id);
- cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
- let mut err = lint.build(fluent::lint::builtin_unreachable_pub);
- err.set_arg("what", what);
-
- err.span_suggestion(
- vis_span,
- fluent::lint::suggestion,
- "pub(crate)",
- applicability,
- );
- if exportable {
- err.help(fluent::lint::help);
- }
- err.emit();
- });
+ cx.struct_span_lint(
+ UNREACHABLE_PUB,
+ def_span,
+ fluent::lint_builtin_unreachable_pub,
+ |lint| {
+ lint.set_arg("what", what);
+
+ lint.span_suggestion(vis_span, fluent::suggestion, "pub(crate)", applicability);
+ if exportable {
+ lint.help(fluent::help);
+ }
+ lint
+ },
+ );
}
}
}
@@ -1398,11 +1415,11 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
return;
}
- self.perform_lint(cx, "item", item.def_id, item.vis_span, true);
+ self.perform_lint(cx, "item", item.owner_id.def_id, item.vis_span, true);
}
fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
- self.perform_lint(cx, "item", foreign_item.def_id, foreign_item.vis_span, true);
+ self.perform_lint(cx, "item", foreign_item.owner_id.def_id, foreign_item.vis_span, true);
}
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
@@ -1412,8 +1429,8 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
// Only lint inherent impl items.
- if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
- self.perform_lint(cx, "item", impl_item.def_id, impl_item.vis_span, false);
+ if cx.tcx.associated_item(impl_item.owner_id).trait_item_def_id.is_none() {
+ self.perform_lint(cx, "item", impl_item.owner_id.def_id, impl_item.vis_span, false);
}
}
}
@@ -1474,9 +1491,9 @@ impl TypeAliasBounds {
impl Visitor<'_> for WalkAssocTypes<'_> {
fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) {
if TypeAliasBounds::is_type_variable_assoc(qpath) {
- self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help);
+ self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help);
}
- intravisit::walk_qpath(self, qpath, id, span)
+ intravisit::walk_qpath(self, qpath, id)
}
}
@@ -1517,36 +1534,34 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
let mut suggested_changing_assoc_types = false;
if !where_spans.is_empty() {
- cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
- let mut err = lint.build(fluent::lint::builtin_type_alias_where_clause);
- err.set_span(where_spans);
- err.span_suggestion(
+ cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_where_clause, |lint| {
+ lint.set_span(where_spans);
+ lint.span_suggestion(
type_alias_generics.where_clause_span,
- fluent::lint::suggestion,
+ fluent::suggestion,
"",
Applicability::MachineApplicable,
);
if !suggested_changing_assoc_types {
- TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+ TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
suggested_changing_assoc_types = true;
}
- err.emit();
+ lint
});
}
if !inline_spans.is_empty() {
- cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
- let mut err = lint.build(fluent::lint::builtin_type_alias_generic_bounds);
- err.set_span(inline_spans);
- err.multipart_suggestion(
- fluent::lint::suggestion,
+ cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_generic_bounds, |lint| {
+ lint.set_span(inline_spans);
+ lint.multipart_suggestion(
+ fluent::suggestion,
inline_sugg,
Applicability::MachineApplicable,
);
if !suggested_changing_assoc_types {
- TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+ TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
}
- err.emit();
+ lint
});
}
}
@@ -1624,7 +1639,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
use rustc_middle::ty::PredicateKind::*;
if cx.tcx.features().trivial_bounds {
- let predicates = cx.tcx.predicates_of(item.def_id);
+ let predicates = cx.tcx.predicates_of(item.owner_id);
for &(predicate, span) in predicates.predicates {
let predicate_kind_name = match predicate.kind().skip_binder() {
Trait(..) => "trait",
@@ -1645,12 +1660,15 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
TypeWellFormedFromEnv(..) => continue,
};
if predicate.is_global() {
- cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
- lint.build(fluent::lint::builtin_trivial_bounds)
- .set_arg("predicate_kind_name", predicate_kind_name)
- .set_arg("predicate", predicate)
- .emit();
- });
+ cx.struct_span_lint(
+ TRIVIAL_BOUNDS,
+ span,
+ fluent::lint_builtin_trivial_bounds,
+ |lint| {
+ lint.set_arg("predicate_kind_name", predicate_kind_name)
+ .set_arg("predicate", predicate)
+ },
+ );
}
}
}
@@ -1750,8 +1768,8 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
};
if let Some((start, end, join)) = endpoints {
- let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns;
- let suggestion = fluent::lint::suggestion;
+ let msg = fluent::lint_builtin_ellipsis_inclusive_range_patterns;
+ let suggestion = fluent::suggestion;
if parenthesise {
self.node_id = Some(pat.id);
let end = expr_to_string(&end);
@@ -1760,55 +1778,37 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
None => format!("&(..={})", end),
};
if join.edition() >= Edition::Edition2021 {
- let mut err = cx.sess().struct_span_err_with_code(
- pat.span,
- msg,
- rustc_errors::error_code!(E0783),
- );
- err.span_suggestion(
- pat.span,
- suggestion,
+ cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
+ span: pat.span,
+ suggestion: pat.span,
replace,
- Applicability::MachineApplicable,
- )
- .emit();
+ });
} else {
- cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
- lint.build(msg)
- .span_suggestion(
- pat.span,
- suggestion,
- replace,
- Applicability::MachineApplicable,
- )
- .emit();
+ cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg, |lint| {
+ lint.span_suggestion(
+ pat.span,
+ suggestion,
+ replace,
+ Applicability::MachineApplicable,
+ )
});
}
} else {
let replace = "..=";
if join.edition() >= Edition::Edition2021 {
- let mut err = cx.sess().struct_span_err_with_code(
- pat.span,
- msg,
- rustc_errors::error_code!(E0783),
- );
- err.span_suggestion_short(
- join,
- suggestion,
- replace,
- Applicability::MachineApplicable,
- )
- .emit();
+ cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
+ span: pat.span,
+ suggestion: join,
+ replace: replace.to_string(),
+ });
} else {
- cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
- lint.build(msg)
- .span_suggestion_short(
- join,
- suggestion,
- replace,
- Applicability::MachineApplicable,
- )
- .emit();
+ cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg, |lint| {
+ lint.span_suggestion_short(
+ join,
+ suggestion,
+ replace,
+ Applicability::MachineApplicable,
+ )
});
}
};
@@ -1864,7 +1864,7 @@ declare_lint! {
}
pub struct UnnameableTestItems {
- boundary: Option<LocalDefId>, // Id of the item under which things are not nameable
+ boundary: Option<hir::OwnerId>, // Id of the item under which things are not nameable
items_nameable: bool,
}
@@ -1882,21 +1882,24 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
if let hir::ItemKind::Mod(..) = it.kind {
} else {
self.items_nameable = false;
- self.boundary = Some(it.def_id);
+ self.boundary = Some(it.owner_id);
}
return;
}
let attrs = cx.tcx.hir().attrs(it.hir_id());
if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
- cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| {
- lint.build(fluent::lint::builtin_unnameable_test_items).emit();
- });
+ cx.struct_span_lint(
+ UNNAMEABLE_TEST_ITEMS,
+ attr.span,
+ fluent::lint_builtin_unnameable_test_items,
+ |lint| lint,
+ );
}
}
fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) {
- if !self.items_nameable && self.boundary == Some(it.def_id) {
+ if !self.items_nameable && self.boundary == Some(it.owner_id) {
self.items_nameable = true;
}
}
@@ -2007,23 +2010,24 @@ impl KeywordIdents {
return;
}
- cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| {
- lint.build(fluent::lint::builtin_keyword_idents)
- .set_arg("kw", ident.clone())
- .set_arg("next", next_edition)
- .span_suggestion(
+ cx.struct_span_lint(
+ KEYWORD_IDENTS,
+ ident.span,
+ fluent::lint_builtin_keyword_idents,
+ |lint| {
+ lint.set_arg("kw", ident.clone()).set_arg("next", next_edition).span_suggestion(
ident.span,
- fluent::lint::suggestion,
+ fluent::suggestion,
format!("r#{}", ident),
Applicability::MachineApplicable,
)
- .emit();
- });
+ },
+ );
}
}
impl EarlyLintPass for KeywordIdents {
- fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) {
+ fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) {
self.check_tokens(cx, mac_def.body.inner_tokens());
}
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
@@ -2039,13 +2043,13 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN
impl ExplicitOutlivesRequirements {
fn lifetimes_outliving_lifetime<'tcx>(
inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
- index: u32,
+ def_id: DefId,
) -> Vec<ty::Region<'tcx>> {
inferred_outlives
.iter()
.filter_map(|(pred, _)| match pred.kind().skip_binder() {
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
- ty::ReEarlyBound(ebr) if ebr.index == index => Some(b),
+ ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b),
_ => None,
},
_ => None,
@@ -2082,8 +2086,12 @@ impl ExplicitOutlivesRequirements {
.filter_map(|(i, bound)| {
if let hir::GenericBound::Outlives(lifetime) = bound {
let is_inferred = match tcx.named_region(lifetime.hir_id) {
- Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| {
- if let ty::ReEarlyBound(ebr) = **r { ebr.index == index } else { false }
+ Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| {
+ if let ty::ReEarlyBound(ebr) = **r {
+ ebr.def_id == def_id
+ } else {
+ false
+ }
}),
_ => false,
};
@@ -2157,7 +2165,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
use rustc_middle::middle::resolve_lifetime::Region;
- let def_id = item.def_id;
+ let def_id = item.owner_id.def_id;
if let hir::ItemKind::Struct(_, ref hir_generics)
| hir::ItemKind::Enum(_, ref hir_generics)
| hir::ItemKind::Union(_, ref hir_generics) = item.kind
@@ -2177,11 +2185,14 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
hir::WherePredicate::RegionPredicate(predicate) => {
- if let Some(Region::EarlyBound(index, ..)) =
+ if let Some(Region::EarlyBound(region_def_id)) =
cx.tcx.named_region(predicate.lifetime.hir_id)
{
(
- Self::lifetimes_outliving_lifetime(inferred_outlives, index),
+ Self::lifetimes_outliving_lifetime(
+ inferred_outlives,
+ region_def_id,
+ ),
&predicate.bounds,
predicate.span,
predicate.in_where_clause,
@@ -2262,19 +2273,21 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
}
if !lint_spans.is_empty() {
- cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| {
- lint.build(fluent::lint::builtin_explicit_outlives)
- .set_arg("count", bound_count)
- .multipart_suggestion(
- fluent::lint::suggestion,
+ cx.struct_span_lint(
+ EXPLICIT_OUTLIVES_REQUIREMENTS,
+ lint_spans.clone(),
+ fluent::lint_builtin_explicit_outlives,
+ |lint| {
+ lint.set_arg("count", bound_count).multipart_suggestion(
+ fluent::suggestion,
lint_spans
.into_iter()
.map(|span| (span, String::new()))
.collect::<Vec<_>>(),
Applicability::MachineApplicable,
)
- .emit();
- });
+ },
+ );
}
}
}
@@ -2321,18 +2334,24 @@ impl EarlyLintPass for IncompleteFeatures {
.chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
.filter(|(&name, _)| features.incomplete(name))
.for_each(|(&name, &span)| {
- cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
- let mut builder = lint.build(fluent::lint::builtin_incomplete_features);
- builder.set_arg("name", name);
- if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) {
- builder.set_arg("n", n);
- builder.note(fluent::lint::note);
- }
- if HAS_MIN_FEATURES.contains(&name) {
- builder.help(fluent::lint::help);
- }
- builder.emit();
- })
+ cx.struct_span_lint(
+ INCOMPLETE_FEATURES,
+ span,
+ fluent::lint_builtin_incomplete_features,
+ |lint| {
+ lint.set_arg("name", name);
+ if let Some(n) =
+ rustc_feature::find_feature_issue(name, GateIssue::Language)
+ {
+ lint.set_arg("n", n);
+ lint.note(fluent::note);
+ }
+ if HAS_MIN_FEATURES.contains(&name) {
+ lint.help(fluent::help);
+ }
+ lint
+ },
+ )
});
}
}
@@ -2419,13 +2438,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
_ => {}
}
}
- } else if let hir::ExprKind::MethodCall(_, ref args, _) = expr.kind {
+ } else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
// Find problematic calls to `MaybeUninit::assume_init`.
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
// This is a call to *some* method named `assume_init`.
// See if the `self` parameter is one of the dangerous constructors.
- if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
+ if let hir::ExprKind::Call(ref path_expr, _) = receiver.kind {
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
match cx.tcx.get_diagnostic_name(def_id) {
@@ -2441,12 +2460,27 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
None
}
- /// Test if this enum has several actually "existing" variants.
- /// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist".
- fn is_multi_variant<'tcx>(adt: ty::AdtDef<'tcx>) -> bool {
- // As an approximation, we only count dataless variants. Those are definitely inhabited.
- let existing_variants = adt.variants().iter().filter(|v| v.fields.is_empty()).count();
- existing_variants > 1
+ fn variant_find_init_error<'tcx>(
+ cx: &LateContext<'tcx>,
+ variant: &VariantDef,
+ substs: ty::SubstsRef<'tcx>,
+ descr: &str,
+ init: InitKind,
+ ) -> Option<InitError> {
+ variant.fields.iter().find_map(|field| {
+ ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(|(mut msg, span)| {
+ if span.is_none() {
+ // Point to this field, should be helpful for figuring
+ // out where the source of the error is.
+ let span = cx.tcx.def_span(field.did);
+ write!(&mut msg, " (in this {descr})").unwrap();
+ (msg, Some(span))
+ } else {
+ // Just forward.
+ (msg, span)
+ }
+ })
+ })
}
/// Return `Some` only if we are sure this type does *not*
@@ -2475,7 +2509,16 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
Char if init == InitKind::Uninit => {
Some(("characters must be a valid Unicode codepoint".to_string(), None))
}
- // Recurse and checks for some compound types.
+ Int(_) | Uint(_) if init == InitKind::Uninit => {
+ Some(("integers must not be uninitialized".to_string(), None))
+ }
+ Float(_) if init == InitKind::Uninit => {
+ Some(("floats must not be uninitialized".to_string(), None))
+ }
+ RawPtr(_) if init == InitKind::Uninit => {
+ Some(("raw pointers must not be uninitialized".to_string(), None))
+ }
+ // Recurse and checks for some compound types. (but not unions)
Adt(adt_def, substs) if !adt_def.is_union() => {
// First check if this ADT has a layout attribute (like `NonNull` and friends).
use std::ops::Bound;
@@ -2483,7 +2526,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
// We exploit here that `layout_scalar_valid_range` will never
// return `Bound::Excluded`. (And we have tests checking that we
// handle the attribute correctly.)
- (Bound::Included(lo), _) if lo > 0 => {
+ // We don't add a span since users cannot declare such types anyway.
+ (Bound::Included(lo), Bound::Included(hi)) if 0 < lo && lo < hi => {
+ return Some((format!("`{}` must be non-null", ty), None));
+ }
+ (Bound::Included(lo), Bound::Unbounded) if 0 < lo => {
return Some((format!("`{}` must be non-null", ty), None));
}
(Bound::Included(_), _) | (_, Bound::Included(_))
@@ -2499,50 +2546,65 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
}
_ => {}
}
- // Now, recurse.
- match adt_def.variants().len() {
- 0 => Some(("enums with no variants have no valid value".to_string(), None)),
- 1 => {
- // Struct, or enum with exactly one variant.
- // Proceed recursively, check all fields.
- let variant = &adt_def.variant(VariantIdx::from_u32(0));
- variant.fields.iter().find_map(|field| {
- ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(
- |(mut msg, span)| {
- if span.is_none() {
- // Point to this field, should be helpful for figuring
- // out where the source of the error is.
- let span = cx.tcx.def_span(field.did);
- write!(
- &mut msg,
- " (in this {} field)",
- adt_def.descr()
- )
- .unwrap();
- (msg, Some(span))
- } else {
- // Just forward.
- (msg, span)
- }
- },
- )
- })
- }
- // Multi-variant enum.
- _ => {
- if init == InitKind::Uninit && is_multi_variant(*adt_def) {
- let span = cx.tcx.def_span(adt_def.did());
- Some((
- "enums have to be initialized to a variant".to_string(),
- Some(span),
- ))
- } else {
- // In principle, for zero-initialization we could figure out which variant corresponds
- // to tag 0, and check that... but for now we just accept all zero-initializations.
- None
- }
+ // Handle structs.
+ if adt_def.is_struct() {
+ return variant_find_init_error(
+ cx,
+ adt_def.non_enum_variant(),
+ substs,
+ "struct field",
+ init,
+ );
+ }
+ // And now, enums.
+ let span = cx.tcx.def_span(adt_def.did());
+ let mut potential_variants = adt_def.variants().iter().filter_map(|variant| {
+ let definitely_inhabited = match variant
+ .inhabited_predicate(cx.tcx, *adt_def)
+ .subst(cx.tcx, substs)
+ .apply_any_module(cx.tcx, cx.param_env)
+ {
+ // Entirely skip uninhbaited variants.
+ Some(false) => return None,
+ // Forward the others, but remember which ones are definitely inhabited.
+ Some(true) => true,
+ None => false,
+ };
+ Some((variant, definitely_inhabited))
+ });
+ let Some(first_variant) = potential_variants.next() else {
+ return Some(("enums with no inhabited variants have no valid value".to_string(), Some(span)));
+ };
+ // So we have at least one potentially inhabited variant. Might we have two?
+ let Some(second_variant) = potential_variants.next() else {
+ // There is only one potentially inhabited variant. So we can recursively check that variant!
+ return variant_find_init_error(
+ cx,
+ &first_variant.0,
+ substs,
+ "field of the only potentially inhabited enum variant",
+ init,
+ );
+ };
+ // So we have at least two potentially inhabited variants.
+ // If we can prove that we have at least two *definitely* inhabited variants,
+ // then we have a tag and hence leaving this uninit is definitely disallowed.
+ // (Leaving it zeroed could be okay, depending on which variant is encoded as zero tag.)
+ if init == InitKind::Uninit {
+ let definitely_inhabited = (first_variant.1 as usize)
+ + (second_variant.1 as usize)
+ + potential_variants
+ .filter(|(_variant, definitely_inhabited)| *definitely_inhabited)
+ .count();
+ if definitely_inhabited > 1 {
+ return Some((
+ "enums with multiple inhabited variants have to be initialized to a variant".to_string(),
+ Some(span),
+ ));
}
}
+ // We couldn't find anything wrong here.
+ None
}
Tuple(..) => {
// Proceed recursively, check all fields.
@@ -2571,28 +2633,37 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init))
{
// FIXME(davidtwco): make translatable
- cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
- let mut err = lint.build(&format!(
- "the type `{}` does not permit {}",
- conjured_ty,
- match init {
- InitKind::Zeroed => "zero-initialization",
- InitKind::Uninit => "being left uninitialized",
- },
- ));
- err.span_label(expr.span, "this code causes undefined behavior when executed");
- err.span_label(
- expr.span,
- "help: use `MaybeUninit<T>` instead, \
+ cx.struct_span_lint(
+ INVALID_VALUE,
+ expr.span,
+ DelayDm(|| {
+ format!(
+ "the type `{}` does not permit {}",
+ conjured_ty,
+ match init {
+ InitKind::Zeroed => "zero-initialization",
+ InitKind::Uninit => "being left uninitialized",
+ },
+ )
+ }),
+ |lint| {
+ lint.span_label(
+ expr.span,
+ "this code causes undefined behavior when executed",
+ );
+ lint.span_label(
+ expr.span,
+ "help: use `MaybeUninit<T>` instead, \
and only call `assume_init` after initialization is done",
- );
- if let Some(span) = span {
- err.span_note(span, &msg);
- } else {
- err.note(&msg);
- }
- err.emit();
- });
+ );
+ if let Some(span) = span {
+ lint.span_note(span, &msg);
+ } else {
+ lint.note(&msg);
+ }
+ lint
+ },
+ );
}
}
}
@@ -2673,7 +2744,7 @@ impl ClashingExternDeclarations {
/// Insert a new foreign item into the seen set. If a symbol with the same name already exists
/// for the item, return its HirId without updating the set.
fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
- let did = fi.def_id.to_def_id();
+ let did = fi.owner_id.to_def_id();
let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
let name = Symbol::intern(tcx.symbol_name(instance).name);
if let Some(&hir_id) = self.seen_decls.get(&name) {
@@ -2691,14 +2762,14 @@ impl ClashingExternDeclarations {
/// symbol's name.
fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
if let Some((overridden_link_name, overridden_link_name_span)) =
- tcx.codegen_fn_attrs(fi.def_id).link_name.map(|overridden_link_name| {
+ tcx.codegen_fn_attrs(fi.owner_id).link_name.map(|overridden_link_name| {
// FIXME: Instead of searching through the attributes again to get span
// information, we could have codegen_fn_attrs also give span information back for
// where the attribute was defined. However, until this is found to be a
// bottleneck, this does just fine.
(
overridden_link_name,
- tcx.get_attr(fi.def_id.to_def_id(), sym::link_name).unwrap().span,
+ tcx.get_attr(fi.owner_id.to_def_id(), sym::link_name).unwrap().span,
)
})
{
@@ -2915,10 +2986,10 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
let tcx = cx.tcx;
if let Some(existing_hid) = self.insert(tcx, this_fi) {
let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid));
- let this_decl_ty = tcx.type_of(this_fi.def_id);
+ let this_decl_ty = tcx.type_of(this_fi.owner_id);
debug!(
"ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
- existing_hid, existing_decl_ty, this_fi.def_id, this_decl_ty
+ existing_hid, existing_decl_ty, this_fi.owner_id, this_decl_ty
);
// Check that the declarations match.
if !Self::structurally_same_type(
@@ -2938,31 +3009,29 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
};
// Finally, emit the diagnostic.
+
+ let msg = if orig.get_name() == this_fi.ident.name {
+ fluent::lint_builtin_clashing_extern_same_name
+ } else {
+ fluent::lint_builtin_clashing_extern_diff_name
+ };
tcx.struct_span_lint_hir(
CLASHING_EXTERN_DECLARATIONS,
this_fi.hir_id(),
get_relevant_span(this_fi),
+ msg,
|lint| {
let mut expected_str = DiagnosticStyledString::new();
expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false);
let mut found_str = DiagnosticStyledString::new();
found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
- lint.build(if orig.get_name() == this_fi.ident.name {
- fluent::lint::builtin_clashing_extern_same_name
- } else {
- fluent::lint::builtin_clashing_extern_diff_name
- })
- .set_arg("this_fi", this_fi.ident.name)
- .set_arg("orig", orig.get_name())
- .span_label(
- get_relevant_span(orig_fi),
- fluent::lint::previous_decl_label,
- )
- .span_label(get_relevant_span(this_fi), fluent::lint::mismatch_label)
- // FIXME(davidtwco): translatable expected/found
- .note_expected_found(&"", expected_str, &"", found_str)
- .emit();
+ lint.set_arg("this_fi", this_fi.ident.name)
+ .set_arg("orig", orig.get_name())
+ .span_label(get_relevant_span(orig_fi), fluent::previous_decl_label)
+ .span_label(get_relevant_span(this_fi), fluent::mismatch_label)
+ // FIXME(davidtwco): translatable expected/found
+ .note_expected_found(&"", expected_str, &"", found_str)
},
);
}
@@ -3043,11 +3112,12 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
if is_null_ptr(cx, expr_deref) {
- cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
- let mut err = lint.build(fluent::lint::builtin_deref_nullptr);
- err.span_label(expr.span, fluent::lint::label);
- err.emit();
- });
+ cx.struct_span_lint(
+ DEREF_NULLPTR,
+ expr.span,
+ fluent::lint_builtin_deref_nullptr,
+ |lint| lint.span_label(expr.span, fluent::label),
+ );
}
}
}
@@ -3060,6 +3130,7 @@ declare_lint! {
/// ### Example
///
/// ```rust,compile_fail
+ /// # #![feature(asm_experimental_arch)]
/// use std::arch::asm;
///
/// fn main() {
@@ -3157,9 +3228,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
cx.lookup_with_diagnostics(
NAMED_ASM_LABELS,
Some(target_spans),
- |diag| {
- diag.build(fluent::lint::builtin_asm_labels).emit();
- },
+ fluent::lint_builtin_asm_labels,
+ |lint| lint,
BuiltinLintDiagnostics::NamedAsmLabel(
"only local labels of the form `<number>:` should be used in inline asm"
.to_string(),
@@ -3170,3 +3240,118 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
}
}
}
+
+declare_lint! {
+ /// The `special_module_name` lint detects module
+ /// declarations for files that have a special meaning.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// mod lib;
+ ///
+ /// fn main() {
+ /// lib::run();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Cargo recognizes `lib.rs` and `main.rs` as the root of a
+ /// library or binary crate, so declaring them as modules
+ /// will lead to miscompilation of the crate unless configured
+ /// explicitly.
+ ///
+ /// To access a library from a binary target within the same crate,
+ /// use `your_crate_name::` as the path instead of `lib::`:
+ ///
+ /// ```rust,compile_fail
+ /// // bar/src/lib.rs
+ /// fn run() {
+ /// // ...
+ /// }
+ ///
+ /// // bar/src/main.rs
+ /// fn main() {
+ /// bar::run();
+ /// }
+ /// ```
+ ///
+ /// Binary targets cannot be used as libraries and so declaring
+ /// one as a module is not allowed.
+ pub SPECIAL_MODULE_NAME,
+ Warn,
+ "module declarations for files with a special meaning",
+}
+
+declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]);
+
+impl EarlyLintPass for SpecialModuleName {
+ fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
+ for item in &krate.items {
+ if let ast::ItemKind::Mod(
+ _,
+ ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
+ ) = item.kind
+ {
+ if item.attrs.iter().any(|a| a.has_name(sym::path)) {
+ continue;
+ }
+
+ match item.ident.name.as_str() {
+ "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for lib.rs", |lint| {
+ lint
+ .note("lib.rs is the root of this crate's library target")
+ .help("to refer to it from other targets, use the library's name as the path")
+ }),
+ "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for main.rs", |lint| {
+ lint
+ .note("a binary crate cannot be used as library")
+ }),
+ _ => continue
+ }
+ }
+ }
+ }
+}
+
+pub use rustc_session::lint::builtin::UNEXPECTED_CFGS;
+
+declare_lint_pass!(UnexpectedCfgs => [UNEXPECTED_CFGS]);
+
+impl EarlyLintPass for UnexpectedCfgs {
+ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
+ let cfg = &cx.sess().parse_sess.config;
+ let check_cfg = &cx.sess().parse_sess.check_config;
+ for &(name, value) in cfg {
+ if let Some(names_valid) = &check_cfg.names_valid {
+ if !names_valid.contains(&name) {
+ cx.lookup(
+ UNEXPECTED_CFGS,
+ None::<MultiSpan>,
+ fluent::lint_builtin_unexpected_cli_config_name,
+ |diag| diag.help(fluent::help).set_arg("name", name),
+ );
+ }
+ }
+ if let Some(value) = value {
+ if let Some(values) = &check_cfg.values_valid.get(&name) {
+ if !values.contains(&value) {
+ cx.lookup(
+ UNEXPECTED_CFGS,
+ None::<MultiSpan>,
+ fluent::lint_builtin_unexpected_cli_config_value,
+ |diag| {
+ diag.help(fluent::help)
+ .set_arg("name", name)
+ .set_arg("value", value)
+ },
+ );
+ }
+ }
+ }
+ }
+ }
+}