From d4cbd9a440d0106fed53cc173dd539492f95f382 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 27 Jul 2025 12:56:02 +0200 Subject: Add lint against integer to pointer transmutes --- compiler/rustc_lint/messages.ftl | 8 ++++ compiler/rustc_lint/src/lints.rs | 42 ++++++++++++++++ compiler/rustc_lint/src/transmute.rs | 92 +++++++++++++++++++++++++++++++++++- 3 files changed, 141 insertions(+), 1 deletion(-) (limited to 'compiler') diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 940a07c94df..417e5a97069 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -462,6 +462,14 @@ lint_invalid_reference_casting_note_book = for more information, visit + .help_exposed_provenance = for more information about exposed provenance, see + .suggestion_with_exposed_provenance = use `std::ptr::with_exposed_provenance{$suffix}` instead to use a previously exposed provenance + .suggestion_without_provenance_mut = if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + lint_legacy_derive_helpers = derive helper attribute is used before it is introduced .label = the attribute is introduced here diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 6c509734626..5c91b36133b 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + #![allow(rustc::untranslatable_diagnostic)] use std::num::NonZero; @@ -1542,6 +1544,46 @@ impl<'a> LintDiagnostic<'a, ()> for DropGlue<'_> { } } +// transmute.rs +#[derive(LintDiagnostic)] +#[diag(lint_int_to_ptr_transmutes)] +#[note] +#[note(lint_note_exposed_provenance)] +#[help(lint_suggestion_without_provenance_mut)] +#[help(lint_help_transmute)] +#[help(lint_help_exposed_provenance)] +pub(crate) struct IntegerToPtrTransmutes<'tcx> { + #[subdiagnostic] + pub suggestion: IntegerToPtrTransmutesSuggestion<'tcx>, +} + +#[derive(Subdiagnostic)] +pub(crate) enum IntegerToPtrTransmutesSuggestion<'tcx> { + #[multipart_suggestion( + lint_suggestion_with_exposed_provenance, + applicability = "machine-applicable" + )] + ToPtr { + dst: Ty<'tcx>, + suffix: &'static str, + #[suggestion_part(code = "std::ptr::with_exposed_provenance{suffix}::<{dst}>(")] + start_call: Span, + }, + #[multipart_suggestion( + lint_suggestion_with_exposed_provenance, + applicability = "machine-applicable" + )] + ToRef { + dst: Ty<'tcx>, + suffix: &'static str, + ref_mutbl: &'static str, + #[suggestion_part( + code = "&{ref_mutbl}*std::ptr::with_exposed_provenance{suffix}::<{dst}>(" + )] + start_call: Span, + }, +} + // types.rs #[derive(LintDiagnostic)] #[diag(lint_range_endpoint_out_of_range)] diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index bc1d4587d07..239c8649041 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -1,3 +1,4 @@ +use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; @@ -7,6 +8,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::sym; +use crate::lints::{IntegerToPtrTransmutes, IntegerToPtrTransmutesSuggestion}; use crate::{LateContext, LateLintPass}; declare_lint! { @@ -67,9 +69,44 @@ declare_lint! { "detects transmutes that can also be achieved by other operations" } +declare_lint! { + /// The `integer_to_ptr_transmutes` lint detects integer to pointer + /// transmutes where the resulting pointers are undefined behavior to dereference. + /// + /// ### Example + /// + /// ```rust + /// fn foo(a: usize) -> *const u8 { + /// unsafe { + /// std::mem::transmute::(a) + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Any attempt to use the resulting pointers are undefined behavior as the resulting + /// pointers won't have any provenance. + /// + /// Alternatively, [`std::ptr::with_exposed_provenance`] should be used, as they do not + /// carry the provenance requirement. If wanting to create pointers without provenance + /// [`std::ptr::without_provenance`] should be used instead. + /// + /// See [`std::mem::transmute`] in the reference for more details. + /// + /// [`std::mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html + /// [`std::ptr::with_exposed_provenance`]: https://doc.rust-lang.org/std/ptr/fn.with_exposed_provenance.html + /// [`std::ptr::without_provenance`]: https://doc.rust-lang.org/std/ptr/fn.without_provenance.html + pub INTEGER_TO_PTR_TRANSMUTES, + Warn, + "detects integer to pointer transmutes", +} + pub(crate) struct CheckTransmutes; -impl_lint_pass!(CheckTransmutes => [PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, UNNECESSARY_TRANSMUTES]); +impl_lint_pass!(CheckTransmutes => [PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, UNNECESSARY_TRANSMUTES, INTEGER_TO_PTR_TRANSMUTES]); impl<'tcx> LateLintPass<'tcx> for CheckTransmutes { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { @@ -94,9 +131,62 @@ impl<'tcx> LateLintPass<'tcx> for CheckTransmutes { check_ptr_transmute_in_const(cx, expr, body_owner_def_id, const_context, src, dst); check_unnecessary_transmute(cx, expr, callee, arg, const_context, src, dst); + check_int_to_ptr_transmute(cx, expr, arg, src, dst); } } +/// Check for transmutes from integer to pointers (*const/*mut and &/&mut). +/// +/// Using the resulting pointers would be undefined behavior. +fn check_int_to_ptr_transmute<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + arg: &'tcx hir::Expr<'tcx>, + src: Ty<'tcx>, + dst: Ty<'tcx>, +) { + if !matches!(src.kind(), ty::Uint(_) | ty::Int(_)) { + return; + } + let (ty::Ref(_, inner_ty, mutbl) | ty::RawPtr(inner_ty, mutbl)) = dst.kind() else { + return; + }; + // bail-out if the argument is literal 0 as we have other lints for those cases + if matches!(arg.kind, hir::ExprKind::Lit(hir::Lit { node: LitKind::Int(v, _), .. }) if v == 0) { + return; + } + // bail-out if the inner type is a ZST + let Ok(layout_inner_ty) = cx.tcx.layout_of(cx.typing_env().as_query_input(*inner_ty)) else { + return; + }; + if layout_inner_ty.is_1zst() { + return; + } + + let suffix = if mutbl.is_mut() { "_mut" } else { "" }; + cx.tcx.emit_node_span_lint( + INTEGER_TO_PTR_TRANSMUTES, + expr.hir_id, + expr.span, + IntegerToPtrTransmutes { + suggestion: if dst.is_ref() { + IntegerToPtrTransmutesSuggestion::ToRef { + dst: *inner_ty, + suffix, + ref_mutbl: mutbl.prefix_str(), + start_call: expr.span.shrink_to_lo().until(arg.span), + } + } else { + IntegerToPtrTransmutesSuggestion::ToPtr { + dst: *inner_ty, + suffix, + start_call: expr.span.shrink_to_lo().until(arg.span), + } + }, + }, + ); +} + /// Check for transmutes that exhibit undefined behavior. /// For example, transmuting pointers to integers in a const context. /// -- cgit 1.4.1-3-g733a5 From 1da4959e54eaee2b3770301fe4902b65f7b97e9f Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 16 Aug 2025 11:17:19 +0200 Subject: Prefer verbose suggestions for `integer_to_ptr_transmutes` lint --- compiler/rustc_lint/src/lints.rs | 6 ++- tests/ui/lint/int_to_ptr.stderr | 108 ++++++++++++++++++++++++++------------- 2 files changed, 76 insertions(+), 38 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 5c91b36133b..426500dda4a 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1561,7 +1561,8 @@ pub(crate) struct IntegerToPtrTransmutes<'tcx> { pub(crate) enum IntegerToPtrTransmutesSuggestion<'tcx> { #[multipart_suggestion( lint_suggestion_with_exposed_provenance, - applicability = "machine-applicable" + applicability = "machine-applicable", + style = "verbose" )] ToPtr { dst: Ty<'tcx>, @@ -1571,7 +1572,8 @@ pub(crate) enum IntegerToPtrTransmutesSuggestion<'tcx> { }, #[multipart_suggestion( lint_suggestion_with_exposed_provenance, - applicability = "machine-applicable" + applicability = "machine-applicable", + style = "verbose" )] ToRef { dst: Ty<'tcx>, diff --git a/tests/ui/lint/int_to_ptr.stderr b/tests/ui/lint/int_to_ptr.stderr index 437f6442397..4035bda8fb2 100644 --- a/tests/ui/lint/int_to_ptr.stderr +++ b/tests/ui/lint/int_to_ptr.stderr @@ -2,9 +2,7 @@ warning: transmuting an integer to a pointer creates a pointer without provenanc --> $DIR/int_to_ptr.rs:10:36 | LL | let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; - | ----------------------------------------^^ - | | - | help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance: `std::ptr::with_exposed_provenance::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance @@ -12,160 +10,198 @@ LL | let _ptr: *const u8 = unsafe { std::mem::transmute::( = help: for more information about transmute, see = help: for more information about exposed provenance, see = note: `#[warn(integer_to_ptr_transmutes)]` on by default +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *const u8 = unsafe { std::ptr::with_exposed_provenance::(a) }; + | warning: transmuting an integer to a pointer creates a pointer without provenance --> $DIR/int_to_ptr.rs:12:34 | LL | let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; - | --------------------------------------^^ - | | - | help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance: `std::ptr::with_exposed_provenance_mut::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` = help: for more information about transmute, see = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance + | +LL - let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *mut u8 = unsafe { std::ptr::with_exposed_provenance_mut::(a) }; + | warning: transmuting an integer to a pointer creates a pointer without provenance --> $DIR/int_to_ptr.rs:14:38 | LL | let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; - | ------------------------------------------^^ - | | - | help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance: `&*std::ptr::with_exposed_provenance::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` = help: for more information about transmute, see = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static u8 = unsafe { &*std::ptr::with_exposed_provenance::(a) }; + | warning: transmuting an integer to a pointer creates a pointer without provenance --> $DIR/int_to_ptr.rs:16:42 | LL | let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; - | ----------------------------------------------^^ - | | - | help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance: `&mut *std::ptr::with_exposed_provenance_mut::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` = help: for more information about transmute, see = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance + | +LL - let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static mut u8 = unsafe { &mut *std::ptr::with_exposed_provenance_mut::(a) }; + | warning: transmuting an integer to a pointer creates a pointer without provenance --> $DIR/int_to_ptr.rs:19:25 | LL | let _ptr = unsafe { std::mem::transmute::(42usize) }; - | ----------------------------------------^^^^^^^^ - | | - | help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance: `std::ptr::with_exposed_provenance::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` = help: for more information about transmute, see = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(42usize) }; +LL + let _ptr = unsafe { std::ptr::with_exposed_provenance::(42usize) }; + | warning: transmuting an integer to a pointer creates a pointer without provenance --> $DIR/int_to_ptr.rs:21:25 | LL | let _ptr = unsafe { std::mem::transmute::(a + a) }; - | ----------------------------------------^^^^^^ - | | - | help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance: `std::ptr::with_exposed_provenance::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` = help: for more information about transmute, see = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(a + a) }; +LL + let _ptr = unsafe { std::ptr::with_exposed_provenance::(a + a) }; + | warning: transmuting an integer to a pointer creates a pointer without provenance --> $DIR/int_to_ptr.rs:26:36 | LL | let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; - | ----------------------------------------^^ - | | - | help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance: `std::ptr::with_exposed_provenance::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` = help: for more information about transmute, see = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *const u8 = unsafe { std::ptr::with_exposed_provenance::(a) }; + | warning: transmuting an integer to a pointer creates a pointer without provenance --> $DIR/int_to_ptr.rs:28:34 | LL | let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; - | --------------------------------------^^ - | | - | help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance: `std::ptr::with_exposed_provenance_mut::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` = help: for more information about transmute, see = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance + | +LL - let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ptr: *mut u8 = unsafe { std::ptr::with_exposed_provenance_mut::(a) }; + | warning: transmuting an integer to a pointer creates a pointer without provenance --> $DIR/int_to_ptr.rs:30:38 | LL | let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; - | ------------------------------------------^^ - | | - | help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance: `&*std::ptr::with_exposed_provenance::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` = help: for more information about transmute, see = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static u8 = unsafe { &*std::ptr::with_exposed_provenance::(a) }; + | warning: transmuting an integer to a pointer creates a pointer without provenance --> $DIR/int_to_ptr.rs:32:42 | LL | let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; - | ----------------------------------------------^^ - | | - | help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance: `&mut *std::ptr::with_exposed_provenance_mut::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` = help: for more information about transmute, see = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance_mut` instead to use a previously exposed provenance + | +LL - let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; +LL + let _ref: &'static mut u8 = unsafe { &mut *std::ptr::with_exposed_provenance_mut::(a) }; + | warning: transmuting an integer to a pointer creates a pointer without provenance --> $DIR/int_to_ptr.rs:35:25 | LL | let _ptr = unsafe { std::mem::transmute::(42usize) }; - | ----------------------------------------^^^^^^^^ - | | - | help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance: `std::ptr::with_exposed_provenance::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` = help: for more information about transmute, see = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(42usize) }; +LL + let _ptr = unsafe { std::ptr::with_exposed_provenance::(42usize) }; + | warning: transmuting an integer to a pointer creates a pointer without provenance --> $DIR/int_to_ptr.rs:37:25 | LL | let _ptr = unsafe { std::mem::transmute::(a + a) }; - | ----------------------------------------^^^^^^ - | | - | help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance: `std::ptr::with_exposed_provenance::(` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this is dangerous because dereferencing the resulting pointer is undefined behavior = note: exposed provenance semantics can be used to create a pointer based on some previously exposed provenance = help: if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` = help: for more information about transmute, see = help: for more information about exposed provenance, see +help: use `std::ptr::with_exposed_provenance` instead to use a previously exposed provenance + | +LL - let _ptr = unsafe { std::mem::transmute::(a + a) }; +LL + let _ptr = unsafe { std::ptr::with_exposed_provenance::(a + a) }; + | warning: 12 warnings emitted -- cgit 1.4.1-3-g733a5 From e4557f0ea4f7e015b3108dc509bce562f64528bc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 23 Aug 2025 20:54:02 +0000 Subject: Use unnamed lifetime spans as primary spans for MISMATCHED_LIFETIME_SYNTAXES --- compiler/rustc_lint/src/lifetime_syntax.rs | 8 +- src/tools/clippy/tests/ui/ptr_arg.stderr | 4 +- .../type-dependent/issue-71348.full.stderr | 4 +- .../rpit-assoc-pair-with-lifetime.stderr | 4 +- .../example-from-issue48686.stderr | 4 +- .../missing-lifetime-kind.stderr | 16 +-- .../not-tied-to-crate.stderr | 8 +- .../static.stderr | 16 +-- tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs | 6 +- .../lifetimes/mismatched-lifetime-syntaxes.stderr | 153 ++++++++++----------- .../elision/ignore-non-reference-lifetimes.stderr | 8 +- tests/ui/self/self_lifetime-async.stderr | 8 +- tests/ui/self/self_lifetime.stderr | 8 +- 13 files changed, 122 insertions(+), 125 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 464f4fc34b9..413525eb6e5 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -214,9 +214,9 @@ impl LifetimeSyntaxCategories> { } } - pub fn flatten(&self) -> impl Iterator { - let Self { hidden, elided, named } = self; - [hidden.iter(), elided.iter(), named.iter()].into_iter().flatten() + pub fn iter_unnamed(&self) -> impl Iterator { + let Self { hidden, elided, named: _ } = self; + [hidden.iter(), elided.iter()].into_iter().flatten() } } @@ -495,7 +495,7 @@ fn emit_mismatch_diagnostic<'tcx>( cx.emit_span_lint( MISMATCHED_LIFETIME_SYNTAXES, - inputs.flatten().copied().collect::>(), + inputs.iter_unnamed().chain(outputs.iter_unnamed()).copied().collect::>(), lints::MismatchedLifetimeSyntaxes { inputs, outputs, suggestions }, ); } diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 87235057349..f32e83d8b81 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -268,10 +268,10 @@ LL | fn barbar(_x: &mut Vec, y: &mut String) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: eliding a lifetime that's named elsewhere is confusing - --> tests/ui/ptr_arg.rs:314:36 + --> tests/ui/ptr_arg.rs:314:56 | LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - | ^^ ^^ ---- the same lifetime is elided here + | -- -- ^^^^ the same lifetime is elided here | | | | | the lifetime is named here | the lifetime is named here diff --git a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr index 32fa46b92b3..299ae680093 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr @@ -1,8 +1,8 @@ warning: hiding a lifetime that's named elsewhere is confusing - --> $DIR/issue-71348.rs:18:40 + --> $DIR/issue-71348.rs:18:56 | LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target - | ^^ -- ------------------------ the same lifetime is hidden here + | -- -- ^^^^^^^^^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | | | the same lifetime is named here | the lifetime is named here diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr index 3651226e0c3..7a9254bac60 100644 --- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:31 + --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:82 | LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { - | ^^ the lifetime is named here ---- the same lifetime is elided here + | -- the lifetime is named here ^^^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr index 5a7a5a6ebf9..2b7d6a6da27 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/example-from-issue48686.rs:6:21 + --> $DIR/example-from-issue48686.rs:6:50 | LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - | ^^^^^^^ ------- the same lifetime is elided here + | ------- ^^^^^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr index af56a0a0ea5..c4d6e78d787 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:3:22 + --> $DIR/missing-lifetime-kind.rs:3:32 | LL | fn ampersand<'a>(x: &'a u8) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn ampersand<'a>(x: &'a u8) -> &'a u8 { | ++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:10:21 + --> $DIR/missing-lifetime-kind.rs:10:31 | LL | fn brackets<'a>(x: &'a u8) -> Brackets { - | ^^ -------- the same lifetime is hidden here + | -- ^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -32,10 +32,10 @@ LL | fn brackets<'a>(x: &'a u8) -> Brackets<'a> { | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:17:18 + --> $DIR/missing-lifetime-kind.rs:17:28 | LL | fn comma<'a>(x: &'a u8) -> Comma { - | ^^ --------- the same lifetime is hidden here + | -- ^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -46,10 +46,10 @@ LL | fn comma<'a>(x: &'a u8) -> Comma<'a, u8> { | +++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:22:23 + --> $DIR/missing-lifetime-kind.rs:22:34 | LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr index cf0a29678fa..28de809faab 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/not-tied-to-crate.rs:8:16 + --> $DIR/not-tied-to-crate.rs:8:31 | LL | fn bar(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn bar(x: &'static u8) -> &'static u8 { | +++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/not-tied-to-crate.rs:14:16 + --> $DIR/not-tied-to-crate.rs:14:31 | LL | fn baz(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr index d60bec6f7e4..5f21a2877a7 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:16:18 + --> $DIR/static.rs:16:33 | LL | fn ampersand(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn ampersand(x: &'static u8) -> &'static u8 { | +++++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:23:17 + --> $DIR/static.rs:23:32 | LL | fn brackets(x: &'static u8) -> Brackets { - | ^^^^^^^ -------- the same lifetime is hidden here + | ------- ^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -32,10 +32,10 @@ LL | fn brackets(x: &'static u8) -> Brackets<'static> { | +++++++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:30:14 + --> $DIR/static.rs:30:29 | LL | fn comma(x: &'static u8) -> Comma { - | ^^^^^^^ --------- the same lifetime is hidden here + | ------- ^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -46,10 +46,10 @@ LL | fn comma(x: &'static u8) -> Comma<'static, u8> { | ++++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:35:19 + --> $DIR/static.rs:35:35 | LL | fn underscore(x: &'static u8) -> &'_ u8 { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs index f6260c47202..f404c4163a9 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs @@ -36,8 +36,8 @@ fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> Contains fn explicit_bound_path_to_explicit_anonymous_path<'a>( v: ContainsLifetime<'a>, - //~^ ERROR eliding a lifetime that's named elsewhere is confusing ) -> ContainsLifetime<'_> { + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } @@ -188,8 +188,8 @@ mod impl_trait { fn explicit_bound_path_to_impl_trait_precise_capture<'a>( v: ContainsLifetime<'a>, - //~^ ERROR eliding a lifetime that's named elsewhere is confusing ) -> impl FnOnce() + use<'_> { + //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } } @@ -208,8 +208,8 @@ mod dyn_trait { fn explicit_bound_path_to_dyn_trait_bound<'a>( v: ContainsLifetime<'a>, - //~^ ERROR hiding a lifetime that's named elsewhere is confusing ) -> Box + '_> { + //~^ ERROR hiding a lifetime that's named elsewhere is confusing Box::new(iter::once(v)) } } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr index 20b7561c594..89768fc764a 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:10:47 + --> $DIR/mismatched-lifetime-syntaxes.rs:10:57 | LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &'a u8 { | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:15:57 + --> $DIR/mismatched-lifetime-syntaxes.rs:15:68 | LL | fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -36,7 +36,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:22:48 | LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { - | ^^^^^^^^^^^^^^^^ -- the same lifetime is elided here + | ^^^^^^^^^^^^^^^^ ^^ the same lifetime is elided here | | | the lifetime is hidden here | @@ -50,7 +50,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:27:65 | LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | ^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -61,10 +61,10 @@ LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> Con | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:32:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:32:73 | LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | -- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -75,13 +75,12 @@ LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> Con | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:38:25 + --> $DIR/mismatched-lifetime-syntaxes.rs:39:23 | LL | v: ContainsLifetime<'a>, - | ^^ the lifetime is named here -LL | + | -- the lifetime is named here LL | ) -> ContainsLifetime<'_> { - | -- the same lifetime is elided here + | ^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -94,7 +93,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:46:37 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -108,7 +107,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:51:48 | LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | ^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -119,10 +118,10 @@ LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime<' | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:56:48 + --> $DIR/mismatched-lifetime-syntaxes.rs:56:58 | LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | -- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -133,10 +132,10 @@ LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime<' | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:61:58 + --> $DIR/mismatched-lifetime-syntaxes.rs:61:85 | LL | fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -151,7 +150,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:68:37 | LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 { - | ^^^^^^^^^^^^^^^^ --- the same lifetime is elided here + | ^^^^^^^^^^^^^^^^ ^^^ the same lifetime is elided here | | | the lifetime is hidden here | @@ -165,7 +164,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:73:47 | LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { - | ^^^^^^^^^^^^^^^^ -- the same lifetime is elided here + | ^^^^^^^^^^^^^^^^ ^^ the same lifetime is elided here | | | the lifetime is hidden here | @@ -176,10 +175,10 @@ LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:78:64 + --> $DIR/mismatched-lifetime-syntaxes.rs:78:72 | LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -190,10 +189,10 @@ LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &'a | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:83:74 + --> $DIR/mismatched-lifetime-syntaxes.rs:83:83 | LL | fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -205,10 +204,10 @@ LL + fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:89:55 + --> $DIR/mismatched-lifetime-syntaxes.rs:89:67 | LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -219,10 +218,10 @@ LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &'a u8 { | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:94:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:94:78 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -237,7 +236,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:101:56 | LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | ^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -248,10 +247,10 @@ LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> Contains | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:106:56 + --> $DIR/mismatched-lifetime-syntaxes.rs:106:68 | LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | -- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -262,10 +261,10 @@ LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> Contains | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:111:66 + --> $DIR/mismatched-lifetime-syntaxes.rs:111:95 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -277,10 +276,10 @@ LL + fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) - | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:126:39 + --> $DIR/mismatched-lifetime-syntaxes.rs:126:54 | LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -291,10 +290,10 @@ LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &'static u8 { | +++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:131:49 + --> $DIR/mismatched-lifetime-syntaxes.rs:131:65 | LL | fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -306,10 +305,10 @@ LL + fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'static u8 | error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:136:40 + --> $DIR/mismatched-lifetime-syntaxes.rs:136:55 | LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime { - | ^^^^^^^ ---------------- the same lifetime is hidden here + | ------- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -320,10 +319,10 @@ LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime<'sta | +++++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:141:50 + --> $DIR/mismatched-lifetime-syntaxes.rs:141:82 | LL | fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -335,10 +334,10 @@ LL + fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLif | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:147:40 + --> $DIR/mismatched-lifetime-syntaxes.rs:147:57 | LL | fn static_ref_to_implicit_ref(&'static self) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -349,10 +348,10 @@ LL | fn static_ref_to_implicit_ref(&'static self) -> &'static u8 { | +++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:152:50 + --> $DIR/mismatched-lifetime-syntaxes.rs:152:68 | LL | fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -364,10 +363,10 @@ LL + fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'static | error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:157:41 + --> $DIR/mismatched-lifetime-syntaxes.rs:157:58 | LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime { - | ^^^^^^^ ---------------- the same lifetime is hidden here + | ------- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -378,10 +377,10 @@ LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime<' | +++++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:162:51 + --> $DIR/mismatched-lifetime-syntaxes.rs:162:85 | LL | fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -393,10 +392,10 @@ LL + fn static_ref_to_explicit_anonymous_path(&'static self) -> Contains | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:174:55 + --> $DIR/mismatched-lifetime-syntaxes.rs:174:81 | LL | fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -408,10 +407,10 @@ LL + fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:179:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:179:95 | LL | fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { - | ^^ the lifetime is named here -- the same lifetime is elided here + | -- the lifetime is named here ^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -421,10 +420,10 @@ LL + fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> i | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:184:72 + --> $DIR/mismatched-lifetime-syntaxes.rs:184:96 | LL | fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -436,13 +435,12 @@ LL + fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:190:29 + --> $DIR/mismatched-lifetime-syntaxes.rs:191:30 | LL | v: ContainsLifetime<'a>, - | ^^ the lifetime is named here -LL | + | -- the lifetime is named here LL | ) -> impl FnOnce() + use<'_> { - | -- the same lifetime is elided here + | ^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -452,10 +450,10 @@ LL + ) -> impl FnOnce() + use<'a> { | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:204:54 + --> $DIR/mismatched-lifetime-syntaxes.rs:204:88 | LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box + '_> { - | ^^ the lifetime is named here --- the same lifetime is elided here + | -- the lifetime is named here ^^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -464,13 +462,12 @@ LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box $DIR/mismatched-lifetime-syntaxes.rs:210:29 + --> $DIR/mismatched-lifetime-syntaxes.rs:211:34 | LL | v: ContainsLifetime<'a>, - | ^^ the lifetime is named here -LL | + | -- the lifetime is named here LL | ) -> Box + '_> { - | ---------------- the same lifetime is hidden here + | ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -479,10 +476,10 @@ LL | ) -> Box> + '_> { | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:222:33 + --> $DIR/mismatched-lifetime-syntaxes.rs:222:52 | LL | fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 { - | ^^ ^^ --- the same lifetime is elided here + | -- -- ^^^ the same lifetime is elided here | | | | | the lifetime is named here | the lifetime is named here @@ -494,10 +491,10 @@ LL | fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &'a u8 { | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:227:33 + --> $DIR/mismatched-lifetime-syntaxes.rs:227:44 | LL | fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { - | ^^ --- --- the same lifetime is elided here + | -- ^^^ ^^^ the same lifetime is elided here | | | | | the same lifetime is elided here | the lifetime is named here @@ -509,10 +506,10 @@ LL | fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) { | ++ ++ error: hiding or eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:232:53 + --> $DIR/mismatched-lifetime-syntaxes.rs:232:62 | LL | fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) { - | ^^ --- ---------------- the same lifetime is hidden here + | -- ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | | | the same lifetime is elided here | the lifetime is named here @@ -524,10 +521,10 @@ LL | fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&'a u8, Contai | ++ ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:237:38 + --> $DIR/mismatched-lifetime-syntaxes.rs:237:49 | LL | fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) { - | ^^ --- -- -- the same lifetime is named here + | -- ^^^ -- -- the same lifetime is named here | | | | | | | the same lifetime is named here | | the same lifetime is elided here @@ -543,7 +540,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:250:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -557,7 +554,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:253:49 | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime; - | ^^^^^ ---------------- the same lifetime is hidden here + | ^^^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -571,7 +568,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:258:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -585,7 +582,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:263:49 | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime { - | ^^^^^ ---------------- the same lifetime is hidden here + | ^^^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -599,7 +596,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:277:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr index 7108fa1a290..1a5c87114d4 100644 --- a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/ignore-non-reference-lifetimes.rs:6:30 + --> $DIR/ignore-non-reference-lifetimes.rs:6:41 | LL | fn a<'a>(self: Self, a: &'a str) -> &str { - | ^^ ---- the same lifetime is elided here + | -- ^^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -14,10 +14,10 @@ LL | fn a<'a>(self: Self, a: &'a str) -> &'a str { | ++ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/ignore-non-reference-lifetimes.rs:10:33 + --> $DIR/ignore-non-reference-lifetimes.rs:10:44 | LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { - | ^^ ---- the same lifetime is elided here + | -- ^^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/self/self_lifetime-async.stderr b/tests/ui/self/self_lifetime-async.stderr index 43dc96abdc2..78cc610fd04 100644 --- a/tests/ui/self/self_lifetime-async.stderr +++ b/tests/ui/self/self_lifetime-async.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime-async.rs:6:29 + --> $DIR/self_lifetime-async.rs:6:44 | LL | async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -14,10 +14,10 @@ LL | async fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } | ++ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime-async.rs:12:42 + --> $DIR/self_lifetime-async.rs:12:52 | LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/self/self_lifetime.stderr b/tests/ui/self/self_lifetime.stderr index 4f9b2fcd2ad..84f63454633 100644 --- a/tests/ui/self/self_lifetime.stderr +++ b/tests/ui/self/self_lifetime.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime.rs:7:23 + --> $DIR/self_lifetime.rs:7:38 | LL | fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -14,10 +14,10 @@ LL | fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } | ++ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime.rs:13:36 + --> $DIR/self_lifetime.rs:13:46 | LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | -- cgit 1.4.1-3-g733a5 From 3bf61444616fc0b9de1e09031f40be0943823fc5 Mon Sep 17 00:00:00 2001 From: Jana Dönszelmann Date: Mon, 11 Aug 2025 11:46:30 +0200 Subject: Allow errors to be emitted as fatal during attribute parsing --- compiler/rustc_attr_parsing/src/context.rs | 40 ++++++++++++++++++++-------- compiler/rustc_attr_parsing/src/interface.rs | 2 +- compiler/rustc_attr_parsing/src/parser.rs | 23 +++++++++------- compiler/rustc_errors/src/diagnostic.rs | 23 ++++++++++++++++ 4 files changed, 66 insertions(+), 22 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index bb701df6053..f30edbfaaa1 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -5,7 +5,7 @@ use std::sync::LazyLock; use private::Sealed; use rustc_ast::{AttrStyle, MetaItemLit, NodeId}; -use rustc_errors::Diagnostic; +use rustc_errors::{Diag, Diagnostic, Level}; use rustc_feature::AttributeTemplate; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; @@ -263,11 +263,7 @@ impl Stage for Early { sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>, ) -> ErrorGuaranteed { - if self.emit_errors.should_emit() { - sess.dcx().emit_err(diag) - } else { - sess.dcx().create_err(diag).delay_as_bug() - } + self.should_emit().emit_err_or_delay(sess.dcx().create_err(diag)) } fn should_emit(&self) -> ShouldEmit { @@ -333,7 +329,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { /// must be delayed until after HIR is built. This method will take care of the details of /// that. pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { - if !self.stage.should_emit().should_emit() { + if matches!(self.stage.should_emit(), ShouldEmit::Nothing) { return; } let id = self.target_id; @@ -651,8 +647,13 @@ pub enum OmitDoc { Skip, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum ShouldEmit { + /// The operations will emit errors, and lints, and errors are fatal. + /// + /// Only relevant when early parsing, in late parsing equivalent to `ErrorsAndLints`. + /// Late parsing is never fatal, and instead tries to emit as many diagnostics as possible. + EarlyFatal, /// The operation will emit errors and lints. /// This is usually what you need. ErrorsAndLints, @@ -662,10 +663,27 @@ pub enum ShouldEmit { } impl ShouldEmit { - pub fn should_emit(&self) -> bool { + pub(crate) fn emit_err_or_delay(&self, diag: Diag<'_>) -> ErrorGuaranteed { + match self { + ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => diag.emit(), + ShouldEmit::EarlyFatal => diag.upgrade_to_fatal().emit(), + ShouldEmit::ErrorsAndLints => diag.emit(), + ShouldEmit::Nothing => diag.delay_as_bug(), + } + } + + pub(crate) fn maybe_emit_err(&self, diag: Diag<'_>) { match self { - ShouldEmit::ErrorsAndLints => true, - ShouldEmit::Nothing => false, + ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => { + diag.emit(); + } + ShouldEmit::EarlyFatal => { + diag.upgrade_to_fatal().emit(); + } + ShouldEmit::ErrorsAndLints => { + diag.emit(); + } + ShouldEmit::Nothing => {} } } } diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index f652d39a708..b4222e41b71 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -252,7 +252,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { (accept.accept_fn)(&mut cx, args); - if self.stage.should_emit().should_emit() { + if !matches!(self.stage.should_emit(), ShouldEmit::Nothing) { self.check_target( path.get_attribute_path(), attr.span, diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 364f8819d13..3ba188938c6 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -328,15 +328,16 @@ fn expr_to_lit( match res { Ok(lit) => { if token_lit.suffix.is_some() { - psess - .dcx() - .create_err(SuffixedLiteralInAttribute { span: lit.span }) - .emit_unless_delay(!should_emit.should_emit()); + should_emit.emit_err_or_delay( + psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }), + ); None } else { - if should_emit.should_emit() && !lit.kind.is_unsuffixed() { + if !lit.kind.is_unsuffixed() { // Emit error and continue, we can still parse the attribute as if the suffix isn't there - psess.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span }); + should_emit.maybe_emit_err( + psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }), + ); } Some(lit) @@ -366,7 +367,7 @@ fn expr_to_lit( err.downgrade_to_delayed_bug(); } - err.emit_unless_delay(!should_emit.should_emit()); + should_emit.emit_err_or_delay(err); None } } @@ -397,9 +398,11 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { } }; - if self.should_emit.should_emit() && !lit.kind.is_unsuffixed() { + if !lit.kind.is_unsuffixed() { // Emit error and continue, we can still parse the attribute as if the suffix isn't there - self.parser.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span }); + self.should_emit.maybe_emit_err( + self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }), + ); } Ok(lit) @@ -539,7 +542,7 @@ impl<'a> MetaItemListParser<'a> { ) { Ok(s) => Some(s), Err(e) => { - e.emit_unless_delay(!should_emit.should_emit()); + should_emit.emit_err_or_delay(e); None } } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 43ce886975c..96a4ed3218f 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -577,6 +577,29 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { self.level = Level::DelayedBug; } + /// Make emitting this diagnostic fatal + /// + /// Changes the level of this diagnostic to Fatal, and importantly also changes the emission guarantee. + /// This is sound for errors that would otherwise be printed, but now simply exit the process instead. + /// This function still gives an emission guarantee, the guarantee is now just that it exits fatally. + /// For delayed bugs this is different, since those are buffered. If we upgrade one to fatal, another + /// might now be ignored. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn upgrade_to_fatal(mut self) -> Diag<'a, FatalAbort> { + assert!( + matches!(self.level, Level::Error), + "upgrade_to_fatal: cannot upgrade {:?} to Fatal: not an error", + self.level + ); + self.level = Level::Fatal; + + // Take is okay since we immediately rewrap it in another diagnostic. + // i.e. we do emit it despite defusing the original diagnostic's drop bomb. + let diag = self.diag.take(); + Diag { dcx: self.dcx, diag, _marker: PhantomData } + } + with_fn! { with_span_label, /// Appends a labeled span to the diagnostic. /// -- cgit 1.4.1-3-g733a5 From 4b35cde904c1015df42b2c63244c1db1ed51fff9 Mon Sep 17 00:00:00 2001 From: Jana Dönszelmann Date: Mon, 11 Aug 2025 11:46:30 +0200 Subject: Support lints in early attribute parsing --- Cargo.lock | 1 - compiler/rustc_attr_parsing/src/interface.rs | 32 ++++++++--- compiler/rustc_attr_parsing/src/lints.rs | 6 +-- .../rustc_attr_parsing/src/session_diagnostics.rs | 6 +-- compiler/rustc_errors/Cargo.toml | 1 - compiler/rustc_errors/src/lib.rs | 6 +-- compiler/rustc_middle/src/ty/context.rs | 2 + compiler/rustc_session/src/session.rs | 17 +++++- .../lint/unused/unused_attributes-must_use.fixed | 2 + tests/ui/lint/unused/unused_attributes-must_use.rs | 2 + .../lint/unused/unused_attributes-must_use.stderr | 63 ++++++++++++---------- 11 files changed, 93 insertions(+), 45 deletions(-) (limited to 'compiler') diff --git a/Cargo.lock b/Cargo.lock index 89392631127..af206e87c45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3791,7 +3791,6 @@ dependencies = [ "rustc_error_messages", "rustc_fluent_macro", "rustc_hashes", - "rustc_hir_id", "rustc_index", "rustc_lexer", "rustc_lint_defs", diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index b4222e41b71..60523c2877c 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -50,6 +50,27 @@ impl<'sess> AttributeParser<'sess, Early> { target_span: Span, target_node_id: NodeId, features: Option<&'sess Features>, + ) -> Option { + Self::parse_limited_should_emit( + sess, + attrs, + sym, + target_span, + target_node_id, + features, + ShouldEmit::Nothing, + ) + } + + /// Usually you want `parse_limited`, which defaults to no errors. + pub fn parse_limited_should_emit( + sess: &'sess Session, + attrs: &[ast::Attribute], + sym: Symbol, + target_span: Span, + target_node_id: NodeId, + features: Option<&'sess Features>, + should_emit: ShouldEmit, ) -> Option { let mut parsed = Self::parse_limited_all( sess, @@ -59,7 +80,7 @@ impl<'sess> AttributeParser<'sess, Early> { target_span, target_node_id, features, - ShouldEmit::Nothing, + should_emit, ); assert!(parsed.len() <= 1); parsed.pop() @@ -84,9 +105,8 @@ impl<'sess> AttributeParser<'sess, Early> { target, OmitDoc::Skip, std::convert::identity, - |_lint| { - // FIXME: Can't emit lints here for now - // This branch can be hit when an attribute produces a warning during early parsing (such as attributes on macro calls) + |lint| { + crate::lints::emit_attribute_lint(&lint, sess); }, ) } @@ -121,8 +141,8 @@ impl<'sess> AttributeParser<'sess, Early> { cx: &mut parser, target_span, target_id: target_node_id, - emit_lint: &mut |_lint| { - panic!("can't emit lints here for now (nothing uses this atm)"); + emit_lint: &mut |lint| { + crate::lints::emit_attribute_lint(&lint, sess); }, }, attr_span: attr.span, diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 7030f28f23c..069478e7f0c 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -1,13 +1,13 @@ use std::borrow::Cow; use rustc_errors::{DiagArgValue, LintEmitter}; +use rustc_hir::Target; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_hir::{HirId, Target}; use rustc_span::sym; use crate::session_diagnostics; -pub fn emit_attribute_lint(lint: &AttributeLint, lint_emitter: L) { +pub fn emit_attribute_lint(lint: &AttributeLint, lint_emitter: L) { let AttributeLint { id, span, kind } = lint; match kind { @@ -51,7 +51,7 @@ pub fn emit_attribute_lint(lint: &AttributeLint, lint_emi *id, *span, session_diagnostics::InvalidTargetLint { - name, + name: name.clone(), target: target.plural_name(), applied: DiagArgValue::StrListSepByAnd( applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(), diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2192e8f8f83..72bee0ddfbf 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -484,9 +484,9 @@ pub(crate) struct EmptyAttributeList { #[diag(attr_parsing_invalid_target_lint)] #[warning] #[help] -pub(crate) struct InvalidTargetLint<'a> { - pub name: &'a AttrPath, - pub target: &'a str, +pub(crate) struct InvalidTargetLint { + pub name: AttrPath, + pub target: &'static str, pub applied: DiagArgValue, pub only: &'static str, #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index f37b6fb748f..7912b8e6098 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -14,7 +14,6 @@ rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_messages = { path = "../rustc_error_messages" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hashes = { path = "../rustc_hashes" } -rustc_hir_id = { path = "../rustc_hir_id" } rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 38c5716348f..71fc54f0d33 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -61,7 +61,6 @@ pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display, }; use rustc_hashes::Hash128; -use rustc_hir_id::HirId; pub use rustc_lint_defs::{Applicability, listify, pluralize}; use rustc_lint_defs::{Lint, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; @@ -110,13 +109,14 @@ rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24); /// Used to avoid depending on `rustc_middle` in `rustc_attr_parsing`. /// Always the `TyCtxt`. pub trait LintEmitter: Copy { + type Id: Copy; #[track_caller] fn emit_node_span_lint( self, lint: &'static Lint, - hir_id: HirId, + hir_id: Self::Id, span: impl Into, - decorator: impl for<'a> LintDiagnostic<'a, ()>, + decorator: impl for<'a> LintDiagnostic<'a, ()> + DynSend + 'static, ); } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c215e44a965..4990a85466e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1421,6 +1421,8 @@ pub struct TyCtxt<'tcx> { } impl<'tcx> LintEmitter for TyCtxt<'tcx> { + type Id = HirId; + fn emit_node_span_lint( self, lint: &'static Lint, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index bb7ffa2a85d..96767d05439 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -7,6 +7,7 @@ use std::sync::atomic::AtomicBool; use std::{env, fmt, io}; use rand::{RngCore, rng}; +use rustc_ast::NodeId; use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; @@ -22,7 +23,7 @@ use rustc_errors::timings::TimingSectionHandler; use rustc_errors::translation::Translator; use rustc_errors::{ Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort, - TerminalUrl, fallback_fluent_bundle, + LintEmitter, TerminalUrl, fallback_fluent_bundle, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -223,6 +224,20 @@ pub struct Session { pub invocation_temp: Option, } +impl LintEmitter for &'_ Session { + type Id = NodeId; + + fn emit_node_span_lint( + self, + lint: &'static rustc_lint_defs::Lint, + node_id: Self::Id, + span: impl Into, + decorator: impl for<'a> rustc_errors::LintDiagnostic<'a, ()> + DynSend + 'static, + ) { + self.psess.buffer_lint(lint, span, node_id, decorator); + } +} + #[derive(Clone, Copy)] pub enum CodegenUnits { /// Specified by the user. In this case we try fairly hard to produce the diff --git a/tests/ui/lint/unused/unused_attributes-must_use.fixed b/tests/ui/lint/unused/unused_attributes-must_use.fixed index 2e800cbff3f..6bc63c8ee5b 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.fixed +++ b/tests/ui/lint/unused/unused_attributes-must_use.fixed @@ -66,6 +66,8 @@ extern "Rust" { } //~ ERROR unused attribute +//~^ ERROR `#[must_use]` attribute cannot be used on macro calls +//~| WARN this was previously accepted by the compiler but is being phased out global_asm!(""); //~ ERROR attribute cannot be used on diff --git a/tests/ui/lint/unused/unused_attributes-must_use.rs b/tests/ui/lint/unused/unused_attributes-must_use.rs index c41c6c1d706..3c0d76e619f 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.rs +++ b/tests/ui/lint/unused/unused_attributes-must_use.rs @@ -66,6 +66,8 @@ extern "Rust" { } #[must_use] //~ ERROR unused attribute +//~^ ERROR `#[must_use]` attribute cannot be used on macro calls +//~| WARN this was previously accepted by the compiler but is being phased out global_asm!(""); #[must_use] //~ ERROR attribute cannot be used on diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 03baea3a004..231d799057c 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -1,20 +1,29 @@ -error: unused attribute `must_use` +error: `#[must_use]` attribute cannot be used on macro calls --> $DIR/unused_attributes-must_use.rs:68:1 | LL | #[must_use] | ^^^^^^^^^^^ | -note: the built-in attribute `must_use` will be ignored, since it's applied to the macro invocation `global_asm` - --> $DIR/unused_attributes-must_use.rs:69:1 - | -LL | global_asm!(""); - | ^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[must_use]` can be applied to functions, data types, unions, and traits note: the lint level is defined here --> $DIR/unused_attributes-must_use.rs:4:9 | LL | #![deny(unused_attributes, unused_must_use)] | ^^^^^^^^^^^^^^^^^ +error: unused attribute `must_use` + --> $DIR/unused_attributes-must_use.rs:68:1 + | +LL | #[must_use] + | ^^^^^^^^^^^ + | +note: the built-in attribute `must_use` will be ignored, since it's applied to the macro invocation `global_asm` + --> $DIR/unused_attributes-must_use.rs:71:1 + | +LL | global_asm!(""); + | ^^^^^^^^^^ + error: `#[must_use]` attribute cannot be used on extern crates --> $DIR/unused_attributes-must_use.rs:7:1 | @@ -88,7 +97,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on type aliases - --> $DIR/unused_attributes-must_use.rs:71:1 + --> $DIR/unused_attributes-must_use.rs:73:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -97,7 +106,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on function params - --> $DIR/unused_attributes-must_use.rs:75:8 + --> $DIR/unused_attributes-must_use.rs:77:8 | LL | fn qux<#[must_use] T>(_: T) {} | ^^^^^^^^^^^ @@ -106,7 +115,7 @@ LL | fn qux<#[must_use] T>(_: T) {} = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on associated consts - --> $DIR/unused_attributes-must_use.rs:80:5 + --> $DIR/unused_attributes-must_use.rs:82:5 | LL | #[must_use] | ^^^^^^^^^^^ @@ -115,7 +124,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on associated types - --> $DIR/unused_attributes-must_use.rs:83:5 + --> $DIR/unused_attributes-must_use.rs:85:5 | LL | #[must_use] | ^^^^^^^^^^^ @@ -124,7 +133,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on trait impl blocks - --> $DIR/unused_attributes-must_use.rs:93:1 + --> $DIR/unused_attributes-must_use.rs:95:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -133,7 +142,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on trait methods in impl blocks - --> $DIR/unused_attributes-must_use.rs:98:5 + --> $DIR/unused_attributes-must_use.rs:100:5 | LL | #[must_use] | ^^^^^^^^^^^ @@ -142,7 +151,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to data types, functions, unions, required trait methods, provided trait methods, inherent methods, foreign functions, and traits error: `#[must_use]` attribute cannot be used on trait aliases - --> $DIR/unused_attributes-must_use.rs:105:1 + --> $DIR/unused_attributes-must_use.rs:107:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -151,7 +160,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on macro defs - --> $DIR/unused_attributes-must_use.rs:109:1 + --> $DIR/unused_attributes-must_use.rs:111:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -160,7 +169,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on statements - --> $DIR/unused_attributes-must_use.rs:118:5 + --> $DIR/unused_attributes-must_use.rs:120:5 | LL | #[must_use] | ^^^^^^^^^^^ @@ -169,7 +178,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on closures - --> $DIR/unused_attributes-must_use.rs:123:13 + --> $DIR/unused_attributes-must_use.rs:125:13 | LL | let x = #[must_use] | ^^^^^^^^^^^ @@ -178,7 +187,7 @@ LL | let x = #[must_use] = help: `#[must_use]` can be applied to methods, data types, functions, unions, foreign functions, and traits error: `#[must_use]` attribute cannot be used on match arms - --> $DIR/unused_attributes-must_use.rs:146:9 + --> $DIR/unused_attributes-must_use.rs:148:9 | LL | #[must_use] | ^^^^^^^^^^^ @@ -187,7 +196,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on struct fields - --> $DIR/unused_attributes-must_use.rs:155:28 + --> $DIR/unused_attributes-must_use.rs:157:28 | LL | let s = PatternField { #[must_use] foo: 123 }; | ^^^^^^^^^^^ @@ -196,7 +205,7 @@ LL | let s = PatternField { #[must_use] foo: 123 }; = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on pattern fields - --> $DIR/unused_attributes-must_use.rs:157:24 + --> $DIR/unused_attributes-must_use.rs:159:24 | LL | let PatternField { #[must_use] foo } = s; | ^^^^^^^^^^^ @@ -205,7 +214,7 @@ LL | let PatternField { #[must_use] foo } = s; = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: unused `X` that must be used - --> $DIR/unused_attributes-must_use.rs:128:5 + --> $DIR/unused_attributes-must_use.rs:130:5 | LL | X; | ^ @@ -221,7 +230,7 @@ LL | let _ = X; | +++++++ error: unused `Y` that must be used - --> $DIR/unused_attributes-must_use.rs:129:5 + --> $DIR/unused_attributes-must_use.rs:131:5 | LL | Y::Z; | ^^^^ @@ -232,7 +241,7 @@ LL | let _ = Y::Z; | +++++++ error: unused `U` that must be used - --> $DIR/unused_attributes-must_use.rs:130:5 + --> $DIR/unused_attributes-must_use.rs:132:5 | LL | U { unit: () }; | ^^^^^^^^^^^^^^ @@ -243,7 +252,7 @@ LL | let _ = U { unit: () }; | +++++++ error: unused return value of `U::method` that must be used - --> $DIR/unused_attributes-must_use.rs:131:5 + --> $DIR/unused_attributes-must_use.rs:133:5 | LL | U::method(); | ^^^^^^^^^^^ @@ -254,7 +263,7 @@ LL | let _ = U::method(); | +++++++ error: unused return value of `foo` that must be used - --> $DIR/unused_attributes-must_use.rs:132:5 + --> $DIR/unused_attributes-must_use.rs:134:5 | LL | foo(); | ^^^^^ @@ -265,7 +274,7 @@ LL | let _ = foo(); | +++++++ error: unused return value of `foreign_foo` that must be used - --> $DIR/unused_attributes-must_use.rs:135:9 + --> $DIR/unused_attributes-must_use.rs:137:9 | LL | foreign_foo(); | ^^^^^^^^^^^^^ @@ -276,7 +285,7 @@ LL | let _ = foreign_foo(); | +++++++ error: unused return value of `Use::get_four` that must be used - --> $DIR/unused_attributes-must_use.rs:143:5 + --> $DIR/unused_attributes-must_use.rs:145:5 | LL | ().get_four(); | ^^^^^^^^^^^^^ @@ -286,5 +295,5 @@ help: use `let _ = ...` to ignore the resulting value LL | let _ = ().get_four(); | +++++++ -error: aborting due to 29 previous errors +error: aborting due to 30 previous errors -- cgit 1.4.1-3-g733a5 From 59ceb02d65f13a20d29422f4d923ecde429d4c0c Mon Sep 17 00:00:00 2001 From: Jana Dönszelmann Date: Mon, 11 Aug 2025 11:46:30 +0200 Subject: Port crate name to the new attribute system --- .../src/attributes/crate_level.rs | 33 ++++++ compiler/rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/attributes/util.rs | 6 +- compiler/rustc_attr_parsing/src/context.rs | 8 +- compiler/rustc_attr_parsing/src/lib.rs | 4 +- compiler/rustc_hir/src/attrs/data_structures.rs | 3 + compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 6 + compiler/rustc_interface/src/passes.rs | 28 ++++- compiler/rustc_interface/src/util.rs | 12 +- compiler/rustc_lint/src/nonstandard_style.rs | 52 ++++----- compiler/rustc_passes/src/check_attr.rs | 46 ++++++-- tests/ui/attributes/crate-name-empty.stderr | 4 +- tests/ui/attributes/crate-name-macro-call.rs | 2 +- tests/ui/attributes/crate-name-macro-call.stderr | 8 +- tests/ui/attributes/crate-name-mismatch.stderr | 4 +- tests/ui/attributes/malformed-attrs.stderr | 14 +-- ...rint-crate-name-request-malformed-crate-name.rs | 2 +- ...-crate-name-request-malformed-crate-name.stderr | 8 +- ...ile-names-request-malformed-crate-name-1.stderr | 5 +- ...nt-file-names-request-malformed-crate-name-2.rs | 2 +- ...ile-names-request-malformed-crate-name-2.stderr | 8 +- ...rint-file-names-request-malformed-crate-name.rs | 2 +- ...-file-names-request-malformed-crate-name.stderr | 8 +- tests/ui/lint/unused/unused-attr-duplicate.rs | 8 +- tests/ui/lint/unused/unused-attr-duplicate.stderr | 130 ++++++++++++--------- 25 files changed, 248 insertions(+), 156 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/crate_level.rs (limited to 'compiler') diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs new file mode 100644 index 00000000000..9175d7479e1 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -0,0 +1,33 @@ +use super::prelude::*; + +pub(crate) struct CrateNameParser; + +impl SingleAttributeParser for CrateNameParser { + const PATH: &[Symbol] = &[sym::crate_name]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); + + // FIXME: crate name is allowed on all targets and ignored, + // even though it should only be valid on crates of course + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let ArgParser::NameValue(n) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + let Some(name) = n.value_as_str() else { + cx.expected_string_literal(n.value_span, Some(n.value_as_lit())); + return None; + }; + + Some(AttributeKind::CrateName { + name, + name_span: n.value_span, + attr_span: cx.attr_span, + style: cx.attr_style, + }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index b98678041d7..9dad9c893f0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -35,6 +35,7 @@ pub(crate) mod cfg; pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; pub(crate) mod confusables; +pub(crate) mod crate_level; pub(crate) mod deprecation; pub(crate) mod dummy; pub(crate) mod inline; diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index ef9701cb7cb..77e8c32e59d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -1,5 +1,5 @@ use rustc_ast::LitKind; -use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name}; +use rustc_ast::attr::AttributeExt; use rustc_feature::is_builtin_attr_name; use rustc_hir::RustcVersion; use rustc_span::{Symbol, sym}; @@ -27,10 +27,6 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) } -pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option { - first_attr_value_str_by_name(attrs, sym::crate_name) -} - pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>( attrs: impl Iterator, symbol: Symbol, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index f30edbfaaa1..128ecd67d2a 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -24,6 +24,7 @@ use crate::attributes::codegen_attrs::{ UsedParser, }; use crate::attributes::confusables::ConfusablesParser; +use crate::attributes::crate_level::CrateNameParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -166,6 +167,7 @@ attribute_parsers!( // tidy-alphabetical-start Single, + Single, Single, Single, Single, @@ -310,7 +312,9 @@ pub struct AcceptContext<'f, 'sess, S: Stage> { /// The span of the attribute currently being parsed pub(crate) attr_span: Span, + /// Whether it is an inner or outer attribute pub(crate) attr_style: AttrStyle, + /// The expected structure of the attribute. /// /// Used in reporting errors to give a hint to users what the attribute *should* look like. @@ -683,7 +687,9 @@ impl ShouldEmit { ShouldEmit::ErrorsAndLints => { diag.emit(); } - ShouldEmit::Nothing => {} + ShouldEmit::Nothing => { + diag.cancel(); + } } } } diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 969c24a4f89..4dd908cdc40 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -106,9 +106,7 @@ pub mod validate_attr; pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr}; pub use attributes::cfg_old::*; -pub use attributes::util::{ - find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version, -}; +pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; pub use interface::AttributeParser; pub use lints::emit_attribute_lint; diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 1e73bb6f5fd..09da5772d23 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -367,6 +367,9 @@ pub enum AttributeKind { /// Represents `#[coverage(..)]`. Coverage(Span, CoverageAttrKind), + /// Represents `#[crate_name = ...]` + CrateName { name: Symbol, name_span: Span, attr_span: Span, style: AttrStyle }, + /// Represents `#[custom_mir]`. CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 77c6faa7acd..e5329c104bb 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -7,6 +7,11 @@ pub enum EncodeCrossCrate { } impl AttributeKind { + /// Whether this attribute should be encoded in metadata files. + /// + /// If this is "Yes", then another crate can do `tcx.get_all_attrs(did)` for a did in this crate, and get the attribute. + /// When this is No, the attribute is filtered out while encoding and other crate won't be able to observe it. + /// This can be unexpectedly good for performance, so unless necessary for cross-crate compilation, prefer No. pub fn encode_cross_crate(&self) -> EncodeCrossCrate { use AttributeKind::*; use EncodeCrossCrate::*; @@ -31,6 +36,7 @@ impl AttributeKind { ConstTrait(..) => No, Coroutine(..) => No, Coverage(..) => No, + CrateName { .. } => No, CustomMir(_, _, _) => Yes, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 90f7ae76387..bc5ef04079e 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -6,7 +6,7 @@ use std::sync::{Arc, LazyLock, OnceLock}; use std::{env, fs, iter}; use rustc_ast as ast; -use rustc_attr_parsing::validate_attr; +use rustc_attr_parsing::{AttributeParser, ShouldEmit, validate_attr}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::steal::Steal; @@ -16,6 +16,7 @@ use rustc_errors::timings::TimingSection; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap}; use rustc_hir::definitions::Definitions; use rustc_incremental::setup_dep_graph; @@ -1244,8 +1245,7 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol // in all code paths that require the crate name very early on, namely before // macro expansion. - let attr_crate_name = - validate_and_find_value_str_builtin_attr(sym::crate_name, sess, krate_attrs); + let attr_crate_name = parse_crate_name(sess, krate_attrs, ShouldEmit::EarlyFatal); let validate = |name, span| { rustc_session::output::validate_crate_name(sess, name, span); @@ -1283,6 +1283,28 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol sym::rust_out } +pub(crate) fn parse_crate_name( + sess: &Session, + attrs: &[ast::Attribute], + emit_errors: ShouldEmit, +) -> Option<(Symbol, Span)> { + let rustc_hir::Attribute::Parsed(AttributeKind::CrateName { name, name_span, .. }) = + AttributeParser::parse_limited_should_emit( + sess, + &attrs, + sym::crate_name, + DUMMY_SP, + rustc_ast::node_id::CRATE_NODE_ID, + None, + emit_errors, + )? + else { + unreachable!("crate_name is the only attr we could've parsed here"); + }; + + Some((name, name_span)) +} + fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit { // We don't permit macro calls inside of the attribute (e.g., #![recursion_limit = `expand!()`]) // because that would require expanding this while in the middle of expansion, which needs to diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 9a432a60819..04006f3e446 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -5,7 +5,7 @@ use std::sync::{Arc, OnceLock}; use std::{env, thread}; use rustc_ast as ast; -use rustc_attr_parsing::validate_attr; +use rustc_attr_parsing::{ShouldEmit, validate_attr}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::sync; @@ -24,6 +24,7 @@ use rustc_target::spec::Target; use tracing::info; use crate::errors; +use crate::passes::parse_crate_name; /// Function pointer type that constructs a new CodegenBackend. type MakeBackendFn = fn() -> Box; @@ -520,11 +521,10 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu sess.dcx().emit_fatal(errors::MultipleOutputTypesToStdout); } - let crate_name = sess - .opts - .crate_name - .clone() - .or_else(|| rustc_attr_parsing::find_crate_name(attrs).map(|n| n.to_string())); + let crate_name = + sess.opts.crate_name.clone().or_else(|| { + parse_crate_name(sess, attrs, ShouldEmit::Nothing).map(|i| i.0.to_string()) + }); match sess.io.output_file { None => { diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 8fafaa33d0c..65075cfecfa 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -5,7 +5,7 @@ use rustc_hir::attrs::{AttributeKind, ReprAttr}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{FnKind, Visitor}; -use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind, find_attr}; +use rustc_hir::{Attribute, GenericParamKind, PatExprKind, PatKind, find_attr}; use rustc_middle::hir::nested_filter::All; use rustc_middle::ty; use rustc_session::config::CrateType; @@ -343,35 +343,27 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { Some(Ident::from_str(name)) } else { - ast::attr::find_by_name(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), sym::crate_name).and_then( - |attr| { - if let Attribute::Unparsed(n) = attr - && let AttrItem { args: AttrArgs::Eq { eq_span: _, expr: lit }, .. } = - n.as_ref() - && let ast::LitKind::Str(name, ..) = lit.kind - { - // Discard the double quotes surrounding the literal. - let sp = cx - .sess() - .source_map() - .span_to_snippet(lit.span) - .ok() - .and_then(|snippet| { - let left = snippet.find('"')?; - let right = snippet.rfind('"').map(|pos| snippet.len() - pos)?; - - Some( - lit.span - .with_lo(lit.span.lo() + BytePos(left as u32 + 1)) - .with_hi(lit.span.hi() - BytePos(right as u32)), - ) - }) - .unwrap_or(lit.span); - - Some(Ident::new(name, sp)) - } else { - None - } + find_attr!(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), AttributeKind::CrateName{name, name_span,..} => (name, name_span)).map( + |(&name, &span)| { + // Discard the double quotes surrounding the literal. + let sp = cx + .sess() + .source_map() + .span_to_snippet(span) + .ok() + .and_then(|snippet| { + let left = snippet.find('"')?; + let right = snippet.rfind('"').map(|pos| snippet.len() - pos)?; + + Some( + span + .with_lo(span.lo() + BytePos(left as u32 + 1)) + .with_hi(span.hi() - BytePos(right as u32)), + ) + }) + .unwrap_or(span); + + Ident::new(name, sp) }, ) }; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c610ce4fc85..7aef60b7b91 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -250,7 +250,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::ShouldPanic { .. } | AttributeKind::Coroutine(..) | AttributeKind::Linkage(..) - | AttributeKind::MustUse { .. }, + | AttributeKind::MustUse { .. } + | AttributeKind::CrateName { .. } ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -367,22 +368,49 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); if hir_id != CRATE_HIR_ID { - if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) - { - match style { - Some(ast::AttrStyle::Outer) => self.tcx.emit_node_span_lint( + match attr { + // FIXME(jdonszelmann) move to attribute parsing when validation gets better there + &Attribute::Parsed(AttributeKind::CrateName { + attr_span: span, style, .. + }) => match style { + ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + span, errors::OuterCrateLevelAttr, ), - Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( + ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + span, errors::InnerCrateLevelAttr, ), + }, + Attribute::Parsed(_) => { /* not crate-level */ } + Attribute::Unparsed(attr) => { + // FIXME(jdonszelmann): remove once all crate-level attrs are parsed and caught by + // the above + if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = + attr.path + .segments + .first() + .and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) + { + match attr.style { + ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::OuterCrateLevelAttr, + ), + ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::InnerCrateLevelAttr, + ), + } + } } } } diff --git a/tests/ui/attributes/crate-name-empty.stderr b/tests/ui/attributes/crate-name-empty.stderr index 509a42d05f7..31d9dd0e948 100644 --- a/tests/ui/attributes/crate-name-empty.stderr +++ b/tests/ui/attributes/crate-name-empty.stderr @@ -1,8 +1,8 @@ error: crate name must not be empty - --> $DIR/crate-name-empty.rs:3:1 + --> $DIR/crate-name-empty.rs:3:17 | LL | #![crate_name = ""] - | ^^^^^^^^^^^^^^^^^^^ + | ^^ error: aborting due to 1 previous error diff --git a/tests/ui/attributes/crate-name-macro-call.rs b/tests/ui/attributes/crate-name-macro-call.rs index 1aae2e506e2..61076349cc3 100644 --- a/tests/ui/attributes/crate-name-macro-call.rs +++ b/tests/ui/attributes/crate-name-macro-call.rs @@ -1,6 +1,6 @@ // issue: rust-lang/rust#122001 // Ensure we reject macro calls inside `#![crate_name]` as their result wouldn't get honored anyway. -#![crate_name = concat!("my", "crate")] //~ ERROR malformed `crate_name` attribute input +#![crate_name = concat!("my", "crate")] //~ ERROR attribute value must be a literal fn main() {} diff --git a/tests/ui/attributes/crate-name-macro-call.stderr b/tests/ui/attributes/crate-name-macro-call.stderr index 56827aa11a4..e988b8461d7 100644 --- a/tests/ui/attributes/crate-name-macro-call.stderr +++ b/tests/ui/attributes/crate-name-macro-call.stderr @@ -1,10 +1,8 @@ -error: malformed `crate_name` attribute input - --> $DIR/crate-name-macro-call.rs:4:1 +error: attribute value must be a literal + --> $DIR/crate-name-macro-call.rs:4:17 | LL | #![crate_name = concat!("my", "crate")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]` - | - = note: for more information, visit + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/attributes/crate-name-mismatch.stderr b/tests/ui/attributes/crate-name-mismatch.stderr index 4021fbe7c18..6416ad2d41a 100644 --- a/tests/ui/attributes/crate-name-mismatch.stderr +++ b/tests/ui/attributes/crate-name-mismatch.stderr @@ -1,8 +1,8 @@ error: `--crate-name` and `#[crate_name]` are required to match, but `foo` != `bar` - --> $DIR/crate-name-mismatch.rs:5:1 + --> $DIR/crate-name-mismatch.rs:5:17 | LL | #![crate_name = "bar"] - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 11e01ac29be..69f9a18c179 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -41,14 +41,6 @@ LL | #![windows_subsystem = "console"] LL | #![windows_subsystem = "windows"] | +++++++++++ -error: malformed `crate_name` attribute input - --> $DIR/malformed-attrs.rs:74:1 - | -LL | #[crate_name] - | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` - | - = note: for more information, visit - error: malformed `instruction_set` attribute input --> $DIR/malformed-attrs.rs:106:1 | @@ -478,6 +470,12 @@ LL | #[used()] | = help: `#[used]` can only be applied to statics +error[E0539]: malformed `crate_name` attribute input + --> $DIR/malformed-attrs.rs:74:1 + | +LL | #[crate_name] + | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` + error[E0539]: malformed `target_feature` attribute input --> $DIR/malformed-attrs.rs:79:1 | diff --git a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs index c7f3c2c5403..62f1f6cd09c 100644 --- a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs +++ b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs @@ -2,4 +2,4 @@ // See also . //@ compile-flags: --print=crate-name -#![crate_name = concat!("wrapped")] //~ ERROR malformed `crate_name` attribute input +#![crate_name = concat!("wrapped")] //~ ERROR attribute value must be a literal diff --git a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr index b773f7c97aa..fab38dae78b 100644 --- a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr +++ b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr @@ -1,10 +1,8 @@ -error: malformed `crate_name` attribute input - --> $DIR/print-crate-name-request-malformed-crate-name.rs:5:1 +error: attribute value must be a literal + --> $DIR/print-crate-name-request-malformed-crate-name.rs:5:17 | LL | #![crate_name = concat!("wrapped")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]` - | - = note: for more information, visit + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr index 64e38ed8533..d3e60948e4c 100644 --- a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr +++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr @@ -1,10 +1,9 @@ -error: malformed `crate_name` attribute input +error[E0539]: malformed `crate_name` attribute input --> $DIR/print-file-names-request-malformed-crate-name-1.rs:4:1 | LL | #![crate_name] | ^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]` - | - = note: for more information, visit error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs index 13c9d1e0027..1ac1208ee44 100644 --- a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs +++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs @@ -4,4 +4,4 @@ //@ compile-flags: --print=file-names #![crate_name = "this_one_is_okay"] -#![crate_name = concat!("this_one_is_not")] //~ ERROR malformed `crate_name` attribute input +#![crate_name = concat!("this_one_is_not")] //~ ERROR attribute value must be a literal diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr index e9a5b58e4f9..1571521ff17 100644 --- a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr +++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr @@ -1,10 +1,8 @@ -error: malformed `crate_name` attribute input - --> $DIR/print-file-names-request-malformed-crate-name-2.rs:7:1 +error: attribute value must be a literal + --> $DIR/print-file-names-request-malformed-crate-name-2.rs:7:17 | LL | #![crate_name = concat!("this_one_is_not")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]` - | - = note: for more information, visit + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs index 5fe8bd7945f..6441017c665 100644 --- a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs +++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs @@ -2,4 +2,4 @@ // See also . //@ compile-flags: --print=file-names -#![crate_name = concat!("wrapped")] //~ ERROR malformed `crate_name` attribute input +#![crate_name = concat!("wrapped")] //~ ERROR attribute value must be a literal diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr index e63525c6a5d..155e2e5a3fa 100644 --- a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr +++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr @@ -1,10 +1,8 @@ -error: malformed `crate_name` attribute input - --> $DIR/print-file-names-request-malformed-crate-name.rs:5:1 +error: attribute value must be a literal + --> $DIR/print-file-names-request-malformed-crate-name.rs:5:17 | LL | #![crate_name = concat!("wrapped")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]` - | - = note: for more information, visit + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/lint/unused/unused-attr-duplicate.rs b/tests/ui/lint/unused/unused-attr-duplicate.rs index cfa6c2b4228..a334c49788c 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.rs +++ b/tests/ui/lint/unused/unused-attr-duplicate.rs @@ -11,8 +11,12 @@ // - no_main: extra setup #![deny(unused_attributes)] #![crate_name = "unused_attr_duplicate"] -#![crate_name = "unused_attr_duplicate2"] //~ ERROR unused attribute -//~^ WARN this was previously accepted +#![crate_name = "unused_attr_duplicate2"] +//~^ ERROR unused attribute +//~| WARN this was previously accepted +//~| ERROR unused attribute +//~| WARN this was previously accepted +// FIXME(jdonszelmann) this error is given twice now. I'll look at this in the future #![recursion_limit = "128"] #![recursion_limit = "256"] //~ ERROR unused attribute //~^ WARN this was previously accepted diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 6c44e884ba5..203211d0d56 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -1,14 +1,15 @@ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:33:1 + --> $DIR/unused-attr-duplicate.rs:14:1 | -LL | #[no_link] - | ^^^^^^^^^^ help: remove this attribute +LL | #![crate_name = "unused_attr_duplicate2"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:32:1 + --> $DIR/unused-attr-duplicate.rs:13:1 | -LL | #[no_link] - | ^^^^^^^^^^ +LL | #![crate_name = "unused_attr_duplicate"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! note: the lint level is defined here --> $DIR/unused-attr-duplicate.rs:12:9 | @@ -16,291 +17,304 @@ LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:14:1 + --> $DIR/unused-attr-duplicate.rs:37:1 | -LL | #![crate_name = "unused_attr_duplicate2"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute +LL | #[no_link] + | ^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:13:1 + --> $DIR/unused-attr-duplicate.rs:36:1 | -LL | #![crate_name = "unused_attr_duplicate"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +LL | #[no_link] + | ^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:17:1 + --> $DIR/unused-attr-duplicate.rs:21:1 | LL | #![recursion_limit = "256"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:16:1 + --> $DIR/unused-attr-duplicate.rs:20:1 | LL | #![recursion_limit = "128"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:20:1 + --> $DIR/unused-attr-duplicate.rs:24:1 | LL | #![type_length_limit = "1"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:19:1 + --> $DIR/unused-attr-duplicate.rs:23:1 | LL | #![type_length_limit = "1048576"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:23:1 + --> $DIR/unused-attr-duplicate.rs:27:1 | LL | #![no_std] | ^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:22:1 + --> $DIR/unused-attr-duplicate.rs:26:1 | LL | #![no_std] | ^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:27:1 + --> $DIR/unused-attr-duplicate.rs:31:1 | LL | #![windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:26:1 + --> $DIR/unused-attr-duplicate.rs:30:1 | LL | #![windows_subsystem = "console"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:30:1 + --> $DIR/unused-attr-duplicate.rs:34:1 | LL | #![no_builtins] | ^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:29:1 + --> $DIR/unused-attr-duplicate.rs:33:1 | LL | #![no_builtins] | ^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:40:5 + --> $DIR/unused-attr-duplicate.rs:44:5 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:39:5 + --> $DIR/unused-attr-duplicate.rs:43:5 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:37:1 + --> $DIR/unused-attr-duplicate.rs:41:1 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:36:1 + --> $DIR/unused-attr-duplicate.rs:40:1 | LL | #[macro_use] | ^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:47:1 + --> $DIR/unused-attr-duplicate.rs:51:1 | LL | #[path = "bar.rs"] | ^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:46:1 + --> $DIR/unused-attr-duplicate.rs:50:1 | LL | #[path = "auxiliary/lint_unused_extern_crate.rs"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:53:1 + --> $DIR/unused-attr-duplicate.rs:57:1 | LL | #[ignore = "some text"] | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:52:1 + --> $DIR/unused-attr-duplicate.rs:56:1 | LL | #[ignore] | ^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:55:1 + --> $DIR/unused-attr-duplicate.rs:59:1 | LL | #[should_panic(expected = "values don't match")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:54:1 + --> $DIR/unused-attr-duplicate.rs:58:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:60:1 + --> $DIR/unused-attr-duplicate.rs:64:1 | LL | #[must_use = "some message"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:59:1 + --> $DIR/unused-attr-duplicate.rs:63:1 | LL | #[must_use] | ^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:66:1 + --> $DIR/unused-attr-duplicate.rs:70:1 | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:65:1 + --> $DIR/unused-attr-duplicate.rs:69:1 | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:72:1 + --> $DIR/unused-attr-duplicate.rs:76:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:71:1 + --> $DIR/unused-attr-duplicate.rs:75:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:76:1 + --> $DIR/unused-attr-duplicate.rs:80:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:75:1 + --> $DIR/unused-attr-duplicate.rs:79:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:79:1 + --> $DIR/unused-attr-duplicate.rs:83:1 | LL | #[cold] | ^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:78:1 + --> $DIR/unused-attr-duplicate.rs:82:1 | LL | #[cold] | ^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:81:1 + --> $DIR/unused-attr-duplicate.rs:85:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:80:1 + --> $DIR/unused-attr-duplicate.rs:84:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:88:5 + --> $DIR/unused-attr-duplicate.rs:92:5 | LL | #[link_name = "this_does_not_exist"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:90:5 + --> $DIR/unused-attr-duplicate.rs:94:5 | LL | #[link_name = "rust_dbg_extern_identity_u32"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:94:1 + --> $DIR/unused-attr-duplicate.rs:98:1 | LL | #[export_name = "exported_symbol_name"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:96:1 + --> $DIR/unused-attr-duplicate.rs:100:1 | LL | #[export_name = "exported_symbol_name2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:100:1 + --> $DIR/unused-attr-duplicate.rs:104:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:99:1 + --> $DIR/unused-attr-duplicate.rs:103:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:104:1 + --> $DIR/unused-attr-duplicate.rs:108:1 | LL | #[used] | ^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:103:1 + --> $DIR/unused-attr-duplicate.rs:107:1 | LL | #[used] | ^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:107:1 + --> $DIR/unused-attr-duplicate.rs:111:1 | LL | #[link_section = ".text"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:110:1 + --> $DIR/unused-attr-duplicate.rs:114:1 | LL | #[link_section = ".bss"] | ^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:25:1 + --> $DIR/unused-attr-duplicate.rs:14:1 + | +LL | #![crate_name = "unused_attr_duplicate2"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:13:1 + | +LL | #![crate_name = "unused_attr_duplicate"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:29:1 | LL | #![no_implicit_prelude] | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:24:1 + --> $DIR/unused-attr-duplicate.rs:28:1 | LL | #![no_implicit_prelude] | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 24 previous errors +error: aborting due to 25 previous errors -- cgit 1.4.1-3-g733a5 From 48a4e2d2dde8d68e1d00d3eac07b2c6155f3239d Mon Sep 17 00:00:00 2001 From: Jana Dönszelmann Date: Sat, 23 Aug 2025 19:42:14 +0200 Subject: fix ICE on stable related to attrs on macros --- compiler/rustc_attr_parsing/src/context.rs | 21 ++------------------ compiler/rustc_attr_parsing/src/parser.rs | 20 +++++++++---------- .../concat-in-crate-deprecated-issue-137687.rs | 6 ++++++ .../unused/concat-in-crate-name-issue-137687.rs | 9 +++++++++ .../concat-in-crate-name-issue-137687.stderr | 23 ++++++++++++++++++++++ tests/ui/resolve/path-attr-in-const-block.rs | 1 + tests/ui/resolve/path-attr-in-const-block.stderr | 8 +++++++- 7 files changed, 58 insertions(+), 30 deletions(-) create mode 100644 tests/ui/lint/unused/concat-in-crate-deprecated-issue-137687.rs create mode 100644 tests/ui/lint/unused/concat-in-crate-name-issue-137687.rs create mode 100644 tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr (limited to 'compiler') diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 128ecd67d2a..d4b9cfe00ad 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -265,7 +265,7 @@ impl Stage for Early { sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>, ) -> ErrorGuaranteed { - self.should_emit().emit_err_or_delay(sess.dcx().create_err(diag)) + self.should_emit().emit_err(sess.dcx().create_err(diag)) } fn should_emit(&self) -> ShouldEmit { @@ -667,7 +667,7 @@ pub enum ShouldEmit { } impl ShouldEmit { - pub(crate) fn emit_err_or_delay(&self, diag: Diag<'_>) -> ErrorGuaranteed { + pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed { match self { ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => diag.emit(), ShouldEmit::EarlyFatal => diag.upgrade_to_fatal().emit(), @@ -675,21 +675,4 @@ impl ShouldEmit { ShouldEmit::Nothing => diag.delay_as_bug(), } } - - pub(crate) fn maybe_emit_err(&self, diag: Diag<'_>) { - match self { - ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => { - diag.emit(); - } - ShouldEmit::EarlyFatal => { - diag.upgrade_to_fatal().emit(); - } - ShouldEmit::ErrorsAndLints => { - diag.emit(); - } - ShouldEmit::Nothing => { - diag.cancel(); - } - } - } } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 3ba188938c6..6d3cf684296 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -328,14 +328,14 @@ fn expr_to_lit( match res { Ok(lit) => { if token_lit.suffix.is_some() { - should_emit.emit_err_or_delay( + should_emit.emit_err( psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }), ); None } else { if !lit.kind.is_unsuffixed() { // Emit error and continue, we can still parse the attribute as if the suffix isn't there - should_emit.maybe_emit_err( + should_emit.emit_err( psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }), ); } @@ -355,6 +355,10 @@ fn expr_to_lit( } } } else { + if matches!(should_emit, ShouldEmit::Nothing) { + return None; + } + // Example cases: // - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`. // - `#[foo = include_str!("nonexistent-file.rs")]`: @@ -362,12 +366,8 @@ fn expr_to_lit( // the error because an earlier error will have already // been reported. let msg = "attribute value must be a literal"; - let mut err = psess.dcx().struct_span_err(span, msg); - if let ExprKind::Err(_) = expr.kind { - err.downgrade_to_delayed_bug(); - } - - should_emit.emit_err_or_delay(err); + let err = psess.dcx().struct_span_err(span, msg); + should_emit.emit_err(err); None } } @@ -400,7 +400,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { if !lit.kind.is_unsuffixed() { // Emit error and continue, we can still parse the attribute as if the suffix isn't there - self.should_emit.maybe_emit_err( + self.should_emit.emit_err( self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }), ); } @@ -542,7 +542,7 @@ impl<'a> MetaItemListParser<'a> { ) { Ok(s) => Some(s), Err(e) => { - should_emit.emit_err_or_delay(e); + should_emit.emit_err(e); None } } diff --git a/tests/ui/lint/unused/concat-in-crate-deprecated-issue-137687.rs b/tests/ui/lint/unused/concat-in-crate-deprecated-issue-137687.rs new file mode 100644 index 00000000000..22dd55f4421 --- /dev/null +++ b/tests/ui/lint/unused/concat-in-crate-deprecated-issue-137687.rs @@ -0,0 +1,6 @@ +//@ check-pass +#[deprecated = concat !()] +macro_rules! a { + () => {}; +} +fn main() {} diff --git a/tests/ui/lint/unused/concat-in-crate-name-issue-137687.rs b/tests/ui/lint/unused/concat-in-crate-name-issue-137687.rs new file mode 100644 index 00000000000..37fbf93ffa1 --- /dev/null +++ b/tests/ui/lint/unused/concat-in-crate-name-issue-137687.rs @@ -0,0 +1,9 @@ +#![deny(unused)] + +#[crate_name = concat !()] +//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo] +macro_rules! a { + //~^ ERROR unused macro definition + () => {}; +} +fn main() {} diff --git a/tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr b/tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr new file mode 100644 index 00000000000..4ffb55d493a --- /dev/null +++ b/tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr @@ -0,0 +1,23 @@ +error: unused macro definition: `a` + --> $DIR/concat-in-crate-name-issue-137687.rs:5:14 + | +LL | macro_rules! a { + | ^ + | +note: the lint level is defined here + --> $DIR/concat-in-crate-name-issue-137687.rs:1:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_macros)]` implied by `#[deny(unused)]` + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/concat-in-crate-name-issue-137687.rs:3:1 + | +LL | #[crate_name = concat !()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/resolve/path-attr-in-const-block.rs b/tests/ui/resolve/path-attr-in-const-block.rs index 076511d26d6..0ca356b1ddf 100644 --- a/tests/ui/resolve/path-attr-in-const-block.rs +++ b/tests/ui/resolve/path-attr-in-const-block.rs @@ -5,5 +5,6 @@ fn main() { const { #![path = foo!()] //~^ ERROR: cannot find macro `foo` in this scope + //~| ERROR: attribute value must be a literal } } diff --git a/tests/ui/resolve/path-attr-in-const-block.stderr b/tests/ui/resolve/path-attr-in-const-block.stderr index 8f9e58157c8..19d2745577b 100644 --- a/tests/ui/resolve/path-attr-in-const-block.stderr +++ b/tests/ui/resolve/path-attr-in-const-block.stderr @@ -4,5 +4,11 @@ error: cannot find macro `foo` in this scope LL | #![path = foo!()] | ^^^ -error: aborting due to 1 previous error +error: attribute value must be a literal + --> $DIR/path-attr-in-const-block.rs:6:19 + | +LL | #![path = foo!()] + | ^^^^^^ + +error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From c2b9a8afa9674f473ac78bc0fad76b18c78b7667 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 11 Aug 2025 16:57:40 +0000 Subject: Make sure to treat only param where clauses as inherent --- compiler/rustc_hir_typeck/src/method/probe.rs | 27 +++++++++++++ .../methods/rigid-alias-bound-is-not-inherent-2.rs | 17 ++++++++ .../rigid-alias-bound-is-not-inherent-2.stderr | 17 ++++++++ .../methods/rigid-alias-bound-is-not-inherent-3.rs | 26 ++++++++++++ .../rigid-alias-bound-is-not-inherent-3.stderr | 30 ++++++++++++++ ...igid-alias-bound-is-not-inherent.current.stderr | 30 ++++++++++++++ .../rigid-alias-bound-is-not-inherent.next.stderr | 30 ++++++++++++++ .../methods/rigid-alias-bound-is-not-inherent.rs | 46 ++++++++++++++++++++++ 8 files changed, 223 insertions(+) create mode 100644 tests/ui/methods/rigid-alias-bound-is-not-inherent-2.rs create mode 100644 tests/ui/methods/rigid-alias-bound-is-not-inherent-2.stderr create mode 100644 tests/ui/methods/rigid-alias-bound-is-not-inherent-3.rs create mode 100644 tests/ui/methods/rigid-alias-bound-is-not-inherent-3.stderr create mode 100644 tests/ui/methods/rigid-alias-bound-is-not-inherent.current.stderr create mode 100644 tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr create mode 100644 tests/ui/methods/rigid-alias-bound-is-not-inherent.rs (limited to 'compiler') diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3ca3b56b87e..f5c3ebd8375 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -909,6 +909,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { debug_assert_matches!(param_ty.kind(), ty::Param(_)); let tcx = self.tcx; + + // We use `DeepRejectCtxt` here which may return false positive on where clauses + // with alias self types. We need to later on reject these as inherent candidates + // in `consider_probe`. let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { @@ -1945,6 +1949,29 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ); (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); + + if matches!(probe.kind, WhereClauseCandidate(_)) { + // `WhereClauseCandidate` requires that the self type is a param, + // because it has special behavior with candidate preference as an + // inherent pick. + match ocx.structurally_normalize_ty( + cause, + self.param_env, + trait_ref.self_ty(), + ) { + Ok(ty) => { + if !matches!(ty.kind(), ty::Param(_)) { + debug!("--> not a param ty: {xform_self_ty:?}"); + return ProbeResult::NoMatch; + } + } + Err(errors) => { + debug!("--> cannot relate self-types {:?}", errors); + return ProbeResult::NoMatch; + } + } + } + xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); match ocx.relate(cause, self.param_env, self.variance(), self_ty, xform_self_ty) { diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent-2.rs b/tests/ui/methods/rigid-alias-bound-is-not-inherent-2.rs new file mode 100644 index 00000000000..8363ec1b3fb --- /dev/null +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent-2.rs @@ -0,0 +1,17 @@ +// Regression test for . + +mod module { + pub trait Trait { + fn method(&self); + } +} + +// Note that we do not import Trait +use std::ops::Deref; + +fn foo(x: impl Deref) { + x.method(); + //~^ ERROR no method named `method` found for type parameter +} + +fn main() {} diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent-2.stderr b/tests/ui/methods/rigid-alias-bound-is-not-inherent-2.stderr new file mode 100644 index 00000000000..433cab9cf9e --- /dev/null +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent-2.stderr @@ -0,0 +1,17 @@ +error[E0599]: no method named `method` found for type parameter `impl Deref` in the current scope + --> $DIR/rigid-alias-bound-is-not-inherent-2.rs:13:7 + | +LL | fn foo(x: impl Deref) { + | --------------------------------- method `method` not found for this type parameter +LL | x.method(); + | ^^^^^^ method not found in `impl Deref` + | + = help: items from traits can only be used if the trait is in scope +help: trait `Trait` which provides `method` is implemented but not in scope; perhaps you want to import it + | +LL + use module::Trait; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent-3.rs b/tests/ui/methods/rigid-alias-bound-is-not-inherent-3.rs new file mode 100644 index 00000000000..bb316eed34d --- /dev/null +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent-3.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +trait Trait1 { + fn call_me(&self) {} +} + +impl Trait1 for T {} + +trait Trait2 { + fn call_me(&self) {} +} + +impl Trait2 for T {} + +pub fn foo(x: T) +where + T: Deref, + U: Trait1, +{ + // This should be ambiguous. The fact that there's an inherent where-bound + // candidate for `U` should not impact the candidates for `T` + x.call_me(); + //~^ ERROR multiple applicable items in scope +} + +fn main() {} diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent-3.stderr b/tests/ui/methods/rigid-alias-bound-is-not-inherent-3.stderr new file mode 100644 index 00000000000..466ad4d2abc --- /dev/null +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent-3.stderr @@ -0,0 +1,30 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/rigid-alias-bound-is-not-inherent-3.rs:22:7 + | +LL | x.call_me(); + | ^^^^^^^ multiple `call_me` found + | +note: candidate #1 is defined in an impl of the trait `Trait1` for the type `T` + --> $DIR/rigid-alias-bound-is-not-inherent-3.rs:4:5 + | +LL | fn call_me(&self) {} + | ^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `Trait2` for the type `T` + --> $DIR/rigid-alias-bound-is-not-inherent-3.rs:10:5 + | +LL | fn call_me(&self) {} + | ^^^^^^^^^^^^^^^^^ +help: disambiguate the method for candidate #1 + | +LL - x.call_me(); +LL + Trait1::call_me(&x); + | +help: disambiguate the method for candidate #2 + | +LL - x.call_me(); +LL + Trait2::call_me(&x); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent.current.stderr b/tests/ui/methods/rigid-alias-bound-is-not-inherent.current.stderr new file mode 100644 index 00000000000..4652bf5e3c5 --- /dev/null +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent.current.stderr @@ -0,0 +1,30 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/rigid-alias-bound-is-not-inherent.rs:42:7 + | +LL | x.method(); + | ^^^^^^ multiple `method` found + | +note: candidate #1 is defined in the trait `Trait1` + --> $DIR/rigid-alias-bound-is-not-inherent.rs:21:5 + | +LL | fn method(&self) { + | ^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `Trait2` for the type `T` + --> $DIR/rigid-alias-bound-is-not-inherent.rs:27:5 + | +LL | fn method(&self) { + | ^^^^^^^^^^^^^^^^ +help: disambiguate the method for candidate #1 + | +LL - x.method(); +LL + Trait1::method(&x); + | +help: disambiguate the method for candidate #2 + | +LL - x.method(); +LL + Trait2::method(&x); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr b/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr new file mode 100644 index 00000000000..afacb3a7d52 --- /dev/null +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr @@ -0,0 +1,30 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/rigid-alias-bound-is-not-inherent.rs:42:7 + | +LL | x.method(); + | ^^^^^^ multiple `method` found + | +note: candidate #1 is defined in the trait `Trait1` + --> $DIR/rigid-alias-bound-is-not-inherent.rs:21:5 + | +LL | fn method(&self) { + | ^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in the trait `Trait2` + --> $DIR/rigid-alias-bound-is-not-inherent.rs:27:5 + | +LL | fn method(&self) { + | ^^^^^^^^^^^^^^^^ +help: disambiguate the method for candidate #1 + | +LL - x.method(); +LL + Trait1::method(&x); + | +help: disambiguate the method for candidate #2 + | +LL - x.method(); +LL + Trait2::method(&x); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent.rs b/tests/ui/methods/rigid-alias-bound-is-not-inherent.rs new file mode 100644 index 00000000000..3dd63df3f39 --- /dev/null +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent.rs @@ -0,0 +1,46 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// See the code below. +// +// We were using `DeepRejectCtxt` to ensure that `assemble_inherent_candidates_from_param` +// did not rely on the param-env being eagerly normalized. Since aliases unify with all +// types, this meant that a rigid param-env candidate like `::Target: Trait1` +// would be registered as a "WhereClauseCandidate", which is treated as inherent. Since +// we evaluate these candidates for all self types in the deref chain, this candidate +// would be satisfied for `::Target`, meaning that it would be preferred over +// an "extension" candidate like `::Target: Trait2` even though it holds. +// This is problematic, since it causes ambiguities to be broken somewhat arbitrarily. +// And as a side-effect, it also caused our computation of "used" traits to be miscalculated +// since inherent candidates don't count as an import usage. + +use std::ops::Deref; + +trait Trait1 { + fn method(&self) { + println!("1"); + } +} + +trait Trait2 { + fn method(&self) { + println!("2"); + } +} +impl Trait2 for T {} + +trait Other {} + +fn foo(x: T) +where + T: Deref, + ::Target: Trait1 + Other, +{ + // Make sure that we don't prefer methods from where clauses for rigid aliases, + // just for params. We could revisit this behavior, but it would be a lang change. + x.method(); + //~^ ERROR multiple applicable items in scope +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From baff99c556a22c962c15cfb9f79a0dcb1d467b20 Mon Sep 17 00:00:00 2001 From: Ryan Lee <138088339+minux-lee@users.noreply.github.com> Date: Mon, 25 Aug 2025 15:49:10 +0900 Subject: Remove bug comments from Repeat variant Removed comments related to a bug in Repeat variant. --- compiler/rustc_middle/src/mir/syntax.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 6039a03aa29..3b8def67f92 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1371,12 +1371,7 @@ pub enum Rvalue<'tcx> { /// Creates an array where each element is the value of the operand. /// - /// This is the cause of a bug in the case where the repetition count is zero because the value - /// is not dropped, see [#74836]. - /// /// Corresponds to source code like `[x; 32]`. - /// - /// [#74836]: https://github.com/rust-lang/rust/issues/74836 Repeat(Operand<'tcx>, ty::Const<'tcx>), /// Creates a reference of the indicated kind to the place. -- cgit 1.4.1-3-g733a5