thread through a HirId to emit lints in the right place

Previously the lint would be reported at the right span, but could not be `allow`ed or `expect`ed in that location, because the lint was actually emitted using `CRATE_HIR_ID`
This commit is contained in:
Folkert de Vries
2026-04-14 22:02:22 +02:00
parent dfb680751e
commit a7590138a7
14 changed files with 65 additions and 29 deletions
+1 -1
View File
@@ -346,7 +346,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
match infer {
ty::TyVar(_) => self.next_ty_var(DUMMY_SP),
ty::IntVar(_) => self.next_int_var(),
ty::FloatVar(_) => self.next_float_var(DUMMY_SP),
ty::FloatVar(_) => self.next_float_var(DUMMY_SP, None),
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
bug!("unexpected fresh ty outside of the trait solver")
}
+1 -1
View File
@@ -349,7 +349,7 @@ fn check_expr_kind(
let tcx = self.tcx;
match expr.kind {
ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expected),
ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expr.hir_id, expected),
ExprKind::Binary(op, lhs, rhs) => self.check_expr_binop(expr, op, lhs, rhs, expected),
ExprKind::Assign(lhs, rhs, span) => {
self.check_expr_assign(expr, expected, lhs, rhs, span)
+5 -5
View File
@@ -161,15 +161,15 @@ fn calculate_fallback_to_f32(&self, unresolved_variables: &[Ty<'tcx>]) -> UnordS
.flat_map(|ty| ty.float_vid())
.filter(|vid| roots.contains(&self.root_float_var(*vid)))
.inspect(|vid| {
let span = self.float_var_origin(*vid);
let origin = self.float_var_origin(*vid);
// Show the entire literal in the suggestion to make it clearer.
let literal = self.tcx.sess.source_map().span_to_snippet(span).ok();
let literal = self.tcx.sess.source_map().span_to_snippet(origin.span).ok();
self.tcx.emit_node_span_lint(
FLOAT_LITERAL_F32_FALLBACK,
CRATE_HIR_ID,
span,
origin.lint_id.unwrap_or(CRATE_HIR_ID),
origin.span,
errors::FloatLiteralF32Fallback {
span: literal.as_ref().map(|_| span),
span: literal.as_ref().map(|_| origin.span),
literal: literal.unwrap_or_default(),
},
);
@@ -718,6 +718,7 @@ fn suggest_ptr_null_mut(
pub(in super::super) fn check_expr_lit(
&self,
lit: &hir::Lit,
lint_id: HirId,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
let tcx = self.tcx;
@@ -765,7 +766,7 @@ pub(in super::super) fn check_expr_lit(
ty::Float(_) => Some(ty),
_ => None,
});
opt_ty.unwrap_or_else(|| self.next_float_var(lit.span))
opt_ty.unwrap_or_else(|| self.next_float_var(lit.span, Some(lint_id)))
}
ast::LitKind::Bool(_) => tcx.types.bool,
ast::LitKind::CStr(_, _) => Ty::new_imm_ref(
+1 -1
View File
@@ -917,7 +917,7 @@ fn should_peel_smart_pointer(&self, peel_kind: PeelKind, expected: Ty<'tcx>) ->
fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
let ty = match &lt.kind {
rustc_hir::PatExprKind::Lit { lit, negated } => {
let ty = self.check_expr_lit(lit, Expectation::NoExpectation);
let ty = self.check_expr_lit(lit, lt.hir_id, Expectation::NoExpectation);
if *negated {
self.register_bound(
ty,
@@ -107,7 +107,10 @@ pub fn instantiate_canonical_var(
CanonicalVarKind::Int => self.next_int_var().into(),
CanonicalVarKind::Float => self.next_float_var(span).into(),
CanonicalVarKind::Float => {
// There is no HirId available to pass as a lint_id.
self.next_float_var(span, None).into()
}
CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound, .. }) => {
let universe_mapped = universe_map(universe);
+12 -9
View File
@@ -16,8 +16,8 @@
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
use rustc_data_structures::unify as ut;
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, HirId};
use rustc_index::IndexVec;
use rustc_macros::extension;
pub use rustc_macros::{TypeFoldable, TypeVisitable};
@@ -39,6 +39,7 @@
use type_variable::TypeVariableOrigin;
use crate::infer::snapshot::undo_log::UndoLog;
use crate::infer::type_variable::FloatVariableOrigin;
use crate::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
use crate::traits::{
self, ObligationCause, ObligationInspector, PredicateObligation, PredicateObligations,
@@ -109,9 +110,10 @@ pub struct InferCtxtInner<'tcx> {
/// Map from floating variable to the kind of float it represents.
float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
/// Map from floating variable to the origin span it came from. This is only used for the FCW
/// for the fallback to `f32`, so can be removed once the `f32` fallback is removed.
float_origin_span_storage: IndexVec<FloatVid, Span>,
/// Map from floating variable to the origin span it came from, and the HirId that should be
/// used to lint at that location. This is only used for the FCW for the fallback to `f32`,
/// so can be removed once the `f32` fallback is removed.
float_origin_origin_storage: IndexVec<FloatVid, FloatVariableOrigin>,
/// Tracks the set of region variables and the constraints between them.
///
@@ -166,7 +168,7 @@ fn new() -> InferCtxtInner<'tcx> {
const_unification_storage: Default::default(),
int_unification_storage: Default::default(),
float_unification_storage: Default::default(),
float_origin_span_storage: Default::default(),
float_origin_origin_storage: Default::default(),
region_constraint_storage: Some(Default::default()),
region_obligations: Default::default(),
region_assumptions: Default::default(),
@@ -653,8 +655,8 @@ pub fn type_var_origin(&self, vid: TyVid) -> TypeVariableOrigin {
/// Returns the origin of the float type variable identified by `vid`.
///
/// No attempt is made to resolve `vid` to its root variable.
pub fn float_var_origin(&self, vid: FloatVid) -> Span {
self.inner.borrow_mut().float_origin_span_storage[vid]
pub fn float_var_origin(&self, vid: FloatVid) -> FloatVariableOrigin {
self.inner.borrow_mut().float_origin_origin_storage[vid]
}
/// Returns the origin of the const variable identified by `vid`
@@ -834,10 +836,11 @@ pub fn next_int_var(&self) -> Ty<'tcx> {
Ty::new_int_var(self.tcx, next_int_var_id)
}
pub fn next_float_var(&self, span: Span) -> Ty<'tcx> {
pub fn next_float_var(&self, span: Span, lint_id: Option<HirId>) -> Ty<'tcx> {
let mut inner = self.inner.borrow_mut();
let next_float_var_id = inner.float_unification_table().new_key(ty::FloatVarValue::Unknown);
let span_index = inner.float_origin_span_storage.push(span);
let origin = FloatVariableOrigin { span, lint_id };
let span_index = inner.float_origin_origin_storage.push(origin);
debug_assert_eq!(next_float_var_id, span_index);
Ty::new_float_var(self.tcx, next_float_var_id)
}
@@ -6,12 +6,11 @@
self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder,
TypeSuperFoldable, TypeVisitableExt,
};
use rustc_span::Span;
use tracing::instrument;
use ut::UnifyKey;
use super::VariableLengths;
use crate::infer::type_variable::TypeVariableOrigin;
use crate::infer::type_variable::{FloatVariableOrigin, TypeVariableOrigin};
use crate::infer::unify_key::{ConstVariableValue, ConstVidKey};
use crate::infer::{
ConstVariableOrigin, InferCtxt, InferCtxtInner, RegionVariableOrigin, UnificationTable,
@@ -31,9 +30,9 @@ fn vars_since_snapshot<'tcx, T>(
fn float_vars_since_snapshot(
inner: &mut InferCtxtInner<'_>,
snapshot_var_len: usize,
) -> (Range<FloatVid>, Vec<Span>) {
) -> (Range<FloatVid>, Vec<FloatVariableOrigin>) {
let range = vars_since_snapshot(&inner.float_unification_table(), snapshot_var_len);
(range.clone(), range.map(|index| inner.float_origin_span_storage[index]).collect())
(range.clone(), range.map(|index| inner.float_origin_origin_storage[index]).collect())
}
fn const_vars_since_snapshot<'tcx>(
@@ -141,7 +140,7 @@ struct SnapshotVarData<'tcx> {
region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin<'tcx>>),
type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
int_vars: Range<IntVid>,
float_vars: (Range<FloatVid>, Vec<Span>),
float_vars: (Range<FloatVid>, Vec<FloatVariableOrigin>),
const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
}
@@ -215,8 +214,9 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
ty::FloatVar(vid) => {
if self.snapshot_vars.float_vars.0.contains(&vid) {
let idx = vid.as_usize() - self.snapshot_vars.float_vars.0.start.as_usize();
let span = self.snapshot_vars.float_vars.1[idx];
self.infcx.next_float_var(span)
let FloatVariableOrigin { span, lint_id } =
self.snapshot_vars.float_vars.1[idx];
self.infcx.next_float_var(span, lint_id)
} else {
ty
}
@@ -4,6 +4,7 @@
use rustc_data_structures::undo_log::Rollback;
use rustc_data_structures::{snapshot_vec as sv, unify as ut};
use rustc_hir::HirId;
use rustc_hir::def_id::DefId;
use rustc_index::IndexVec;
use rustc_middle::bug;
@@ -99,6 +100,16 @@ pub struct TypeVariableOrigin {
pub param_def_id: Option<DefId>,
}
#[derive(Copy, Clone, Debug)]
pub struct FloatVariableOrigin {
pub span: Span,
/// `HirId` to lint at for this float variable, if any.
///
/// This should only be used for diagnostics.
pub lint_id: Option<HirId>,
}
#[derive(Clone)]
pub(crate) struct TypeVariableData {
origin: TypeVariableOrigin,
+1
View File
@@ -47,6 +47,7 @@
EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
EXPORTED_PRIVATE_DEPENDENCIES,
FFI_UNWIND_CALLS,
FLOAT_LITERAL_F32_FALLBACK,
FORBIDDEN_LINT_GROUPS,
FUNCTION_ITEM_REFERENCES,
FUZZY_PROVENANCE_CASTS,
+17
View File
@@ -0,0 +1,17 @@
//@ build-pass
#![feature(f16, f32_from_f16)]
#![allow(unused)]
// Check that float conversions work, specifically a {float} literal that normally would fall back
// to an f64 but due to the Into bound here falls back to f32. Also test that the lint is emitted in
// the correct location, and can be `expect`ed or `allow`ed.
fn convert(x: impl Into<f32>) -> f32 {
x.into()
}
pub fn main() {
let _ = convert(1.0f32);
let _ = convert(1.0f16);
#[expect(float_literal_f32_fallback)]
let _ = convert(1.0);
}
@@ -6,7 +6,7 @@ LL | foo(1.0);
|
= 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 #154024 <https://github.com/rust-lang/rust/issues/154024>
= note: `#[warn(float_literal_f32_fallback)]` on by default
= note: `#[warn(float_literal_f32_fallback)]` (part of `#[warn(future_incompatible)]`) on by default
warning: falling back to `f32` as the trait bound `f32: From<f64>` is not satisfied
--> $DIR/f32-into-f32.rs:12:11
@@ -6,7 +6,7 @@ LL | foo(1.0);
|
= 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 #154024 <https://github.com/rust-lang/rust/issues/154024>
= note: `#[warn(float_literal_f32_fallback)]` on by default
= note: `#[warn(float_literal_f32_fallback)]` (part of `#[warn(future_incompatible)]`) on by default
warning: falling back to `f32` as the trait bound `f32: From<f64>` is not satisfied
--> $DIR/f32-into-f32.rs:12:11
+1 -1
View File
@@ -6,7 +6,7 @@ LL | let x = f32::from(3.14);
|
= 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 #154024 <https://github.com/rust-lang/rust/issues/154024>
= note: `#[warn(float_literal_f32_fallback)]` on by default
= note: `#[warn(float_literal_f32_fallback)]` (part of `#[warn(future_incompatible)]`) on by default
warning: 1 warning emitted