Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1019,10 +1019,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if let Some(hir_id) =
terminator.source_info.scope.lint_root(&self.mir.source_scopes)
{
let msg = "tail calling a function marked with `#[track_caller]` has no special effect";
bx.tcx().node_lint(TAIL_CALL_TRACK_CALLER, hir_id, |d| {
_ = d.primary_message(msg).span(fn_span)
});
bx.tcx().emit_node_lint(TAIL_CALL_TRACK_CALLER, hir_id, rustc_errors::DiagDecorator(|d| {
_ = d.primary_message("tail calling a function marked with `#[track_caller]` has no special effect").span(fn_span)
}));
}

let instance = ty::Instance::resolve_for_fn_ptr(
Expand Down
12 changes: 9 additions & 3 deletions compiler/rustc_hir_typeck/src/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,12 +736,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
let trait_name = self.tcx.item_name(pick.item.container_id(self.tcx));
let import_span = self.tcx.hir_span_if_local(pick.import_ids[0].to_def_id()).unwrap();

self.tcx.node_lint(AMBIGUOUS_GLOB_IMPORTED_TRAITS, segment.hir_id, |diag| {
diag.primary_message(format!("Use of ambiguously glob imported trait `{trait_name}`"))
self.tcx.emit_node_lint(
AMBIGUOUS_GLOB_IMPORTED_TRAITS,
segment.hir_id,
rustc_errors::DiagDecorator(|diag| {
diag.primary_message(format!(
"Use of ambiguously glob imported trait `{trait_name}`"
))
.span(segment.ident.span)
.span_label(import_span, format!("`{trait_name}` imported ambiguously here"))
.help(format!("Import `{trait_name}` explicitly"));
});
}),
);
}

