diff --git a/Cargo.lock b/Cargo.lock index 71ae559bd129a..07d4899422242 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3803,7 +3803,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/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs new file mode 100644 index 0000000000000..9175d7479e123 --- /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 b98678041d74b..9dad9c893f0a8 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 ef9701cb7cb81..77e8c32e59d73 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 b9c415e8085f7..26d9e8ab6d117 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}; @@ -23,6 +23,7 @@ use crate::attributes::codegen_attrs::{ NoMangleParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, 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}; @@ -165,6 +166,7 @@ attribute_parsers!( // tidy-alphabetical-start Single, + Single, Single, Single, Single, @@ -261,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(sess.dcx().create_err(diag)) } fn should_emit(&self) -> ShouldEmit { @@ -312,7 +310,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. @@ -331,7 +331,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; @@ -649,8 +649,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, @@ -660,10 +665,12 @@ pub enum ShouldEmit { } impl ShouldEmit { - pub fn should_emit(&self) -> bool { + pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed { 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 => diag.delay_as_bug(), } } } diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index f652d39a7089e..60523c2877c0a 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, @@ -252,7 +272,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/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 969c24a4f89da..4dd908cdc40b1 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_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 7030f28f23c7a..069478e7f0c82 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/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 364f8819d1336..6d3cf684296bc 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( + 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.emit_err( + psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }), + ); } Some(lit) @@ -354,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")]`: @@ -361,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(); - } - - err.emit_unless_delay(!should_emit.should_emit()); + let err = psess.dcx().struct_span_err(span, msg); + should_emit.emit_err(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.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(e); None } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2192e8f8f83f6..72bee0ddfbfe2 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_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index da954cf4ed740..fccb6b171b1c2 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -280,22 +280,110 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { interp_ok(match (a, b) { // Comparisons between integers are always known. (Scalar::Int(a), Scalar::Int(b)) => (a == b) as u8, - // Comparisons of null with an arbitrary scalar can be known if `scalar_may_be_null` - // indicates that the scalar can definitely *not* be null. - (Scalar::Int(int), ptr) | (ptr, Scalar::Int(int)) - if int.is_null() && !self.scalar_may_be_null(ptr)? => - { - 0 + // Comparing a pointer `ptr` with an integer `int` is equivalent to comparing + // `ptr-int` with null, so we can reduce this case to a `scalar_may_be_null` test. + (Scalar::Int(int), Scalar::Ptr(ptr, _)) | (Scalar::Ptr(ptr, _), Scalar::Int(int)) => { + let int = int.to_target_usize(*self.tcx); + // The `wrapping_neg` here may produce a value that is not + // a valid target usize any more... but `wrapping_offset` handles that correctly. + let offset_ptr = ptr.wrapping_offset(Size::from_bytes(int.wrapping_neg()), self); + if !self.scalar_may_be_null(Scalar::from_pointer(offset_ptr, self))? { + // `ptr.wrapping_sub(int)` is definitely not equal to `0`, so `ptr != int` + 0 + } else { + // `ptr.wrapping_sub(int)` could be equal to `0`, but might not be, + // so we cannot know for sure if `ptr == int` or not + 2 + } + } + (Scalar::Ptr(a, _), Scalar::Ptr(b, _)) => { + let (a_prov, a_offset) = a.prov_and_relative_offset(); + let (b_prov, b_offset) = b.prov_and_relative_offset(); + let a_allocid = a_prov.alloc_id(); + let b_allocid = b_prov.alloc_id(); + let a_info = self.get_alloc_info(a_allocid); + let b_info = self.get_alloc_info(b_allocid); + + // Check if the pointers cannot be equal due to alignment + if a_info.align > Align::ONE && b_info.align > Align::ONE { + let min_align = Ord::min(a_info.align.bytes(), b_info.align.bytes()); + let a_residue = a_offset.bytes() % min_align; + let b_residue = b_offset.bytes() % min_align; + if a_residue != b_residue { + // If the two pointers have a different residue modulo their + // common alignment, they cannot be equal. + return interp_ok(0); + } + // The pointers have the same residue modulo their common alignment, + // so they could be equal. Try the other checks. + } + + if let (Some(GlobalAlloc::Static(a_did)), Some(GlobalAlloc::Static(b_did))) = ( + self.tcx.try_get_global_alloc(a_allocid), + self.tcx.try_get_global_alloc(b_allocid), + ) { + if a_allocid == b_allocid { + debug_assert_eq!( + a_did, b_did, + "different static item DefIds had same AllocId? {a_allocid:?} == {b_allocid:?}, {a_did:?} != {b_did:?}" + ); + // Comparing two pointers into the same static. As per + // https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.intro + // a static cannot be duplicated, so if two pointers are into the same + // static, they are equal if and only if their offsets are equal. + (a_offset == b_offset) as u8 + } else { + debug_assert_ne!( + a_did, b_did, + "same static item DefId had two different AllocIds? {a_allocid:?} != {b_allocid:?}, {a_did:?} == {b_did:?}" + ); + // Comparing two pointers into the different statics. + // We can never determine for sure that two pointers into different statics + // are *equal*, but we can know that they are *inequal* if they are both + // strictly in-bounds (i.e. in-bounds and not one-past-the-end) of + // their respective static, as different non-zero-sized statics cannot + // overlap or be deduplicated as per + // https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.intro + // (non-deduplication), and + // https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.storage-disjointness + // (non-overlapping). + if a_offset < a_info.size && b_offset < b_info.size { + 0 + } else { + // Otherwise, conservatively say we don't know. + // There are some cases we could still return `0` for, e.g. + // if the pointers being equal would require their statics to overlap + // one or more bytes, but for simplicity we currently only check + // strictly in-bounds pointers. + 2 + } + } + } else { + // All other cases we conservatively say we don't know. + // + // For comparing statics to non-statics, as per https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.storage-disjointness + // immutable statics can overlap with other kinds of allocations sometimes. + // + // FIXME: We could be more decisive for (non-zero-sized) mutable statics, + // which cannot overlap with other kinds of allocations. + // + // Functions and vtables can be duplicated and deduplicated, so we + // cannot be sure of runtime equality of pointers to the same one, or the + // runtime inequality of pointers to different ones (see e.g. #73722), + // so comparing those should return 2, whether they are the same allocation + // or not. + // + // `GlobalAlloc::TypeId` exists mostly to prevent consteval from comparing + // `TypeId`s, so comparing those should always return 2, whether they are the + // same allocation or not. + // + // FIXME: We could revisit comparing pointers into the same + // `GlobalAlloc::Memory` once https://github.com/rust-lang/rust/issues/128775 + // is fixed (but they can be deduplicated, so comparing pointers into different + // ones should return 2). + 2 + } } - // Other ways of comparing integers and pointers can never be known for sure. - (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => 2, - // FIXME: return a `1` for when both sides are the same pointer, *except* that - // some things (like functions and vtables) do not have stable addresses - // so we need to be careful around them (see e.g. #73722). - // FIXME: return `0` for at least some comparisons where we can reliably - // determine the result of runtime inequality tests at compile-time. - // Examples include comparison of addresses in different static items. - (Scalar::Ptr(..), Scalar::Ptr(..)) => 2, }) } } diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index f37b6fb748fc9..7912b8e6098b3 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/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 43ce886975c0a..96a4ed3218fbf 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. /// diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 38c5716348f3b..71fc54f0d33f0 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_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 2209b18df3fa1..c208f438f4b23 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -366,6 +366,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 485ded3981fc2..0859b5e4ed923 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 90f7ae7638756..bc5ef04079ed4 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 9a432a60819b2..04006f3e446c1 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/messages.ftl b/compiler/rustc_lint/messages.ftl index 940a07c94df87..417e5a97069c3 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 6c50973462684..426500dda4a72 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,48 @@ 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", + style = "verbose" + )] + 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", + style = "verbose" + )] + 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/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 8fafaa33d0c44..65075cfecfa49 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_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index bc1d4587d076e..239c864904163 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. /// diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 49a4733de3b0a..3aed1c8b48b94 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1418,6 +1418,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_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 077afd6dd2371..86d6e77864911 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -247,7 +247,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/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index bb7ffa2a85d8c..96767d054398c 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/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index f5c490ca7cea3..6fc85a83e179e 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -914,6 +914,7 @@ pub const fn dangling() -> *const T { #[must_use] #[stable(feature = "strict_provenance", since = "1.84.0")] #[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] +#[allow(integer_to_ptr_transmutes)] // Expected semantics here. pub const fn without_provenance_mut(addr: usize) -> *mut T { // An int-to-pointer transmute currently has exactly the intended semantics: it creates a // pointer without provenance. Note that this is *not* a stable guarantee about transmute diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ab417b6c72f9b..f0de03c9a2806 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -15,7 +15,7 @@ //! //! If you already know the name of what you are looking for, the fastest way to //! find it is to use the search -//! bar at the top of the page. +//! button at the top of the page. //! //! Otherwise, you may want to jump to one of these useful sections: //! diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index a40e29a772a9c..3231125f7a13a 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -244,7 +244,11 @@ impl T> LazyLock { #[inline] #[stable(feature = "lazy_cell", since = "1.80.0")] pub fn force(this: &LazyLock) -> &T { - this.once.call_once(|| { + this.once.call_once_force(|state| { + if state.is_poisoned() { + panic_poisoned(); + } + // SAFETY: `call_once` only runs this closure once, ever. let data = unsafe { &mut *this.data.get() }; let f = unsafe { ManuallyDrop::take(&mut data.f) }; @@ -257,8 +261,7 @@ impl T> LazyLock { // * the closure was called and initialized `value`. // * the closure was called and panicked, so this point is never reached. // * the closure was not called, but a previous call initialized `value`. - // * the closure was not called because the Once is poisoned, so this point - // is never reached. + // * the closure was not called because the Once is poisoned, which we handled above. // So `value` has definitely been initialized and will not be modified again. unsafe { &*(*this.data.get()).value } } diff --git a/library/std/tests/sync/lazy_lock.rs b/library/std/tests/sync/lazy_lock.rs index 6c14b79f2ce7c..68aeea834b4fa 100644 --- a/library/std/tests/sync/lazy_lock.rs +++ b/library/std/tests/sync/lazy_lock.rs @@ -33,16 +33,6 @@ fn lazy_default() { assert_eq!(CALLED.load(SeqCst), 1); } -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn lazy_poisoning() { - let x: LazyCell = LazyCell::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); - assert!(res.is_err()); - } -} - #[test] #[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn sync_lazy_new() { @@ -123,16 +113,6 @@ fn static_sync_lazy_via_fn() { assert_eq!(xs(), &vec![1, 2, 3]); } -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn sync_lazy_poisoning() { - let x: LazyLock = LazyLock::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(|| x.len()); - assert!(res.is_err()); - } -} - // Check that we can infer `T` from closure's type. #[test] fn lazy_type_inference() { @@ -145,17 +125,6 @@ fn is_sync_send() { assert_traits::>(); } -#[test] -#[should_panic = "has previously been poisoned"] -fn lazy_force_mut_panic() { - let mut lazy = LazyLock::::new(|| panic!()); - panic::catch_unwind(panic::AssertUnwindSafe(|| { - let _ = LazyLock::force_mut(&mut lazy); - })) - .unwrap_err(); - let _ = &*lazy; -} - #[test] fn lazy_force_mut() { let s = "abc".to_owned(); @@ -165,3 +134,56 @@ fn lazy_force_mut() { p.clear(); LazyLock::force_mut(&mut lazy); } + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn lazy_poisoning() { + let x: LazyCell = LazyCell::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); + assert!(res.is_err()); + } +} + +/// Verifies that when a `LazyLock` is poisoned, it panics with the correct error message ("LazyLock +/// instance has previously been poisoned") instead of the underlying `Once` error message. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +#[should_panic(expected = "LazyLock instance has previously been poisoned")] +fn lazy_lock_deref_panic() { + let lazy: LazyLock = LazyLock::new(|| panic!("initialization failed")); + + // First access will panic during initialization. + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let _ = &*lazy; + })); + + // Second access should panic with the poisoned message. + let _ = &*lazy; +} + +#[test] +#[should_panic(expected = "LazyLock instance has previously been poisoned")] +fn lazy_lock_deref_mut_panic() { + let mut lazy: LazyLock = LazyLock::new(|| panic!("initialization failed")); + + // First access will panic during initialization. + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let _ = LazyLock::force_mut(&mut lazy); + })); + + // Second access should panic with the poisoned message. + let _ = &*lazy; +} + +/// Verifies that when the initialization closure panics with a custom message, that message is +/// preserved and not overridden by `LazyLock`. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +#[should_panic(expected = "custom panic message from closure")] +fn lazy_lock_preserves_closure_panic_message() { + let lazy: LazyLock = LazyLock::new(|| panic!("custom panic message from closure")); + + // This should panic with the original message from the closure. + let _ = &*lazy; +} diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml index 04d6469aeaa42..5ff3118960da6 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml @@ -3,8 +3,8 @@ name: rustc-pull on: workflow_dispatch: schedule: - # Run at 04:00 UTC every Monday and Thursday - - cron: '0 4 * * 1,4' + # Run at 04:00 UTC every Monday + - cron: '0 4 * * 1' jobs: pull: diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 6ec700b9b4dc1..a399b5cd77e54 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -6bcdcc73bd11568fd85f5a38b58e1eda054ad1cd +425a9c0a0e365c0b8c6cfd00c2ded83a73bed9a0 diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index 057e4a4cceed3..f3957724967c3 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -74,7 +74,6 @@ You might also find the following sites useful: of the team procedures, active working groups, and the team calendar. - [std-dev-guide] -- a similar guide for developing the standard library. - [The t-compiler zulip][z] -- `#contribute` and `#wg-rustup` on [Discord](https://discord.gg/rust-lang). - The [Rust Internals forum][rif], a place to ask questions and discuss Rust's internals - The [Rust reference][rr], even though it doesn't specifically talk about diff --git a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md index 1b6b87e4c8d50..1693432b90de7 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md @@ -20,7 +20,7 @@ explanations should help users understand why their code cannot be accepted by the compiler. Rust prides itself on helpful error messages and long-form explanations are no exception. However, before error explanations are overhauled[^new-explanations] it is a bit open as to how exactly they should be -written, as always: ask your reviewer or ask around on the Rust Discord or Zulip. +written, as always: ask your reviewer or ask around on the Rust Zulip. [^new-explanations]: See the draft RFC [here][new-explanations-rfc]. diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index 04d2e37732fa9..87e26d3796881 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -11,7 +11,6 @@ quick guide for the most useful things. For more information, [see this chapter on how to build and run the compiler](./building/how-to-build-and-run.md). [internals]: https://internals.rust-lang.org -[rust-discord]: http://discord.gg/rust-lang [rust-zulip]: https://rust-lang.zulipchat.com [coc]: https://www.rust-lang.org/policies/code-of-conduct [walkthrough]: ./walkthrough.md @@ -20,8 +19,7 @@ chapter on how to build and run the compiler](./building/how-to-build-and-run.md ## Asking Questions If you have questions, please make a post on the [Rust Zulip server][rust-zulip] or -[internals.rust-lang.org][internals]. If you are contributing to Rustup, be aware they are not on -Zulip - you can ask questions in `#wg-rustup` [on Discord][rust-discord]. +[internals.rust-lang.org][internals]. See the [list of teams and working groups][governance] and [the Community page][community] on the official website for more resources. @@ -30,19 +28,23 @@ official website for more resources. As a reminder, all contributors are expected to follow our [Code of Conduct][coc]. -The compiler team (or `t-compiler`) usually hangs out in Zulip [in this -"stream"][z]; it will be easiest to get questions answered there. +The compiler team (or `t-compiler`) usually hangs out in Zulip in +[the #t-compiler channel][z-t-compiler]; +questions about how the compiler works can go in [#t-compiler/help][z-help]. -[z]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler +[z-t-compiler]: https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler +[z-help]: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp **Please ask questions!** A lot of people report feeling that they are "wasting -expert time", but nobody on `t-compiler` feels this way. Contributors are +expert's time", but nobody on `t-compiler` feels this way. Contributors are important to us. Also, if you feel comfortable, prefer public topics, as this means others can see the questions and answers, and perhaps even integrate them back into this guide :) +**Tip**: If you're not a native English speaker and feel unsure about writing, try using a translator to help. But avoid using LLM tools that generate long, complex words. In daily teamwork, **simple and clear words** are best for easy understanding. Even small typos or grammar mistakes can make you seem more human, and people connect better with humans. + ### Experts Not all `t-compiler` members are experts on all parts of `rustc`; it's a @@ -162,15 +164,12 @@ incredibly helpful: - [Triaging issues][triage]: categorizing, replicating, and minimizing issues is very helpful to the Rust maintainers. - [Working groups][wg]: there are a bunch of working groups on a wide variety of rust-related things. -- Answer questions in the _Get Help!_ channels on the [Rust Discord - server][rust-discord], on [users.rust-lang.org][users], or on - [StackOverflow][so]. +- Answer questions on [users.rust-lang.org][users], or on [Stack Overflow][so]. - Participate in the [RFC process](https://github.com/rust-lang/rfcs). - Find a [requested community library][community-library], build it, and publish it to [Crates.io](http://crates.io). Easier said than done, but very, very valuable! -[rust-discord]: https://discord.gg/rust-lang [users]: https://users.rust-lang.org/ [so]: http://stackoverflow.com/questions/tagged/rust [community-library]: https://github.com/rust-lang/rfcs/labels/A-community-library diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index 447c6fd454671..8f0511a4548af 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -338,13 +338,13 @@ your fork with `git push --force-with-lease`. ### Keeping things up to date -The above section on [Rebasing](#rebasing) is a specific +The [above section](#rebasing) is a specific guide on rebasing work and dealing with merge conflicts. Here is some general advice about how to keep your local repo up-to-date with upstream changes: Using `git pull upstream master` while on your local master branch regularly -will keep it up-to-date. You will also want to rebase your feature branches +will keep it up-to-date. You will also want to keep your feature branches up-to-date as well. After pulling, you can checkout the feature branches and rebase them: diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs index ec5fb2793f976..b898920baefc2 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs @@ -49,17 +49,7 @@ pub(super) fn check<'tcx>( true }, (ty::Int(_) | ty::Uint(_), ty::RawPtr(_, _)) => { - span_lint_and_then( - cx, - USELESS_TRANSMUTE, - e.span, - "transmute from an integer to a pointer", - |diag| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified); - } - }, - ); + // Handled by the upstream rustc `integer_to_ptr_transmutes` lint true }, _ => false, diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index e968e7a59244d..e7099104f942d 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -4,6 +4,7 @@ dead_code, clippy::borrow_as_ptr, unnecessary_transmutes, + integer_to_ptr_transmutes, clippy::needless_lifetimes, clippy::missing_transmute_annotations )] @@ -60,12 +61,10 @@ fn useless() { //~^ useless_transmute let _: *const usize = std::mem::transmute(5_isize); - //~^ useless_transmute let _ = std::ptr::dangling::(); let _: *const usize = std::mem::transmute(1 + 1usize); - //~^ useless_transmute let _ = (1 + 1_usize) as *const usize; } diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index 79528ec06f1bf..9478db09481a8 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -1,5 +1,5 @@ error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:33:27 + --> tests/ui/transmute.rs:34:27 | LL | let _: *const T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` @@ -8,61 +8,49 @@ LL | let _: *const T = core::mem::transmute(t); = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:36:25 + --> tests/ui/transmute.rs:37:25 | LL | let _: *mut T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:39:27 + --> tests/ui/transmute.rs:40:27 | LL | let _: *const U = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:47:27 + --> tests/ui/transmute.rs:48:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:50:27 + --> tests/ui/transmute.rs:51:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:53:27 + --> tests/ui/transmute.rs:54:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:56:27 + --> tests/ui/transmute.rs:57:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:59:27 + --> tests/ui/transmute.rs:60:27 | LL | let _: Vec = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ -error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:62:31 - | -LL | let _: *const usize = std::mem::transmute(5_isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` - -error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:67:31 - | -LL | let _: *const usize = std::mem::transmute(1 + 1usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` - error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:99:24 + --> tests/ui/transmute.rs:98:24 | LL | let _: Usize = core::mem::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,25 +59,25 @@ LL | let _: Usize = core::mem::transmute(int_const_ptr); = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:102:24 + --> tests/ui/transmute.rs:101:24 | LL | let _: Usize = core::mem::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> tests/ui/transmute.rs:105:31 + --> tests/ui/transmute.rs:104:31 | LL | let _: *const Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> tests/ui/transmute.rs:108:29 + --> tests/ui/transmute.rs:107:29 | LL | let _: *mut Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u8` to a `bool` - --> tests/ui/transmute.rs:115:28 + --> tests/ui/transmute.rs:114:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -98,7 +86,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:122:28 + --> tests/ui/transmute.rs:121:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -107,16 +95,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:125:32 + --> tests/ui/transmute.rs:124:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:128:30 + --> tests/ui/transmute.rs:127:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 18 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed index e7ad2a1cbbcb1..02f67f79e2b19 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -13,9 +13,6 @@ fn main() { // We should see an error message for each transmute, and no error messages for // the casts, since the casts are the recommended fixes. - // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast - let _ptr_i32_transmute = unsafe { usize::MAX as *const i32 }; - //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs index 42a81777a8267..c5e156405ebca 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -13,9 +13,6 @@ fn main() { // We should see an error message for each transmute, and no error messages for // the casts, since the casts are the recommended fixes. - // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast - let _ptr_i32_transmute = unsafe { transmute::(usize::MAX) }; - //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr index 7746f087cc714..f39a64d57eb49 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr @@ -1,14 +1,5 @@ -error: transmute from an integer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:17:39 - | -LL | let _ptr_i32_transmute = unsafe { transmute::(usize::MAX) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `usize::MAX as *const i32` - | - = note: `-D clippy::useless-transmute` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` - error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:22:38 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:19:38 | LL | let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +13,7 @@ LL + let _ptr_i8_transmute = unsafe { ptr_i32.cast::() }; | error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:29:46 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:26:46 | LL | let _ptr_to_unsized_transmute = unsafe { transmute::<*const [i32], *const [u32]>(slice_ptr) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +25,7 @@ LL + let _ptr_to_unsized_transmute = unsafe { slice_ptr as *const [u32] }; | error: transmute from `*const i32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:36:50 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:33:50 | LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, usize>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as usize` @@ -43,40 +34,43 @@ LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, us = help: to override `-D warnings` add `#[allow(clippy::transmutes_expressible_as_ptr_casts)]` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:43:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:40:41 | LL | let _array_ptr_transmute = unsafe { transmute::<&[i32; 4], *const [i32; 4]>(array_ref) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array_ref as *const [i32; 4]` + | + = note: `-D clippy::useless-transmute` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from `fn(usize) -> u8` to `*const usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:52:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:49:41 | LL | let _usize_ptr_transmute = unsafe { transmute:: u8, *const usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as *const usize` error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:57:49 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:54:49 | LL | let _usize_from_fn_ptr_transmute = unsafe { transmute:: u8, usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize` error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:61:36 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:58:36 | LL | let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:73:14 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:70:14 | LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8` error: transmute from `fn()` to `*const u8` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:92:28 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:89:28 | LL | let _x: u8 = unsafe { *std::mem::transmute::(f) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(f as *const u8)` -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs index 2b861e5447b03..7147813c4b6c1 100644 --- a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs +++ b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs @@ -1,3 +1,5 @@ +#![allow(integer_to_ptr_transmutes)] + use std::mem::transmute; #[cfg(target_pointer_width = "32")] diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs index d72f10530d7ab..60cb9a7f6bfb1 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs @@ -1,5 +1,7 @@ //@compile-flags: -Zmiri-permissive-provenance +#![allow(integer_to_ptr_transmutes)] + use std::mem; // This is the example from diff --git a/src/tools/miri/tests/fail/validity/dangling_ref1.rs b/src/tools/miri/tests/fail/validity/dangling_ref1.rs index fc3a9f344638f..57ba1117e765e 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref1.rs +++ b/src/tools/miri/tests/fail/validity/dangling_ref1.rs @@ -1,5 +1,8 @@ // Make sure we catch this even without Stacked Borrows //@compile-flags: -Zmiri-disable-stacked-borrows + +#![allow(integer_to_ptr_transmutes)] + use std::mem; fn main() { diff --git a/src/tools/miri/tests/panic/transmute_fat2.rs b/src/tools/miri/tests/panic/transmute_fat2.rs index e695ff2d57ba5..7441f25d03ea7 100644 --- a/src/tools/miri/tests/panic/transmute_fat2.rs +++ b/src/tools/miri/tests/panic/transmute_fat2.rs @@ -1,3 +1,5 @@ +#![allow(integer_to_ptr_transmutes)] + fn main() { #[cfg(all(target_endian = "little", target_pointer_width = "64"))] let bad = unsafe { std::mem::transmute::(42) }; diff --git a/src/tools/miri/tests/pass/binops.rs b/src/tools/miri/tests/pass/binops.rs index 0aff7acb29d44..fcbe6c85b7b8f 100644 --- a/src/tools/miri/tests/pass/binops.rs +++ b/src/tools/miri/tests/pass/binops.rs @@ -32,6 +32,7 @@ fn test_bool() { assert_eq!(true ^ true, false); } +#[allow(integer_to_ptr_transmutes)] fn test_ptr() { unsafe { let p1: *const u8 = ::std::mem::transmute(0_usize); diff --git a/src/tools/miri/tests/pass/too-large-primval-write-problem.rs b/src/tools/miri/tests/pass/too-large-primval-write-problem.rs index f4c418bd78a99..00882b7ecca6e 100644 --- a/src/tools/miri/tests/pass/too-large-primval-write-problem.rs +++ b/src/tools/miri/tests/pass/too-large-primval-write-problem.rs @@ -7,6 +7,8 @@ // // This is just intended as a regression test to make sure we don't reintroduce this problem. +#![allow(integer_to_ptr_transmutes)] + #[cfg(target_pointer_width = "32")] fn main() { use std::mem::transmute; diff --git a/tests/ui/attributes/crate-name-empty.stderr b/tests/ui/attributes/crate-name-empty.stderr index 509a42d05f711..31d9dd0e9489c 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 1aae2e506e29b..61076349cc3bf 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 56827aa11a45c..e988b8461d770 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 4021fbe7c181f..6416ad2d41a76 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 98ff578918b04..66fec59150682 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 `sanitize` attribute input --> $DIR/malformed-attrs.rs:92:1 | @@ -496,6 +488,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/binop/binops.rs b/tests/ui/binop/binops.rs index 7142190a45b9a..702e9a61345b7 100644 --- a/tests/ui/binop/binops.rs +++ b/tests/ui/binop/binops.rs @@ -35,6 +35,7 @@ fn test_bool() { assert_eq!(true ^ true, false); } +#[allow(integer_to_ptr_transmutes)] fn test_ptr() { unsafe { let p1: *const u8 = ::std::mem::transmute(0_usize); diff --git a/tests/ui/consts/ptr_comparisons.rs b/tests/ui/consts/ptr_comparisons.rs index e142ab3a754a4..0682184e5567c 100644 --- a/tests/ui/consts/ptr_comparisons.rs +++ b/tests/ui/consts/ptr_comparisons.rs @@ -1,43 +1,221 @@ //@ compile-flags: --crate-type=lib //@ check-pass +//@ edition: 2024 +#![feature(const_raw_ptr_comparison)] +#![feature(fn_align)] +// Generally: +// For any `Some` return, `None` would also be valid, unless otherwise noted. +// For any `None` return, only `None` is valid, unless otherwise noted. -#![feature( - core_intrinsics, - const_raw_ptr_comparison, -)] +macro_rules! do_test { + ($a:expr, $b:expr, $expected:pat) => { + const _: () = { + let a: *const _ = $a; + let b: *const _ = $b; + assert!(matches!(<*const u8>::guaranteed_eq(a.cast(), b.cast()), $expected)); + }; + }; +} -const FOO: &usize = &42; +#[repr(align(2))] +struct T(#[allow(unused)] u16); -macro_rules! check { - (eq, $a:expr, $b:expr) => { - pub const _: () = - assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 1); - }; - (ne, $a:expr, $b:expr) => { - pub const _: () = - assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 0); +#[repr(align(2))] +struct AlignedZst; + +static A: T = T(42); +static B: T = T(42); +static mut MUT_STATIC: T = T(42); +static ZST: () = (); +static ALIGNED_ZST: AlignedZst = AlignedZst; +static LARGE_WORD_ALIGNED: [usize; 2] = [0, 1]; +static mut MUT_LARGE_WORD_ALIGNED: [usize; 2] = [0, 1]; + +const FN_PTR: *const () = { + fn foo() {} + unsafe { std::mem::transmute(foo as fn()) } +}; + +const ALIGNED_FN_PTR: *const () = { + #[rustc_align(2)] + fn aligned_foo() {} + unsafe { std::mem::transmute(aligned_foo as fn()) } +}; + +// Only on armv5te-* and armv4t-* +#[cfg(all( + target_arch = "arm", + not(target_feature = "v6"), +))] +const ALIGNED_THUMB_FN_PTR: *const () = { + #[rustc_align(2)] + #[instruction_set(arm::t32)] + fn aligned_thumb_foo() {} + unsafe { std::mem::transmute(aligned_thumb_foo as fn()) } +}; + +trait Trait { + #[allow(unused)] + fn method(&self) -> u8; +} +impl Trait for u32 { + fn method(&self) -> u8 { 1 } +} +impl Trait for i32 { + fn method(&self) -> u8 { 2 } +} + +const VTABLE_PTR_1: *const () = { + let [_data, vtable] = unsafe { + std::mem::transmute::<&dyn Trait, [*const (); 2]>(&42_u32 as &dyn Trait) }; - (!, $a:expr, $b:expr) => { - pub const _: () = - assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 2); + vtable +}; +const VTABLE_PTR_2: *const () = { + let [_data, vtable] = unsafe { + std::mem::transmute::<&dyn Trait, [*const (); 2]>(&42_i32 as &dyn Trait) }; -} + vtable +}; -check!(eq, 0, 0); -check!(ne, 0, 1); -check!(ne, FOO as *const _, 0); -check!(ne, unsafe { (FOO as *const usize).offset(1) }, 0); -check!(ne, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0); +// Cannot be `None`: `is_null` is stable with strong guarantees about integer-valued pointers. +do_test!(0 as *const u8, 0 as *const u8, Some(true)); +do_test!(0 as *const u8, 1 as *const u8, Some(false)); -// We want pointers to be equal to themselves, but aren't checking this yet because -// there are some open questions (e.g. whether function pointers to the same function -// compare equal: they don't necessarily do at runtime). -check!(!, FOO as *const _, FOO as *const _); +// Integer-valued pointers can always be compared. +do_test!(1 as *const u8, 1 as *const u8, Some(true)); +do_test!(1 as *const u8, 2 as *const u8, Some(false)); + +// Cannot be `None`: `static`s' addresses, references, (and within and one-past-the-end of those), +// and `fn` pointers cannot be null, and `is_null` is stable with strong guarantees, and +// `is_null` is implemented using `guaranteed_cmp`. +do_test!(&A, 0 as *const u8, Some(false)); +do_test!((&raw const A).cast::().wrapping_add(1), 0 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_add(1), 0 as *const u8, Some(false)); +do_test!(&ZST, 0 as *const u8, Some(false)); +do_test!(&(), 0 as *const u8, Some(false)); +do_test!(const { &() }, 0 as *const u8, Some(false)); +do_test!(FN_PTR, 0 as *const u8, Some(false)); + +// This pointer is out-of-bounds, but still cannot be equal to 0 because of alignment. +do_test!((&raw const A).cast::().wrapping_add(size_of::() + 1), 0 as *const u8, Some(false)); // aside from 0, these pointers might end up pretty much anywhere. -check!(!, FOO as *const _, 1); // this one could be `ne` by taking into account alignment -check!(!, FOO as *const _, 1024); +do_test!(&A, align_of::() as *const u8, None); +do_test!((&raw const A).wrapping_byte_add(1), (align_of::() + 1) as *const u8, None); + +// except that they must still be aligned +do_test!(&A, 1 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_byte_add(1), align_of::() as *const u8, Some(false)); + +// If `ptr.wrapping_sub(int)` cannot be null (because it is in-bounds or one-past-the-end of +// `ptr`'s allocation, or because it is misaligned from `ptr`'s allocation), then we know that +// `ptr != int`, even if `ptr` itself is out-of-bounds or one-past-the-end of its allocation. +do_test!((&raw const A).wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_byte_add(2), 2 as *const u8, Some(false)); +do_test!((&raw const A).wrapping_byte_add(3), 1 as *const u8, Some(false)); +do_test!((&raw const ZST).wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!(VTABLE_PTR_1.wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!(FN_PTR.wrapping_byte_add(1), 1 as *const u8, Some(false)); +do_test!(&A, size_of::().wrapping_neg() as *const u8, Some(false)); +do_test!(&LARGE_WORD_ALIGNED, size_of::().wrapping_neg() as *const u8, Some(false)); +// (`ptr - int != 0` due to misalignment) +do_test!((&raw const A).wrapping_byte_add(2), 1 as *const u8, Some(false)); +do_test!((&raw const ALIGNED_ZST).wrapping_byte_add(2), 1 as *const u8, Some(false)); // When pointers go out-of-bounds, they *might* become null, so these comparions cannot work. -check!(!, unsafe { (FOO as *const usize).wrapping_add(2) }, 0); -check!(!, unsafe { (FOO as *const usize).wrapping_sub(1) }, 0); +do_test!((&raw const A).wrapping_add(2), 0 as *const u8, None); +do_test!((&raw const A).wrapping_sub(1), 0 as *const u8, None); + +// Statics cannot be duplicated +do_test!(&A, &A, Some(true)); + +// Two non-ZST statics cannot have the same address +do_test!(&A, &B, Some(false)); +do_test!(&A, &raw const MUT_STATIC, Some(false)); + +// One-past-the-end of one static can be equal to the address of another static. +do_test!(&A, (&raw const B).wrapping_add(1), None); + +// Cannot know if ZST static is at the same address with anything non-null (if alignment allows). +do_test!(&A, &ZST, None); +do_test!(&A, &ALIGNED_ZST, None); + +// Unclear if ZST statics can be placed "in the middle of" non-ZST statics. +// For now, we conservatively say they could, and return None here. +do_test!(&ZST, (&raw const A).wrapping_byte_add(1), None); + +// As per https://doc.rust-lang.org/nightly/reference/items/static-items.html#r-items.static.storage-disjointness +// immutable statics are allowed to overlap with const items and promoteds. +do_test!(&A, &T(42), None); +do_test!(&A, const { &T(42) }, None); +do_test!(&A, { const X: T = T(42); &X }, None); + +// These could return Some(false), since only immutable statics can overlap with const items +// and promoteds. +do_test!(&raw const MUT_STATIC, &T(42), None); +do_test!(&raw const MUT_STATIC, const { &T(42) }, None); +do_test!(&raw const MUT_STATIC, { const X: T = T(42); &X }, None); + +// An odd offset from a 2-aligned allocation can never be equal to an even offset from a +// 2-aligned allocation, even if the offsets are out-of-bounds. +do_test!(&A, (&raw const B).wrapping_byte_add(1), Some(false)); +do_test!(&A, (&raw const B).wrapping_byte_add(5), Some(false)); +do_test!(&A, (&raw const ALIGNED_ZST).wrapping_byte_add(1), Some(false)); +do_test!(&ALIGNED_ZST, (&raw const A).wrapping_byte_add(1), Some(false)); +do_test!(&A, (&T(42) as *const T).wrapping_byte_add(1), Some(false)); +do_test!(&A, (const { &T(42) } as *const T).wrapping_byte_add(1), Some(false)); +do_test!(&A, ({ const X: T = T(42); &X } as *const T).wrapping_byte_add(1), Some(false)); + +// We could return `Some(false)` for these, as pointers to different statics can never be equal if +// that would require the statics to overlap, even if the pointers themselves are offset out of +// bounds or one-past-the-end. We currently only check strictly in-bounds pointers when comparing +// pointers to different statics, however. +do_test!((&raw const A).wrapping_add(1), (&raw const B).wrapping_add(1), None); +do_test!( + (&raw const LARGE_WORD_ALIGNED).cast::().wrapping_add(2), + (&raw const MUT_LARGE_WORD_ALIGNED).cast::().wrapping_add(1), + None +); + +// Pointers into the same static are equal if and only if their offset is the same, +// even if either is out-of-bounds. +do_test!(&A, &A, Some(true)); +do_test!(&A, &A.0, Some(true)); +do_test!(&A, (&raw const A).wrapping_byte_add(1), Some(false)); +do_test!(&A, (&raw const A).wrapping_byte_add(2), Some(false)); +do_test!(&A, (&raw const A).wrapping_byte_add(51), Some(false)); +do_test!((&raw const A).wrapping_byte_add(51), (&raw const A).wrapping_byte_add(51), Some(true)); + +// Pointers to the same fn may be unequal, since `fn`s can be duplicated. +do_test!(FN_PTR, FN_PTR, None); +do_test!(ALIGNED_FN_PTR, ALIGNED_FN_PTR, None); + +// Pointers to different fns may be equal, since `fn`s can be deduplicated. +do_test!(FN_PTR, ALIGNED_FN_PTR, None); + +// Pointers to the same vtable may be unequal, since vtables can be duplicated. +do_test!(VTABLE_PTR_1, VTABLE_PTR_1, None); + +// Pointers to different vtables may be equal, since vtables can be deduplicated. +do_test!(VTABLE_PTR_1, VTABLE_PTR_2, None); + +// Function pointers to aligned function allocations are not necessarily actually aligned, +// due to platform-specific semantics. +// See https://github.com/rust-lang/rust/issues/144661 +// FIXME: This could return `Some` on platforms where function pointers' addresses actually +// correspond to function addresses including alignment, or on ARM if t32 function pointers +// have their low bit set for consteval. +do_test!(ALIGNED_FN_PTR, ALIGNED_FN_PTR.wrapping_byte_offset(1), None); +#[cfg(all( + target_arch = "arm", + not(target_feature = "v6"), +))] +do_test!(ALIGNED_THUMB_FN_PTR, ALIGNED_THUMB_FN_PTR.wrapping_byte_offset(1), None); + +// Conservatively say we don't know. +do_test!(FN_PTR, VTABLE_PTR_1, None); +do_test!((&raw const LARGE_WORD_ALIGNED).cast::().wrapping_add(1), VTABLE_PTR_1, None); +do_test!((&raw const MUT_LARGE_WORD_ALIGNED).cast::().wrapping_add(1), VTABLE_PTR_1, None); +do_test!((&raw const LARGE_WORD_ALIGNED).cast::().wrapping_add(1), FN_PTR, None); +do_test!((&raw const MUT_LARGE_WORD_ALIGNED).cast::().wrapping_add(1), FN_PTR, None); 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 c7f3c2c5403d1..62f1f6cd09ce4 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 b773f7c97aa34..fab38dae78b6e 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 64e38ed853329..d3e60948e4c14 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 13c9d1e002739..1ac1208ee4409 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 e9a5b58e4f921..1571521ff17ce 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 5fe8bd7945f4a..6441017c665e7 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 e63525c6a5dbd..155e2e5a3fa49 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/int_to_ptr.fixed b/tests/ui/lint/int_to_ptr.fixed new file mode 100644 index 0000000000000..8f373492e6fb8 --- /dev/null +++ b/tests/ui/lint/int_to_ptr.fixed @@ -0,0 +1,47 @@ +// Checks for the `integer_to_pointer_transmutes` lint + +//@ check-pass +//@ run-rustfix + +#![allow(unused_unsafe)] +#![allow(dead_code)] + +unsafe fn should_lint(a: usize) { + let _ptr: *const u8 = unsafe { std::ptr::with_exposed_provenance::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr: *mut u8 = unsafe { std::ptr::with_exposed_provenance_mut::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static u8 = unsafe { &*std::ptr::with_exposed_provenance::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static mut u8 = unsafe { &mut *std::ptr::with_exposed_provenance_mut::(a) }; + //~^ WARN transmuting an integer to a pointer + + let _ptr = unsafe { std::ptr::with_exposed_provenance::(42usize) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::ptr::with_exposed_provenance::(a + a) }; + //~^ WARN transmuting an integer to a pointer +} + +const unsafe fn should_lintin_const(a: usize) { + let _ptr: *const u8 = unsafe { std::ptr::with_exposed_provenance::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr: *mut u8 = unsafe { std::ptr::with_exposed_provenance_mut::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static u8 = unsafe { &*std::ptr::with_exposed_provenance::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static mut u8 = unsafe { &mut *std::ptr::with_exposed_provenance_mut::(a) }; + //~^ WARN transmuting an integer to a pointer + + let _ptr = unsafe { std::ptr::with_exposed_provenance::(42usize) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::ptr::with_exposed_provenance::(a + a) }; + //~^ WARN transmuting an integer to a pointer +} + +unsafe fn should_not_lint(a: usize) { + let _ptr = unsafe { std::mem::transmute::(0usize) }; // linted by other lints + let _ptr = unsafe { std::mem::transmute::(a) }; // inner type is a ZST + let _ptr = unsafe { std::mem::transmute::(a) }; // omit fn-ptr for now +} + +fn main() {} diff --git a/tests/ui/lint/int_to_ptr.rs b/tests/ui/lint/int_to_ptr.rs new file mode 100644 index 0000000000000..7f60da47b85d8 --- /dev/null +++ b/tests/ui/lint/int_to_ptr.rs @@ -0,0 +1,47 @@ +// Checks for the `integer_to_pointer_transmutes` lint + +//@ check-pass +//@ run-rustfix + +#![allow(unused_unsafe)] +#![allow(dead_code)] + +unsafe fn should_lint(a: usize) { + let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + + let _ptr = unsafe { std::mem::transmute::(42usize) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(a + a) }; + //~^ WARN transmuting an integer to a pointer +} + +const unsafe fn should_lintin_const(a: usize) { + let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ptr: *mut u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + let _ref: &'static mut u8 = unsafe { std::mem::transmute::(a) }; + //~^ WARN transmuting an integer to a pointer + + let _ptr = unsafe { std::mem::transmute::(42usize) }; + //~^ WARN transmuting an integer to a pointer + let _ptr = unsafe { std::mem::transmute::(a + a) }; + //~^ WARN transmuting an integer to a pointer +} + +unsafe fn should_not_lint(a: usize) { + let _ptr = unsafe { std::mem::transmute::(0usize) }; // linted by other lints + let _ptr = unsafe { std::mem::transmute::(a) }; // inner type is a ZST + let _ptr = unsafe { std::mem::transmute::(a) }; // omit fn-ptr for now +} + +fn main() {} diff --git a/tests/ui/lint/int_to_ptr.stderr b/tests/ui/lint/int_to_ptr.stderr new file mode 100644 index 0000000000000..4035bda8fb2cf --- /dev/null +++ b/tests/ui/lint/int_to_ptr.stderr @@ -0,0 +1,207 @@ +warning: transmuting an integer to a pointer creates a pointer without provenance + --> $DIR/int_to_ptr.rs:10:36 + | +LL | let _ptr: *const u8 = unsafe { std::mem::transmute::(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 + = 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) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 + 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 0000000000000..22dd55f442183 --- /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 0000000000000..37fbf93ffa18a --- /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 0000000000000..4ffb55d493aa8 --- /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/lint/unused/unused-attr-duplicate.rs b/tests/ui/lint/unused/unused-attr-duplicate.rs index cfa6c2b4228cd..a334c49788cb2 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 6c44e884ba54f..203211d0d5620 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 diff --git a/tests/ui/lint/unused/unused_attributes-must_use.fixed b/tests/ui/lint/unused/unused_attributes-must_use.fixed index 2e800cbff3f31..6bc63c8ee5be2 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 c41c6c1d706b4..3c0d76e619f3d 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 03baea3a00415..231d799057c87 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 diff --git a/tests/ui/resolve/path-attr-in-const-block.rs b/tests/ui/resolve/path-attr-in-const-block.rs index 076511d26d6d3..0ca356b1ddf0b 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 8f9e58157c809..19d2745577be1 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