fn upcast(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ pub trait LintContext {
// set the span in their `decorate` function (preferably using set_span).
/// Emit a lint at the appropriate level, with an optional associated span.
///
/// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
/// [`diag_lint_level`]: rustc_middle::lint::diag_lint_level#decorate-signature
#[track_caller]
fn opt_span_diag_lint<S: Into<MultiSpan>>(
&self,
Expand Down
189 changes: 0 additions & 189 deletions compiler/rustc_middle/src/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,201 +293,12 @@ fn explain_lint_level_source(
}
}

/// The innermost function for emitting lints.
///
/// If you are looking to implement a lint, look for higher level functions,
/// for example:
/// - [`TyCtxt::emit_node_span_lint`]
/// - [`TyCtxt::node_lint`]
/// - `LintContext::opt_span_lint`
///
/// ## `decorate`
///
/// It is not intended to call `emit`/`cancel` on the `Diag` passed in the `decorate` callback.
#[track_caller]
pub fn lint_level(
sess: &Session,
lint: &'static Lint,
level: LevelAndSource,
span: Option<MultiSpan>,
decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
) {
// Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
// the "real" work.
#[track_caller]
fn lint_level_impl(
sess: &Session,
lint: &'static Lint,
level: LevelAndSource,
span: Option<MultiSpan>,
decorate: Box<dyn '_ + for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>)>,
) {
let LevelAndSource { level, lint_id, src } = level;

// Check for future incompatibility lints and issue a stronger warning.
let future_incompatible = lint.future_incompatible;

let has_future_breakage = future_incompatible.map_or(
// Default allow lints trigger too often for testing.
sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow,
|incompat| incompat.report_in_deps,
);

// Convert lint level to error level.
let err_level = match level {
Level::Allow => {
if has_future_breakage {
rustc_errors::Level::Allow
} else {
return;
}
}
Level::Expect => {
// This case is special as we actually allow the lint itself in this context, but
// we can't return early like in the case for `Level::Allow` because we still
// need the lint diagnostic to be emitted to `rustc_error::DiagCtxtInner`.
//
// We can also not mark the lint expectation as fulfilled here right away, as it
// can still be cancelled in the decorate function. All of this means that we simply
// create a `Diag` and continue as we would for warnings.
rustc_errors::Level::Expect
}
Level::ForceWarn => rustc_errors::Level::ForceWarning,
Level::Warn => rustc_errors::Level::Warning,
Level::Deny | Level::Forbid => rustc_errors::Level::Error,
};
let mut err = Diag::new(sess.dcx(), err_level, "");
if let Some(span) = span {
err.span(span);
}
if let Some(lint_id) = lint_id {
err.lint_id(lint_id);
}

// If this code originates in a foreign macro, aka something that this crate
// did not itself author, then it's likely that there's nothing this crate
// can do about it. We probably want to skip the lint entirely.
if err.span.primary_spans().iter().any(|s| s.in_external_macro(sess.source_map())) {
// Any suggestions made here are likely to be incorrect, so anything we
// emit shouldn't be automatically fixed by rustfix.
err.disable_suggestions();

// If this is a future incompatible that is not an edition fixing lint
// it'll become a hard error, so we have to emit *something*. Also,
// if this lint occurs in the expansion of a macro from an external crate,
// allow individual lints to opt-out from being reported.
let incompatible = future_incompatible.is_some_and(|f| f.reason.edition().is_none());

// In rustc, for the find_attr macro, we want to always emit this.
// This completely circumvents normal lint checking, which usually doesn't happen for macros from other crates.
// However, we kind of want that when using find_attr from another rustc crate. So we cheat a little.
let is_in_find_attr = sess.enable_internal_lints()
&& err.span.primary_spans().iter().any(|s| {
s.source_callee().is_some_and(
|i| matches!(i.kind, ExpnKind::Macro(_, name) if name.as_str() == "find_attr")
)
});

if !incompatible && !lint.report_in_external_macro && !is_in_find_attr {
err.cancel();

// Don't continue further, since we don't want to have
// `diag_span_note_once` called for a diagnostic that isn't emitted.
return;
}
}

err.is_lint(lint.name_lower(), has_future_breakage);

// Lint diagnostics that are covered by the expect level will not be emitted outside
// the compiler. It is therefore not necessary to add any information for the user.
// This will therefore directly call the decorate function which will in turn emit
// the diagnostic.
if let Level::Expect = level {
decorate(&mut err);
err.emit();
return;
}

if let Some(future_incompatible) = future_incompatible {
let explanation = match future_incompatible.reason {
FutureIncompatibilityReason::FutureReleaseError(_) => {
"this was previously accepted by the compiler but is being phased out; \
it will become a hard error in a future release!"
.to_owned()
}
FutureIncompatibilityReason::FutureReleaseSemanticsChange(_) => {
"this will change its meaning in a future release!".to_owned()
}
FutureIncompatibilityReason::EditionError(EditionFcw { edition, .. }) => {
let current_edition = sess.edition();
format!(
"this is accepted in the current edition (Rust {current_edition}) but is a hard error in Rust {edition}!"
)
}
FutureIncompatibilityReason::EditionSemanticsChange(EditionFcw {
edition, ..
}) => {
format!("this changes meaning in Rust {edition}")
}
FutureIncompatibilityReason::EditionAndFutureReleaseError(EditionFcw {
edition,
..
}) => {
format!(
"this was previously accepted by the compiler but is being phased out; \
it will become a hard error in Rust {edition} and in a future release in all editions!"
)
}
FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(
EditionFcw { edition, .. },
) => {
format!(
"this changes meaning in Rust {edition} and in a future release in all editions!"
)
}
FutureIncompatibilityReason::Custom(reason, _) => reason.to_owned(),
FutureIncompatibilityReason::Unreachable => unreachable!(),
};

if future_incompatible.explain_reason {
err.warn(explanation);
}

let citation =
format!("for more information, see {}", future_incompatible.reason.reference());
err.note(citation);
}

// Finally, run `decorate`. `decorate` can call `trimmed_path_str` (directly or indirectly),
// so we need to make sure when we do call `decorate` that the diagnostic is eventually
// emitted or we'll get a `must_produce_diag` ICE.
//
// When is a diagnostic *eventually* emitted? Well, that is determined by 2 factors:
// 1. If the corresponding `rustc_errors::Level` is beyond warning, i.e. `ForceWarning(_)`
// or `Error`, then the diagnostic will be emitted regardless of CLI options.
// 2. If the corresponding `rustc_errors::Level` is warning, then that can be affected by
// `-A warnings` or `--cap-lints=xxx` on the command line. In which case, the diagnostic
// will be emitted if `can_emit_warnings` is true.
let skip = err_level == rustc_errors::Level::Warning && !sess.dcx().can_emit_warnings();

if !skip {
decorate(&mut err);
}

explain_lint_level_source(sess, lint, level, src, &mut err);
err.emit()
}
lint_level_impl(sess, lint, level, span, Box::new(decorate))
}

/// The innermost function for emitting lints implementing the [`trait@Diagnostic`] trait.
///
/// If you are looking to implement a lint, look for higher level functions,
/// for example:
///
/// - [`TyCtxt::emit_node_span_lint`]
/// - [`TyCtxt::node_lint`]
/// - `LintContext::opt_span_lint`
///
/// This function will replace `lint_level` once all its callers have been replaced
Expand Down
16 changes: 1 addition & 15 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use crate::dep_graph::dep_node::make_metadata;
use crate::dep_graph::{DepGraph, DepKindVTable, DepNodeIndex};
use crate::ich::StableHashingContext;
use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind};
use crate::lint::{diag_lint_level, lint_level};
use crate::lint::diag_lint_level;
use crate::metadata::ModChild;
use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature};
use crate::middle::resolve_bound_vars;
Expand Down Expand Up @@ -2585,20 +2585,6 @@ impl<'tcx> TyCtxt<'tcx> {
diag_lint_level(self.sess, lint, level, None, decorator);
}

/// Emit a lint at the appropriate level for a hir node.
///
/// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
#[track_caller]
pub fn node_lint(
self,
lint: &'static Lint,
id: HirId,
decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
) {
let level = self.lint_level_at_node(lint, id);
lint_level(self.sess, lint, level, None, decorate);
}

pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate<'tcx>]> {
let map = self.in_scope_traits_map(id.owner)?;
let candidates = map.get(&id.local_id)?;
Expand Down
6 changes: 3 additions & 3 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,16 +400,16 @@ pub(crate) fn run_global_ctxt(
{}/rustdoc/how-to-write-documentation.html",
crate::DOC_RUST_LANG_ORG_VERSION
);
tcx.node_lint(
tcx.emit_node_lint(
crate::lint::MISSING_CRATE_LEVEL_DOCS,
DocContext::as_local_hir_id(tcx, krate.module.item_id).unwrap(),
|lint| {
rustc_errors::DiagDecorator(|lint| {
if let Some(local_def_id) = krate.module.item_id.as_local_def_id() {
lint.span(tcx.def_span(local_def_id));
}
lint.primary_message("no documentation found for this crate's top-level module");
lint.help(help);
},
}),
);
}

Expand Down
14 changes: 7 additions & 7 deletions tests/ui/imports/ambiguous-trait-in-scope.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ LL | use m2::*;
LL | 0u8.method1();
| ^^^^^^^
|
= help: Import `Trait` explicitly
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #147992 <https://github.com/rust-lang/rust/issues/147992>
= help: Import `Trait` explicitly
= note: `#[warn(ambiguous_glob_imported_traits)]` (part of `#[warn(future_incompatible)]`) on by default

error[E0599]: no method named `method2` found for type `u8` in the current scope
Expand Down Expand Up @@ -49,9 +49,9 @@ LL | use m2::*;
LL | 0u8.method2();
| ^^^^^^^
|
= help: Import `Trait` explicitly
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #147992 <https://github.com/rust-lang/rust/issues/147992>
= help: Import `Trait` explicitly

warning: Use of ambiguously glob imported trait `Trait`
--> $DIR/ambiguous-trait-in-scope.rs:49:9
Expand All @@ -62,9 +62,9 @@ LL | use m2_reexport::*;
LL | 0u8.method1();
| ^^^^^^^
|
= help: Import `Trait` explicitly
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #147992 <https://github.com/rust-lang/rust/issues/147992>
= help: Import `Trait` explicitly

error[E0599]: no method named `method2` found for type `u8` in the current scope
--> $DIR/ambiguous-trait-in-scope.rs:51:9
Expand All @@ -88,9 +88,9 @@ LL | use ambig_reexport::*;
LL | 0u8.method1();
| ^^^^^^^
|
= help: Import `Trait` explicitly
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #147992 <https://github.com/rust-lang/rust/issues/147992>
= help: Import `Trait` explicitly

error[E0599]: no method named `method2` found for type `u8` in the current scope
--> $DIR/ambiguous-trait-in-scope.rs:58:9
Expand All @@ -115,9 +115,9 @@ LL | use external::m2::*;
LL | 0u8.method1();
| ^^^^^^^
|
= help: Import `Trait` explicitly
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #147992 <https://github.com/rust-lang/rust/issues/147992>
= help: Import `Trait` explicitly

error[E0599]: no method named `method2` found for type `u8` in the current scope
--> $DIR/ambiguous-trait-in-scope.rs:66:9
Expand All @@ -142,9 +142,9 @@ LL | use external::m2_reexport::*;
LL | 0u8.method1();
| ^^^^^^^
|
= help: Import `Trait` explicitly
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #147992 <https://github.com/rust-lang/rust/issues/147992>
= help: Import `Trait` explicitly

error[E0599]: no method named `method2` found for type `u8` in the current scope
--> $DIR/ambiguous-trait-in-scope.rs:74:9
Expand All @@ -168,9 +168,9 @@ LL | use external::ambig_reexport::*;
LL | 0u8.method1();
| ^^^^^^^
|
= help: Import `Trait` explicitly
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #147992 <https://github.com/rust-lang/rust/issues/147992>
= help: Import `Trait` explicitly

error[E0599]: no method named `method2` found for type `u8` in the current scope
--> $DIR/ambiguous-trait-in-scope.rs:81:9
Expand Down
Loading