diff --git a/.mailmap b/.mailmap index 6c168bbbcb554..c0638de4aeec5 100644 --- a/.mailmap +++ b/.mailmap @@ -9,7 +9,7 @@ Aaron Todd Abhishek Chanda Abhishek Chanda Abhijeet Bhagat Abroskin Alexander -Adolfo Ochagavía +Adolfo Ochagavía Adrian Heine né Lang Adrien Tétar Ahmed Charles @@ -36,6 +36,7 @@ Amanda Stjerna Amanda Stjerna Amanieu d'Antras Amos Onn +Amos Wenger Ana-Maria Mihalache Anatoly Ikorsky Andre Bogus @@ -276,7 +277,8 @@ Irina Popa Ivan Ivaschenko ivan tkachenko J. J. Weber -Jack Huey +Jack Huey +Jack Huey <31162821+jackh726@users.noreply.github.com> Jacob Jacob Hoffman-Andrews Jacob Greenfield @@ -292,6 +294,8 @@ Jakub Adam Wieczorek Jakub Adam Wieczorek Jakub Adam Wieczorek Jakub Adam Wieczorek +Jakub Adam Wieczorek +Jakub Adam Wieczorek Jakub Beránek James [Undefined] James Deng @@ -303,6 +307,7 @@ Jamie Hill-Daniel Jana Dönszelmann Jana Dönszelmann Jana Dönszelmann +Jane Lusby Jan-Erik Rediger Jaro Fietz Jason Fager @@ -313,6 +318,7 @@ Jason Toffaletti Jason Toffaletti Jauhien Piatlicki Jauhien Piatlicki Jay True Jeremy Letang +Jeremy Soller Jeremy Sorensen Jeremy Stucki Jeremy Stucki @@ -336,6 +342,7 @@ John Kåre Alsaker John Kåre Alsaker John Talling John Van Enk +Jon Gjengset Jonas Tepe Jonathan Bailey Jonathan Chan Kwan Yin @@ -424,7 +431,7 @@ Malo Jaffré Manish Goregaokar Mara Bos Marcell Pardavi -Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> +Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Marcus Klaas de Vries Margaret Meyerhofer Marijn Schouten @@ -531,6 +538,7 @@ Oliver Scherer Oliver Scherer Oliver Scherer Oliver Scherer +Onur Özkan Onur Özkan Onur Özkan Ömer Sinan Ağacan @@ -591,6 +599,7 @@ Rusty Blitzerr RustyYato Ruud van Asseldonk Ruud van Asseldonk Ryan Leung +Ryan Levick Ryan Scheel Ryan Sullivant Ryan Wiedemann @@ -686,6 +695,8 @@ Weihang Lo Weihang Lo Wesley Wiser whitequark +Will Crichton +Will Crichton William Ting Wim Looman Wim Looman @@ -695,6 +706,8 @@ Xinye Tao Xuefeng Wu Xuefeng Wu Xuefeng Wu XuefengWu York Xiang +Yoshua Wuyts +Yoshua Wuyts <2467194+yoshuawuyts@users.noreply.github.com> Yotam Ofek Youngsoo Son Youngsuk Kim diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 04fde563b6809..e65688f3532e1 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -714,6 +714,15 @@ impl Pat { } } + /// Strip off all reference patterns (`&`, `&mut`) and return the inner pattern. + pub fn peel_refs(&self) -> &Pat { + let mut current = self; + while let PatKind::Ref(inner, _) = ¤t.kind { + current = inner; + } + current + } + /// Is this a `..` pattern? pub fn is_rest(&self) -> bool { matches!(self.kind, PatKind::Rest) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 47b46cd69d84c..631c2f1be4fd4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -199,14 +199,13 @@ pub fn eval_config_entry( sess: &Session, cfg_entry: &CfgEntry, id: NodeId, - features: Option<&Features>, emit_lints: ShouldEmit, ) -> EvalConfigResult { match cfg_entry { CfgEntry::All(subs, ..) => { let mut all = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, features, emit_lints); + let res = eval_config_entry(sess, sub, id, emit_lints); // We cannot short-circuit because `eval_config_entry` emits some lints if !res.as_bool() { all.get_or_insert(res); @@ -217,7 +216,7 @@ pub fn eval_config_entry( CfgEntry::Any(subs, span) => { let mut any = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, features, emit_lints); + let res = eval_config_entry(sess, sub, id, emit_lints); // We cannot short-circuit because `eval_config_entry` emits some lints if res.as_bool() { any.get_or_insert(res); @@ -229,7 +228,7 @@ pub fn eval_config_entry( }) } CfgEntry::Not(sub, span) => { - if eval_config_entry(sess, sub, id, features, emit_lints).as_bool() { + if eval_config_entry(sess, sub, id, emit_lints).as_bool() { EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } else { EvalConfigResult::True diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d1d0bff8fe06b..46f39ea8f2507 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1046,8 +1046,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - &Rvalue::NullaryOp(NullOp::ContractChecks, _) => {} - &Rvalue::NullaryOp(NullOp::UbChecks, _) => {} + &Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => {} Rvalue::ShallowInitBox(_operand, ty) => { let trait_ref = diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 387399668111e..5ca4fff948788 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -3,7 +3,7 @@ //! current compilation environment. use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrStyle, CRATE_NODE_ID, token}; +use rustc_ast::{AttrStyle, token}; use rustc_attr_parsing as attr; use rustc_attr_parsing::parser::MetaItemOrLitParser; use rustc_attr_parsing::{ @@ -30,7 +30,6 @@ pub(crate) fn expand_cfg( cx.sess, &cfg, cx.current_expansion.lint_node_id, - Some(cx.ecfg.features), ShouldEmit::ErrorsAndLints, ) .as_bool(); @@ -57,7 +56,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: fields.iter(), ) .bytes(), - NullOp::UbChecks => { - let val = fx.tcx.sess.ub_checks(); - let val = CValue::by_val( - fx.bcx.ins().iconst(types::I8, i64::from(val)), - fx.layout_of(fx.tcx.types.bool), - ); - lval.write_cvalue(fx, val); - return; - } - NullOp::ContractChecks => { - let val = fx.tcx.sess.contract_checks(); + NullOp::RuntimeChecks(kind) => { + let val = kind.value(fx.tcx.sess); let val = CValue::by_val( fx.bcx.ins().iconst(types::I8, i64::from(val)), fx.layout_of(fx.tcx.types.bool), diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ce496c7137913..c5724c20b2165 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3036,7 +3036,7 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { Some(ref cfg) => { - eval_config_entry(sess, cfg, CRATE_NODE_ID, None, ShouldEmit::ErrorsAndLints).as_bool() + eval_config_entry(sess, cfg, CRATE_NODE_ID, ShouldEmit::ErrorsAndLints).as_bool() } None => true, } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index e31dc86b926f2..827dc6e167afd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -624,12 +624,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .bytes(); bx.cx().const_usize(val) } - mir::NullOp::UbChecks => { - let val = bx.tcx().sess.ub_checks(); - bx.cx().const_bool(val) - } - mir::NullOp::ContractChecks => { - let val = bx.tcx().sess.contract_checks(); + mir::NullOp::RuntimeChecks(kind) => { + let val = kind.value(bx.tcx().sess); bx.cx().const_bool(val) } }; diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index ca173fe26c2f6..f515f5d751bc6 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -645,10 +645,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Cast(_, _, _) => {} - Rvalue::NullaryOp( - NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks, - _, - ) => {} + Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::RuntimeChecks(_), _) => {} Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(op, operand) => { diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 236c35ec7b96a..753b2dd3b8ea1 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -298,11 +298,11 @@ pub trait Machine<'tcx>: Sized { interp_ok(()) } - /// Determines the result of a `NullaryOp::UbChecks` invocation. - fn ub_checks(_ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool>; - - /// Determines the result of a `NullaryOp::ContractChecks` invocation. - fn contract_checks(_ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool>; + /// Determines the result of a `NullaryOp::RuntimeChecks` invocation. + fn runtime_checks( + _ecx: &InterpCx<'tcx, Self>, + r: mir::RuntimeChecks, + ) -> InterpResult<'tcx, bool>; /// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction. /// You can use this to detect long or endlessly running programs. @@ -681,14 +681,10 @@ pub macro compile_time_machine(<$tcx: lifetime>) { } #[inline(always)] - fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> { - // We can't look at `tcx.sess` here as that can differ across crates, which can lead to - // unsound differences in evaluating the same constant at different instantiation sites. - interp_ok(true) - } - - #[inline(always)] - fn contract_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> { + fn runtime_checks( + _ecx: &InterpCx<$tcx, Self>, + _r: mir::RuntimeChecks, + ) -> InterpResult<$tcx, bool> { // We can't look at `tcx.sess` here as that can differ across crates, which can lead to // unsound differences in evaluating the same constant at different instantiation sites. interp_ok(true) diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 58b90abf01295..feba237692090 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -522,8 +522,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.tcx.offset_of_subfield(self.typing_env, layout, fields.iter()).bytes(); ImmTy::from_uint(val, usize_layout()) } - UbChecks => ImmTy::from_bool(M::ub_checks(self)?, *self.tcx), - ContractChecks => ImmTy::from_bool(M::contract_checks(self)?, *self.tcx), + RuntimeChecks(r) => ImmTy::from_bool(M::runtime_checks(self, r)?, *self.tcx), }) } } diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs index 9aafc7efd8a6a..0fab4b288d18f 100644 --- a/compiler/rustc_const_eval/src/util/alignment.rs +++ b/compiler/rustc_const_eval/src/util/alignment.rs @@ -1,24 +1,24 @@ use rustc_abi::Align; use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, TyCtxt}; use tracing::debug; -/// Returns `true` if this place is allowed to be less aligned -/// than its containing struct (because it is within a packed -/// struct). -pub fn is_disaligned<'tcx, L>( +/// If the place may be less aligned than its type requires +/// (because it is in a packed type), returns the AdtDef +/// and packed alignment of its most-unaligned projection. +pub fn place_unalignment<'tcx, L>( tcx: TyCtxt<'tcx>, local_decls: &L, typing_env: ty::TypingEnv<'tcx>, place: Place<'tcx>, -) -> bool +) -> Option<(AdtDef<'tcx>, Align)> where L: HasLocalDecls<'tcx>, { - debug!("is_disaligned({:?})", place); - let Some(pack) = is_within_packed(tcx, local_decls, place) else { - debug!("is_disaligned({:?}) - not within packed", place); - return false; + debug!("unalignment({:?})", place); + let Some((descr, pack)) = most_packed_projection(tcx, local_decls, place) else { + debug!("unalignment({:?}) - not within packed", place); + return None; }; let ty = place.ty(local_decls, tcx).ty; @@ -30,31 +30,34 @@ where || matches!(unsized_tail().kind(), ty::Slice(..) | ty::Str)) => { // If the packed alignment is greater or equal to the field alignment, the type won't be - // further disaligned. + // further unaligned. // However we need to ensure the field is sized; for unsized fields, `layout.align` is // just an approximation -- except when the unsized tail is a slice, where the alignment // is fully determined by the type. debug!( - "is_disaligned({:?}) - align = {}, packed = {}; not disaligned", + "unalignment({:?}) - align = {}, packed = {}; not unaligned", place, layout.align.bytes(), pack.bytes() ); - false + None } _ => { - // We cannot figure out the layout. Conservatively assume that this is disaligned. - debug!("is_disaligned({:?}) - true", place); - true + // We cannot figure out the layout. Conservatively assume that this is unaligned. + debug!("unalignment({:?}) - unaligned", place); + Some((descr, pack)) } } } -pub fn is_within_packed<'tcx, L>( +/// If the place includes a projection from a packed struct, +/// returns the AdtDef and packed alignment of the projection +/// with the lowest pack +pub fn most_packed_projection<'tcx, L>( tcx: TyCtxt<'tcx>, local_decls: &L, place: Place<'tcx>, -) -> Option +) -> Option<(AdtDef<'tcx>, Align)> where L: HasLocalDecls<'tcx>, { @@ -65,9 +68,11 @@ where .take_while(|(_base, elem)| !matches!(elem, ProjectionElem::Deref)) // Consider the packed alignments at play here... .filter_map(|(base, _elem)| { - base.ty(local_decls, tcx).ty.ty_adt_def().and_then(|adt| adt.repr().pack) + let adt = base.ty(local_decls, tcx).ty.ty_adt_def()?; + let pack = adt.repr().pack?; + Some((adt, pack)) }) // ... and compute their minimum. // The overall smallest alignment is what matters. - .min() + .min_by_key(|(_, align)| *align) } diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 5be5ee8d1ae97..39992123882a9 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -6,7 +6,7 @@ mod check_validity_requirement; mod compare_types; mod type_name; -pub use self::alignment::{is_disaligned, is_within_packed}; +pub use self::alignment::{most_packed_projection, place_unalignment}; pub use self::check_validity_requirement::check_validity_requirement; pub(crate) use self::check_validity_requirement::validate_scalar_in_layout; pub use self::compare_types::{relate_types, sub_types}; diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 8278c29570b75..e93d9702774e1 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -322,7 +322,6 @@ impl<'a> StripUnconfigured<'a> { self.sess, &cfg_predicate, ast::CRATE_NODE_ID, - self.features, ShouldEmit::ErrorsAndLints, ) .as_bool() @@ -443,7 +442,7 @@ impl<'a> StripUnconfigured<'a> { return EvalConfigResult::True; }; - eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features, emit_errors) + eval_config_entry(self.sess, &cfg, self.lint_node_id, emit_errors) } /// If attributes are not allowed on expressions, emit an error for `attr` diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index a8e8830db99d7..d87a154b0f1bb 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -163,6 +163,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::minnumf128 | sym::mul_with_overflow | sym::needs_drop + | sym::overflow_checks | sym::powf16 | sym::powf32 | sym::powf64 @@ -643,7 +644,7 @@ pub(crate) fn check_intrinsic_type( sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)), sym::ptr_metadata => (2, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), - sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool), + sym::ub_checks | sym::overflow_checks => (0, 0, Vec::new(), tcx.types.bool), sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))), diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 4895e61069e52..f3e6db6f2d8e4 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1022,7 +1022,8 @@ declare_lint! { /// /// - Passing `Ordering::Release` or `Ordering::AcqRel` as the failure /// ordering for any of `AtomicType::compare_exchange`, - /// `AtomicType::compare_exchange_weak`, or `AtomicType::fetch_update`. + /// `AtomicType::compare_exchange_weak`, `AtomicType::update`, or + /// `AtomicType::try_update`. INVALID_ATOMIC_ORDERING, Deny, "usage of invalid atomic ordering in atomic operations and memory fences" @@ -1118,13 +1119,19 @@ impl InvalidAtomicOrdering { let Some((method, args)) = Self::inherent_atomic_method_call( cx, expr, - &[sym::fetch_update, sym::compare_exchange, sym::compare_exchange_weak], + &[ + sym::update, + sym::try_update, + sym::fetch_update, + sym::compare_exchange, + sym::compare_exchange_weak, + ], ) else { return; }; let fail_order_arg = match method { - sym::fetch_update => &args[1], + sym::update | sym::try_update | sym::fetch_update => &args[1], sym::compare_exchange | sym::compare_exchange_weak => &args[3], _ => return, }; diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 2d2eedd2ba5a0..291f5c65dfa27 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -189,7 +189,7 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { Some(ref cfg) => { - eval_config_entry(sess, cfg, CRATE_NODE_ID, None, ShouldEmit::ErrorsAndLints).as_bool() + eval_config_entry(sess, cfg, CRATE_NODE_ID, ShouldEmit::ErrorsAndLints).as_bool() } None => true, } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index fab04df500a5c..802adceb063ea 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -649,7 +649,9 @@ impl<'tcx> Body<'tcx> { } match rvalue { - Rvalue::NullaryOp(NullOp::UbChecks, _) => Some((tcx.sess.ub_checks() as u128, targets)), + Rvalue::NullaryOp(NullOp::RuntimeChecks(kind), _) => { + Some((kind.value(tcx.sess) as u128, targets)) + } Rvalue::Use(Operand::Constant(constant)) => { let bits = eval_mono_const(constant)?; Some((bits, targets)) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 929513c0dced5..e31b110ab2650 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1101,8 +1101,13 @@ impl<'tcx> Debug for Rvalue<'tcx> { let t = with_no_trimmed_paths!(format!("{}", t)); match op { NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"), - NullOp::UbChecks => write!(fmt, "UbChecks()"), - NullOp::ContractChecks => write!(fmt, "ContractChecks()"), + NullOp::RuntimeChecks(RuntimeChecks::UbChecks) => write!(fmt, "UbChecks()"), + NullOp::RuntimeChecks(RuntimeChecks::ContractChecks) => { + write!(fmt, "ContractChecks()") + } + NullOp::RuntimeChecks(RuntimeChecks::OverflowChecks) => { + write!(fmt, "OverflowChecks()") + } } } ThreadLocalRef(did) => ty::tls::with(|tcx| { diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 3cbb4b70b062a..a1f5ffb0b2774 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -795,8 +795,7 @@ impl<'tcx> Rvalue<'tcx> { } Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => tcx.types.usize, - Rvalue::NullaryOp(NullOp::ContractChecks, _) - | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool, + Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => tcx.types.bool, Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64), AggregateKind::Tuple => { @@ -864,7 +863,7 @@ impl<'tcx> NullOp<'tcx> { pub fn ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self { NullOp::OffsetOf(_) => tcx.types.usize, - NullOp::UbChecks | NullOp::ContractChecks => tcx.types.bool, + NullOp::RuntimeChecks(_) => tcx.types.bool, } } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 9d99239546ae2..3b48a68df1262 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1565,12 +1565,31 @@ pub enum AggregateKind<'tcx> { pub enum NullOp<'tcx> { /// Returns the offset of a field OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>), + /// Returns whether we should perform some checking at runtime. + RuntimeChecks(RuntimeChecks), +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum RuntimeChecks { /// Returns whether we should perform some UB-checking at runtime. /// See the `ub_checks` intrinsic docs for details. UbChecks, /// Returns whether we should perform contract-checking at runtime. /// See the `contract_checks` intrinsic docs for details. ContractChecks, + /// Returns whether we should perform some overflow-checking at runtime. + /// See the `overflow_checks` intrinsic docs for details. + OverflowChecks, +} + +impl RuntimeChecks { + pub fn value(self, sess: &rustc_session::Session) -> bool { + match self { + Self::UbChecks => sess.ub_checks(), + Self::ContractChecks => sess.contract_checks(), + Self::OverflowChecks => sess.overflow_checks(), + } + } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 9308570d89d18..7f6c7376501fa 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -293,9 +293,9 @@ pub fn reverse_postorder<'a, 'tcx>( /// reachable. /// /// Such a traversal is mostly useful because it lets us skip lowering the `false` side -/// of `if ::CONST`, as well as [`NullOp::UbChecks`]. +/// of `if ::CONST`, as well as [`NullOp::RuntimeChecks`]. /// -/// [`NullOp::UbChecks`]: rustc_middle::mir::NullOp::UbChecks +/// [`NullOp::RuntimeChecks`]: rustc_middle::mir::NullOp::RuntimeChecks pub fn mono_reachable<'a, 'tcx>( body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index dd65f0699e97e..b4ffeb782b596 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -451,10 +451,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { Rvalue::Ref(..) | Rvalue::RawPtr(..) | Rvalue::Discriminant(..) - | Rvalue::NullaryOp( - NullOp::OffsetOf(..) | NullOp::UbChecks | NullOp::ContractChecks, - _, - ) => {} + | Rvalue::NullaryOp(NullOp::OffsetOf(..) | NullOp::RuntimeChecks(_), _) => {} } } diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index 71ec2db1ef00c..cfc9b8edf7a28 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -69,8 +69,11 @@ mir_transform_tail_expr_local = {$is_generated_name -> *[false] `{$name}` calls a custom destructor } -mir_transform_unaligned_packed_ref = reference to packed field is unaligned - .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses +mir_transform_unaligned_packed_ref = reference to field of packed {$ty_descr} is unaligned + .note = this {$ty_descr} is {$align -> + [one] {""} + *[other] {"at most "} + }{$align}-byte aligned, but the type of this field may require higher alignment .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index 7ae2ebaf4ff09..9950a94d722eb 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -51,7 +51,7 @@ impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops { match terminator.kind { TerminatorKind::Drop { place, .. } - if util::is_disaligned(tcx, body, typing_env, place) => + if util::place_unalignment(tcx, body, typing_env, place).is_some() => { add_move_for_packed_drop( tcx, diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 100104e9de03e..9ce244a00fcec 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -37,7 +37,9 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { } fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { - if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.typing_env, *place) + if context.is_borrow() + && let Some((adt, pack)) = + util::place_unalignment(self.tcx, self.body, self.typing_env, *place) { let def_id = self.body.source.instance.def_id(); if let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(def_id) @@ -48,7 +50,11 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { // shouldn't do. span_bug!(self.source_info.span, "builtin derive created an unaligned reference"); } else { - self.tcx.dcx().emit_err(errors::UnalignedPackedRef { span: self.source_info.span }); + self.tcx.dcx().emit_err(errors::UnalignedPackedRef { + span: self.source_info.span, + ty_descr: adt.descr(), + align: pack.bytes(), + }); } } } diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index 00a8293966b04..1a9af0e22bbe2 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -75,7 +75,8 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, _location: Location) { match rvalue { - Rvalue::NullaryOp(NullOp::UbChecks, ..) + // FIXME: Should we do the same for `OverflowChecks`? + Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks), ..) if !self .tcx .sess diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 732c3dcd44ab8..63ee69322eef0 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -23,7 +23,7 @@ use rustc_mir_dataflow::impls::{ }; use crate::simplify::UsedInStmtLocals; -use crate::util::is_within_packed; +use crate::util::most_packed_projection; /// Performs the optimization on the body /// @@ -65,7 +65,7 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { // the move may be codegened as a pointer to that field. // Using that disaligned pointer may trigger UB in the callee, // so do nothing. - && is_within_packed(tcx, body, place).is_none() + && most_packed_projection(tcx, body, place).is_none() { call_operands_to_move.push((bb, index)); } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index a039851681a67..517e4dd692625 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -99,6 +99,8 @@ pub(crate) enum ConstMutate { pub(crate) struct UnalignedPackedRef { #[primary_span] pub span: Span, + pub ty_descr: &'static str, + pub align: u64, } #[derive(Diagnostic)] diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 48663c4a52f61..a20e04371b987 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -675,8 +675,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { .tcx .offset_of_subfield(self.typing_env(), arg_layout, fields.iter()) .bytes(), - NullOp::UbChecks => return None, - NullOp::ContractChecks => return None, + NullOp::RuntimeChecks(_) => return None, }; ImmTy::from_uint(val, ty).into() } diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 932744e4fa25c..51e18516534ad 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -169,7 +169,10 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } fn simplify_ub_check(&self, rvalue: &mut Rvalue<'tcx>) { - let Rvalue::NullaryOp(NullOp::UbChecks, _) = *rvalue else { return }; + // FIXME: Should we do the same for overflow checks? + let Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks), _) = *rvalue else { + return; + }; let const_ = Const::from_bool(self.tcx, self.tcx.sess.ub_checks()); let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None }; diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 131e3943689b8..dab2267eea690 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -612,8 +612,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { .tcx .offset_of_subfield(self.typing_env, op_layout, fields.iter()) .bytes(), - NullOp::UbChecks => return None, - NullOp::ContractChecks => return None, + NullOp::RuntimeChecks(_) => return None, }; ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() } diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index ad7c52064a8ef..1e874300e25ea 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -23,13 +23,19 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { sym::unreachable => { terminator.kind = TerminatorKind::Unreachable; } - sym::ub_checks => { + sym::ub_checks | sym::overflow_checks | sym::contract_checks => { + let op = match intrinsic.name { + sym::ub_checks => RuntimeChecks::UbChecks, + sym::contract_checks => RuntimeChecks::ContractChecks, + sym::overflow_checks => RuntimeChecks::OverflowChecks, + _ => unreachable!(), + }; let target = target.unwrap(); block.statements.push(Statement::new( terminator.source_info, StatementKind::Assign(Box::new(( *destination, - Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool), + Rvalue::NullaryOp(NullOp::RuntimeChecks(op), tcx.types.bool), ))), )); terminator.kind = TerminatorKind::Goto { target }; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 9204c221515c9..da5814c6b4cce 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -451,8 +451,7 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::NullaryOp(op, _) => match op { NullOp::OffsetOf(_) => {} - NullOp::UbChecks => {} - NullOp::ContractChecks => {} + NullOp::RuntimeChecks(_) => {} }, Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable), diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 5a9018a62c574..1f0490a120152 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -20,7 +20,7 @@ use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::debuginfo::debuginfo_locals; use rustc_trait_selection::traits::ObligationCtxt; -use crate::util::{self, is_within_packed}; +use crate::util::{self, most_packed_projection}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum EdgeKind { @@ -409,7 +409,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { // The call destination place and Operand::Move place used as an argument might // be passed by a reference to the callee. Consequently they cannot be packed. - if is_within_packed(self.tcx, &self.body.local_decls, destination).is_some() { + if most_packed_projection(self.tcx, &self.body.local_decls, destination) + .is_some() + { // This is bad! The callee will expect the memory to be aligned. self.fail( location, @@ -423,7 +425,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { for arg in args { if let Operand::Move(place) = &arg.node { - if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() { + if most_packed_projection(self.tcx, &self.body.local_decls, *place) + .is_some() + { // This is bad! The callee will expect the memory to be aligned. self.fail( location, @@ -1478,7 +1482,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Repeat(_, _) | Rvalue::ThreadLocalRef(_) | Rvalue::RawPtr(_, _) - | Rvalue::NullaryOp(NullOp::UbChecks | NullOp::ContractChecks, _) + | Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) | Rvalue::Discriminant(_) => {} Rvalue::WrapUnsafeBinder(op, ty) => { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c36cd610c6a59..bc08faabece47 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2,13 +2,12 @@ use std::mem::take; use std::ops::{Deref, DerefMut}; use ast::token::IdentIsRaw; -use rustc_ast as ast; use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ - AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block, - BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind, - Path, PathSegment, QSelf, Recovered, Ty, TyKind, + self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, + Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, + PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -2302,6 +2301,38 @@ impl<'a> Parser<'a> { pat.span.shrink_to_hi(), pat.span.shrink_to_lo(), ), + PatKind::Ref(ref inner_pat, _) + // Fix suggestions for multi-reference `self` parameters (e.g. `&&&self`) + // cc: https://github.com/rust-lang/rust/pull/146305 + if let PatKind::Ref(_, _) = &inner_pat.kind + && let PatKind::Path(_, path) = &pat.peel_refs().kind + && let [a, ..] = path.segments.as_slice() + && a.ident.name == kw::SelfLower => + { + let mut inner = inner_pat; + let mut span_vec = vec![pat.span]; + + while let PatKind::Ref(ref inner_type, _) = inner.kind { + inner = inner_type; + span_vec.push(inner.span.shrink_to_lo()); + } + + let span = match span_vec.len() { + // Should be unreachable: match guard ensures at least 2 references + 0 | 1 => unreachable!(), + 2 => span_vec[0].until(inner_pat.span.shrink_to_lo()), + _ => span_vec[0].until(span_vec[span_vec.len() - 2].shrink_to_lo()), + }; + + err.span_suggestion_verbose( + span, + "`self` should be `self`, `&self` or `&mut self`, consider removing extra references", + "".to_string(), + Applicability::MachineApplicable, + ); + + return None; + } // Also catches `fn foo(&a)`. PatKind::Ref(ref inner_pat, mutab) if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind => diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 55a279f7ee0cc..39d8a1dd9e2df 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -82,25 +82,24 @@ enum AllowCVariadic { No, } -/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT`, -/// `IDENT<::AssocTy>`. +/// Determine if the given token can begin a bound assuming it follows Rust 2015 identifier `dyn`. /// -/// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes -/// that `IDENT` is not the ident of a fn trait. -fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { - t == &token::PathSep || t == &token::Lt || t == &token::Shl -} +/// In Rust 2015, `dyn` is a contextual keyword, not a full one. +fn can_begin_dyn_bound_in_edition_2015(t: Token) -> bool { + if t.is_path_start() { + // In `dyn::x`, `dyn` and `dyn<::Y>`, `dyn` should (continue to) denote a regular path + // segment for backward compatibility. We make an exception for `dyn(X)` which used to be + // interpreted as a path with parenthesized generic arguments which can be semantically + // well-formed (consider: `use std::ops::Fn as dyn;`). Instead, we treat it as a trait + // object type whose first bound is parenthesized. + return t != token::PathSep && t != token::Lt && t != token::Shl; + } -fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { - // `!`, `const`, `[`, `async` are deliberately not part of this list to - // contain the number of potential regressions esp. in MBE code. - // `const` and `[` would regress UI test `macro-dyn-const-2015.rs`. - // `!` would regress `dyn!(...)` macro calls in Rust 2015. - t.is_path_start() - || t.is_lifetime() - || t == &TokenKind::Question - || t.is_keyword(kw::For) - || t == &TokenKind::OpenParen + // Contrary to `Parser::can_begin_bound`, `!`, `const`, `[` and `async` are deliberately not + // part of this list to contain the number of potential regressions esp. in MBE code. + // `const` and `[` would regress UI test `macro-dyn-const-2015.rs` and + // `!` would regress `dyn!(...)` macro calls in Rust 2015 for example. + t == token::OpenParen || t == token::Question || t.is_lifetime() || t.is_keyword(kw::For) } impl<'a> Parser<'a> { @@ -687,7 +686,6 @@ impl<'a> Parser<'a> { let mut err = self.dcx().struct_span_err(span, format!("expected `;` or `]`, found {}", token_descr)); err.span_label(span, "expected `;` or `]`"); - err.note("you might have meant to write a slice or array type"); // If we cannot recover, return the error immediately. if !self.may_recover() { @@ -696,12 +694,10 @@ impl<'a> Parser<'a> { let snapshot = self.create_snapshot_for_diagnostic(); - let suggestion_span = if self.eat(exp!(Comma)) || self.eat(exp!(Star)) { - // Consume common erroneous separators. - self.prev_token.span - } else { - self.token.span.shrink_to_lo() - }; + // Consume common erroneous separators. + let hi = self.prev_token.span.hi(); + _ = self.eat(exp!(Comma)) || self.eat(exp!(Colon)) || self.eat(exp!(Star)); + let suggestion_span = self.prev_token.span.with_lo(hi); // we first try to parse pattern like `[u8 5]` let length = match self.parse_expr_anon_const() { @@ -969,10 +965,7 @@ impl<'a> Parser<'a> { fn is_explicit_dyn_type(&mut self) -> bool { self.check_keyword(exp!(Dyn)) && (self.token_uninterpolated_span().at_least_rust_2018() - || self.look_ahead(1, |t| { - (can_begin_dyn_bound_in_edition_2015(t) || *t == TokenKind::Star) - && !can_continue_type_after_non_fn_ident(t) - })) + || self.look_ahead(1, |&t| can_begin_dyn_bound_in_edition_2015(t))) } /// Parses a `dyn B0 + ... + Bn` type. @@ -981,13 +974,11 @@ impl<'a> Parser<'a> { fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { self.bump(); // `dyn` - // We used to parse `*` for `dyn*` here. - let syntax = TraitObjectSyntax::Dyn; - // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds()?; *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus; - Ok(TyKind::TraitObject(bounds, syntax)) + + Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)) } /// Parses a type starting with a path. diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index 1a939cbe8dba2..5f41b1063280e 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -642,8 +642,7 @@ impl Rvalue { .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}")) } Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => Ok(Ty::usize_ty()), - Rvalue::NullaryOp(NullOp::ContractChecks, _) - | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()), + Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => Ok(Ty::bool_ty()), Rvalue::Aggregate(ak, ops) => match *ak { AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64), AggregateKind::Tuple => Ok(Ty::new_tuple( @@ -1024,10 +1023,18 @@ pub enum CastKind { pub enum NullOp { /// Returns the offset of a field. OffsetOf(Vec<(VariantIdx, FieldIdx)>), + /// Codegen conditions for runtime checks. + RuntimeChecks(RuntimeChecks), +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] +pub enum RuntimeChecks { /// cfg!(ub_checks), but at codegen time UbChecks, /// cfg!(contract_checks), but at codegen time ContractChecks, + /// cfg!(overflow_checks), but at codegen time + OverflowChecks, } impl Operand { diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index f850bc5f89b8a..d5896474d0093 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -322,12 +322,16 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { use rustc_middle::mir::NullOp::*; + use rustc_middle::mir::RuntimeChecks::*; match self { OffsetOf(indices) => crate::mir::NullOp::OffsetOf( indices.iter().map(|idx| idx.stable(tables, cx)).collect(), ), - UbChecks => crate::mir::NullOp::UbChecks, - ContractChecks => crate::mir::NullOp::ContractChecks, + RuntimeChecks(op) => crate::mir::NullOp::RuntimeChecks(match op { + UbChecks => crate::mir::RuntimeChecks::UbChecks, + ContractChecks => crate::mir::RuntimeChecks::ContractChecks, + OverflowChecks => crate::mir::RuntimeChecks::OverflowChecks, + }), } } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1d00a6b81fabc..ad3493d93e80a 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1125,6 +1125,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } } + + self.suggest_ident_hidden_by_hygiene(err, path, span); } else if err_code == E0412 { if let Some(correct) = Self::likely_rust_type(path) { err.span_suggestion( @@ -1138,6 +1140,28 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } + fn suggest_ident_hidden_by_hygiene(&self, err: &mut Diag<'_>, path: &[Segment], span: Span) { + let [segment] = path else { return }; + + let ident = segment.ident; + let callsite_span = span.source_callsite(); + for rib in self.ribs[ValueNS].iter().rev() { + for (binding_ident, _) in &rib.bindings { + if binding_ident.name == ident.name + && !binding_ident.span.eq_ctxt(span) + && !binding_ident.span.from_expansion() + && binding_ident.span.lo() < callsite_span.lo() + { + err.span_help( + binding_ident.span, + "an identifier with the same name exists, but is not accessible due to macro hygiene", + ); + return; + } + } + } + } + /// Emit special messages for unresolved `Self` and `self`. fn suggest_self_ty( &self, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 39ecc8c66cacf..266d138a060ab 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2279,6 +2279,7 @@ symbols! { try_from_fn, try_into, try_trait_v2, + try_update, tt, tuple, tuple_indexing, @@ -2396,6 +2397,7 @@ symbols! { unwrap, unwrap_binder, unwrap_or, + update, use_cloned, use_extern_macros, use_nested_groups, diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs index 17b371f05e530..82811cda00ce9 100644 --- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs @@ -8,6 +8,7 @@ pub(crate) fn target() -> Target { base.features = "-small-data,+hvx-length128b".into(); base.has_rpath = true; + base.linker = Some("rust-lld".into()); base.linker_flavor = LinkerFlavor::Unix(Cc::Yes); base.c_enum_min_bits = Some(8); diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs index 6379cd30c3559..55ec3697a15e9 100644 --- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs @@ -27,6 +27,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(32), emit_debug_gdb_scripts: false, c_enum_min_bits: Some(8), + linker: Some("rust-lld".into()), ..Default::default() }, } diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 4f3f140af67d1..8e6376b22ce61 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -23,7 +23,7 @@ use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir::data_structures::HashMap; -use tracing::{debug, instrument}; +use tracing::{debug, instrument, trace}; mod stack; use stack::{Stack, StackDepth, StackEntry}; @@ -916,6 +916,7 @@ impl, X: Cx> SearchGraph { /// heads from the stack. This may not necessarily mean that we've actually /// reached a fixpoint for that cycle head, which impacts the way we rebase /// provisional cache entries. +#[derive_where(Debug; X: Cx)] enum RebaseReason { NoCycleUsages, Ambiguity(X::AmbiguityInfo), @@ -950,6 +951,7 @@ impl, X: Cx> SearchGraph { /// cache entries to also be ambiguous. This causes some undesirable ambiguity for nested /// goals whose result doesn't actually depend on this cycle head, but that's acceptable /// to me. + #[instrument(level = "trace", skip(self, cx))] fn rebase_provisional_cache_entries( &mut self, cx: X, @@ -969,6 +971,7 @@ impl, X: Cx> SearchGraph { let popped_head = if heads.highest_cycle_head_index() == popped_head_index { heads.remove_highest_cycle_head() } else { + debug_assert!(heads.highest_cycle_head_index() < popped_head_index); return true; }; @@ -1057,6 +1060,8 @@ impl, X: Cx> SearchGraph { new_highest_head_index, )); + trace!(?input, ?entry, "rebased provisional cache entry"); + true }); !entries.is_empty() @@ -1379,7 +1384,8 @@ impl, X: Cx> SearchGraph { } // Clear all provisional cache entries which depend on a previous provisional - // result of this goal and rerun. + // result of this goal and rerun. This does not remove goals which accessed this + // goal without depending on its result. self.clear_dependent_provisional_results_for_rerun(); debug!(?result, "fixpoint changed provisional results"); @@ -1399,7 +1405,12 @@ impl, X: Cx> SearchGraph { // similar to the previous iterations when reevaluating, it's better // for caching if the reevaluation also starts out with `false`. encountered_overflow: false, - usages: None, + // We keep provisional cache entries around if they used this goal + // without depending on its result. + // + // We still need to drop or rebase these cache entries once we've + // finished evaluating this goal. + usages: Some(HeadUsages::default()), candidate_usages: None, }); } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 7ad1679b1c822..39b17514a699c 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2241,3 +2241,55 @@ impl Error for Box { Error::provide(&**self, request); } } + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl Allocator for Box { + #[inline] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate(layout) + } + + #[inline] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate_zeroed(layout) + } + + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).deallocate(ptr, layout) } + } + + #[inline] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).shrink(ptr, old_layout, new_layout) } + } +} diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index a24ea6e526c4b..d25d7044e0001 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -4413,3 +4413,55 @@ impl Drop for UniqueRcUninit { } } } + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl Allocator for Rc { + #[inline] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate(layout) + } + + #[inline] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate_zeroed(layout) + } + + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).deallocate(ptr, layout) } + } + + #[inline] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).shrink(ptr, old_layout, new_layout) } + } +} diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 13b5cf23e72d8..6618d3f8ad980 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -4780,3 +4780,55 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueArc { unsafe { ptr::drop_in_place(&mut (*self.ptr.as_ptr()).data) }; } } + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl Allocator for Arc { + #[inline] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate(layout) + } + + #[inline] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate_zeroed(layout) + } + + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).deallocate(ptr, layout) } + } + + #[inline] + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } + } + + #[inline] + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).shrink(ptr, old_layout, new_layout) } + } +} diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 655ec4dff309a..ff55793340bd0 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -227,7 +227,7 @@ impl dyn Any { // SAFETY: just checked whether we are pointing to the correct type, and we can rely on // that check for memory safety because we have implemented Any for all types; no other // impls can exist as they would conflict with our impl. - unsafe { Some(self.downcast_ref_unchecked()) } + unsafe { Some(self.downcast_unchecked_ref()) } } else { None } @@ -263,7 +263,7 @@ impl dyn Any { // SAFETY: just checked whether we are pointing to the correct type, and we can rely on // that check for memory safety because we have implemented Any for all types; no other // impls can exist as they would conflict with our impl. - unsafe { Some(self.downcast_mut_unchecked()) } + unsafe { Some(self.downcast_unchecked_mut()) } } else { None } @@ -281,7 +281,7 @@ impl dyn Any { /// let x: Box = Box::new(1_usize); /// /// unsafe { - /// assert_eq!(*x.downcast_ref_unchecked::(), 1); + /// assert_eq!(*x.downcast_unchecked_ref::(), 1); /// } /// ``` /// @@ -291,7 +291,7 @@ impl dyn Any { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_ref_unchecked(&self) -> &T { + pub unsafe fn downcast_unchecked_ref(&self) -> &T { debug_assert!(self.is::()); // SAFETY: caller guarantees that T is the correct type unsafe { &*(self as *const dyn Any as *const T) } @@ -309,7 +309,7 @@ impl dyn Any { /// let mut x: Box = Box::new(1_usize); /// /// unsafe { - /// *x.downcast_mut_unchecked::() += 1; + /// *x.downcast_unchecked_mut::() += 1; /// } /// /// assert_eq!(*x.downcast_ref::().unwrap(), 2); @@ -321,7 +321,7 @@ impl dyn Any { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + pub unsafe fn downcast_unchecked_mut(&mut self) -> &mut T { debug_assert!(self.is::()); // SAFETY: caller guarantees that T is the correct type unsafe { &mut *(self as *mut dyn Any as *mut T) } @@ -417,7 +417,7 @@ impl dyn Any + Send { /// let x: Box = Box::new(1_usize); /// /// unsafe { - /// assert_eq!(*x.downcast_ref_unchecked::(), 1); + /// assert_eq!(*x.downcast_unchecked_ref::(), 1); /// } /// ``` /// @@ -427,9 +427,9 @@ impl dyn Any + Send { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_ref_unchecked(&self) -> &T { + pub unsafe fn downcast_unchecked_ref(&self) -> &T { // SAFETY: guaranteed by caller - unsafe { ::downcast_ref_unchecked::(self) } + unsafe { ::downcast_unchecked_ref::(self) } } /// Forwards to the method defined on the type `dyn Any`. @@ -444,7 +444,7 @@ impl dyn Any + Send { /// let mut x: Box = Box::new(1_usize); /// /// unsafe { - /// *x.downcast_mut_unchecked::() += 1; + /// *x.downcast_unchecked_mut::() += 1; /// } /// /// assert_eq!(*x.downcast_ref::().unwrap(), 2); @@ -456,9 +456,9 @@ impl dyn Any + Send { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + pub unsafe fn downcast_unchecked_mut(&mut self) -> &mut T { // SAFETY: guaranteed by caller - unsafe { ::downcast_mut_unchecked::(self) } + unsafe { ::downcast_unchecked_mut::(self) } } } @@ -551,7 +551,7 @@ impl dyn Any + Send + Sync { /// let x: Box = Box::new(1_usize); /// /// unsafe { - /// assert_eq!(*x.downcast_ref_unchecked::(), 1); + /// assert_eq!(*x.downcast_unchecked_ref::(), 1); /// } /// ``` /// # Safety @@ -560,9 +560,9 @@ impl dyn Any + Send + Sync { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_ref_unchecked(&self) -> &T { + pub unsafe fn downcast_unchecked_ref(&self) -> &T { // SAFETY: guaranteed by caller - unsafe { ::downcast_ref_unchecked::(self) } + unsafe { ::downcast_unchecked_ref::(self) } } /// Forwards to the method defined on the type `Any`. @@ -577,7 +577,7 @@ impl dyn Any + Send + Sync { /// let mut x: Box = Box::new(1_usize); /// /// unsafe { - /// *x.downcast_mut_unchecked::() += 1; + /// *x.downcast_unchecked_mut::() += 1; /// } /// /// assert_eq!(*x.downcast_ref::().unwrap(), 2); @@ -588,9 +588,9 @@ impl dyn Any + Send + Sync { /// with the incorrect type is *undefined behavior*. #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] - pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + pub unsafe fn downcast_unchecked_mut(&mut self) -> &mut T { // SAFETY: guaranteed by caller - unsafe { ::downcast_mut_unchecked::(self) } + unsafe { ::downcast_unchecked_mut::(self) } } } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 5ba2d92a4596f..4f6a425a09839 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2589,6 +2589,24 @@ pub const fn ub_checks() -> bool { cfg!(ub_checks) } +/// Returns whether we should perform some overflow-checking at runtime. This eventually evaluates to +/// `cfg!(overflow_checks)`, but behaves different from `cfg!` when mixing crates built with different +/// flags: if the crate has overflow checks enabled or carries the `#[rustc_inherit_overflow_checks]` +/// attribute, evaluation is delayed until monomorphization (or until the call gets inlined into +/// a crate that does not delay evaluation further); otherwise it can happen any time. +/// +/// The common case here is a user program built with overflow_checks linked against the distributed +/// sysroot which is built without overflow_checks but with `#[rustc_inherit_overflow_checks]`. +/// For code that gets monomorphized in the user crate (i.e., generic functions and functions with +/// `#[inline]`), gating assertions on `overflow_checks()` rather than `cfg!(overflow_checks)` means that +/// assertions are enabled whenever the *user crate* has overflow checks enabled. However if the +/// user has overflow checks disabled, the checks will still get optimized out. +#[inline(always)] +#[rustc_intrinsic] +pub const fn overflow_checks() -> bool { + cfg!(debug_assertions) +} + /// Allocates a block of memory at compile time. /// At runtime, just returns a null pointer. /// diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 6fee7febde38d..9afa71ec0f117 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1646,11 +1646,16 @@ impl Result { #[inline] #[track_caller] #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")] - pub unsafe fn unwrap_unchecked(self) -> T { + #[rustc_const_unstable(feature = "const_result_unwrap_unchecked", issue = "148714")] + pub const unsafe fn unwrap_unchecked(self) -> T { match self { Ok(t) => t, - // SAFETY: the safety contract must be upheld by the caller. - Err(_) => unsafe { hint::unreachable_unchecked() }, + Err(e) => { + // FIXME(const-hack): to avoid E: const Destruct bound + super::mem::forget(e); + // SAFETY: the safety contract must be upheld by the caller. + unsafe { hint::unreachable_unchecked() } + } } } diff --git a/library/std/benches/path.rs b/library/std/benches/path.rs index 094c00894a8ee..912c783b31e4c 100644 --- a/library/std/benches/path.rs +++ b/library/std/benches/path.rs @@ -55,6 +55,30 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { }); } +#[bench] +fn bench_path_components_iter(b: &mut test::Bencher) { + let p = Path::new("/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"); + + b.iter(|| { + for c in black_box(p).components() { + black_box(c); + } + }) +} + +#[bench] +fn bench_path_file_name(b: &mut test::Bencher) { + let p1 = Path::new("foo.bar"); + let p2 = Path::new("foo/bar"); + let p3 = Path::new("/bar"); + + b.iter(|| { + black_box(black_box(p1).file_name()); + black_box(black_box(p2).file_name()); + black_box(black_box(p3).file_name()); + }) +} + #[bench] #[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_hashset(b: &mut test::Bencher) { diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 1ae36a71270aa..114fcc796c525 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -79,7 +79,7 @@ use crate::ops::{self, Deref}; use crate::rc::Rc; use crate::str::FromStr; use crate::sync::Arc; -use crate::sys::path::{MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix}; +use crate::sys::path::{HAS_PREFIXES, MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix}; use crate::{cmp, fmt, fs, io, sys}; //////////////////////////////////////////////////////////////////////////////// @@ -643,17 +643,26 @@ impl<'a> Components<'a> { // how long is the prefix, if any? #[inline] fn prefix_len(&self) -> usize { + if !HAS_PREFIXES { + return 0; + } self.prefix.as_ref().map(Prefix::len).unwrap_or(0) } #[inline] fn prefix_verbatim(&self) -> bool { + if !HAS_PREFIXES { + return false; + } self.prefix.as_ref().map(Prefix::is_verbatim).unwrap_or(false) } /// how much of the prefix is left from the point of view of iteration? #[inline] fn prefix_remaining(&self) -> usize { + if !HAS_PREFIXES { + return 0; + } if self.front == State::Prefix { self.prefix_len() } else { 0 } } @@ -707,7 +716,7 @@ impl<'a> Components<'a> { if self.has_physical_root { return true; } - if let Some(p) = self.prefix { + if HAS_PREFIXES && let Some(p) = self.prefix { if p.has_implicit_root() { return true; } @@ -720,10 +729,10 @@ impl<'a> Components<'a> { if self.has_root() { return false; } - let mut iter = self.path[self.prefix_remaining()..].iter(); - match (iter.next(), iter.next()) { - (Some(&b'.'), None) => true, - (Some(&b'.'), Some(&b)) => self.is_sep_byte(b), + let slice = &self.path[self.prefix_remaining()..]; + match slice { + [b'.'] => true, + [b'.', b, ..] => self.is_sep_byte(*b), _ => false, } } @@ -732,7 +741,7 @@ impl<'a> Components<'a> { // corresponding path component unsafe fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option> { match comp { - b"." if self.prefix_verbatim() => Some(Component::CurDir), + b"." if HAS_PREFIXES && self.prefix_verbatim() => Some(Component::CurDir), b"." => None, // . components are normalized away, except at // the beginning of a path, which is treated // separately via `include_cur_dir` @@ -889,18 +898,16 @@ impl<'a> Iterator for Components<'a> { fn next(&mut self) -> Option> { while !self.finished() { match self.front { - State::Prefix if self.prefix_len() > 0 => { - self.front = State::StartDir; - debug_assert!(self.prefix_len() <= self.path.len()); - let raw = &self.path[..self.prefix_len()]; - self.path = &self.path[self.prefix_len()..]; - return Some(Component::Prefix(PrefixComponent { - raw: unsafe { OsStr::from_encoded_bytes_unchecked(raw) }, - parsed: self.prefix.unwrap(), - })); + // most likely case first + State::Body if !self.path.is_empty() => { + let (size, comp) = self.parse_next_component(); + self.path = &self.path[size..]; + if comp.is_some() { + return comp; + } } - State::Prefix => { - self.front = State::StartDir; + State::Body => { + self.front = State::Done; } State::StartDir => { self.front = State::Body; @@ -908,7 +915,7 @@ impl<'a> Iterator for Components<'a> { debug_assert!(!self.path.is_empty()); self.path = &self.path[1..]; return Some(Component::RootDir); - } else if let Some(p) = self.prefix { + } else if HAS_PREFIXES && let Some(p) = self.prefix { if p.has_implicit_root() && !p.is_verbatim() { return Some(Component::RootDir); } @@ -918,15 +925,19 @@ impl<'a> Iterator for Components<'a> { return Some(Component::CurDir); } } - State::Body if !self.path.is_empty() => { - let (size, comp) = self.parse_next_component(); - self.path = &self.path[size..]; - if comp.is_some() { - return comp; - } + _ if const { !HAS_PREFIXES } => unreachable!(), + State::Prefix if self.prefix_len() == 0 => { + self.front = State::StartDir; } - State::Body => { - self.front = State::Done; + State::Prefix => { + self.front = State::StartDir; + debug_assert!(self.prefix_len() <= self.path.len()); + let raw = &self.path[..self.prefix_len()]; + self.path = &self.path[self.prefix_len()..]; + return Some(Component::Prefix(PrefixComponent { + raw: unsafe { OsStr::from_encoded_bytes_unchecked(raw) }, + parsed: self.prefix.unwrap(), + })); } State::Done => unreachable!(), } @@ -951,11 +962,11 @@ impl<'a> DoubleEndedIterator for Components<'a> { self.back = State::StartDir; } State::StartDir => { - self.back = State::Prefix; + self.back = if HAS_PREFIXES { State::Prefix } else { State::Done }; if self.has_physical_root { self.path = &self.path[..self.path.len() - 1]; return Some(Component::RootDir); - } else if let Some(p) = self.prefix { + } else if HAS_PREFIXES && let Some(p) = self.prefix { if p.has_implicit_root() && !p.is_verbatim() { return Some(Component::RootDir); } @@ -964,6 +975,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { return Some(Component::CurDir); } } + _ if !HAS_PREFIXES => unreachable!(), State::Prefix if self.prefix_len() > 0 => { self.back = State::Done; return Some(Component::Prefix(PrefixComponent { @@ -3138,7 +3150,9 @@ impl Path { path: self.as_u8_slice(), prefix, has_physical_root: has_physical_root(self.as_u8_slice(), prefix), - front: State::Prefix, + // use a platform-specific initial state to avoid one turn of + // the state-machine when the platform doesn't have a Prefix. + front: const { if HAS_PREFIXES { State::Prefix } else { State::StartDir } }, back: State::Body, } } diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 74354227d84a6..bc1052b6f8c55 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -122,7 +122,7 @@ pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> { with_native_path(path, &|path| imp::set_perm(path, perm.clone())) } -#[cfg(unix)] +#[cfg(all(unix, not(target_os = "vxworks")))] pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> { use crate::fs::OpenOptions; @@ -139,7 +139,7 @@ pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io options.open(path)?.set_permissions(perm) } -#[cfg(not(unix))] +#[cfg(any(not(unix), target_os = "vxworks"))] pub fn set_permissions_nofollow(_path: &Path, _perm: crate::fs::Permissions) -> io::Result<()> { crate::unimplemented!( "`set_permissions_nofollow` is currently only implemented on Unix platforms" diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 129fccdbf4197..cadcfddb0f7f8 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1296,6 +1296,7 @@ impl File { target_os = "openbsd", target_os = "cygwin", target_os = "illumos", + target_os = "aix", target_vendor = "apple", ))] pub fn lock(&self) -> io::Result<()> { @@ -1321,6 +1322,7 @@ impl File { target_os = "cygwin", target_os = "solaris", target_os = "illumos", + target_os = "aix", target_vendor = "apple", )))] pub fn lock(&self) -> io::Result<()> { @@ -1335,6 +1337,7 @@ impl File { target_os = "openbsd", target_os = "cygwin", target_os = "illumos", + target_os = "aix", target_vendor = "apple", ))] pub fn lock_shared(&self) -> io::Result<()> { @@ -1360,6 +1363,7 @@ impl File { target_os = "cygwin", target_os = "solaris", target_os = "illumos", + target_os = "aix", target_vendor = "apple", )))] pub fn lock_shared(&self) -> io::Result<()> { @@ -1374,6 +1378,7 @@ impl File { target_os = "openbsd", target_os = "cygwin", target_os = "illumos", + target_os = "aix", target_vendor = "apple", ))] pub fn try_lock(&self) -> Result<(), TryLockError> { @@ -1415,6 +1420,7 @@ impl File { target_os = "cygwin", target_os = "solaris", target_os = "illumos", + target_os = "aix", target_vendor = "apple", )))] pub fn try_lock(&self) -> Result<(), TryLockError> { @@ -1432,6 +1438,7 @@ impl File { target_os = "openbsd", target_os = "cygwin", target_os = "illumos", + target_os = "aix", target_vendor = "apple", ))] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { @@ -1473,6 +1480,7 @@ impl File { target_os = "cygwin", target_os = "solaris", target_os = "illumos", + target_os = "aix", target_vendor = "apple", )))] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { @@ -1490,6 +1498,7 @@ impl File { target_os = "openbsd", target_os = "cygwin", target_os = "illumos", + target_os = "aix", target_vendor = "apple", ))] pub fn unlock(&self) -> io::Result<()> { @@ -1515,6 +1524,7 @@ impl File { target_os = "cygwin", target_os = "solaris", target_os = "illumos", + target_os = "aix", target_vendor = "apple", )))] pub fn unlock(&self) -> io::Result<()> { diff --git a/library/std/src/sys/path/cygwin.rs b/library/std/src/sys/path/cygwin.rs index da0982384b0e6..416877a7280d2 100644 --- a/library/std/src/sys/path/cygwin.rs +++ b/library/std/src/sys/path/cygwin.rs @@ -21,6 +21,7 @@ pub fn is_verbatim_sep(b: u8) -> bool { pub use super::windows_prefix::parse_prefix; +pub const HAS_PREFIXES: bool = true; pub const MAIN_SEP_STR: &str = "/"; pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/path/sgx.rs b/library/std/src/sys/path/sgx.rs index 32c7752f605d9..dca61f3ea145d 100644 --- a/library/std/src/sys/path/sgx.rs +++ b/library/std/src/sys/path/sgx.rs @@ -17,6 +17,7 @@ pub fn parse_prefix(_: &OsStr) -> Option> { None } +pub const HAS_PREFIXES: bool = false; pub const MAIN_SEP_STR: &str = "/"; pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/path/uefi.rs b/library/std/src/sys/path/uefi.rs index a3f4a3bfe1b67..6b8258685aa0f 100644 --- a/library/std/src/sys/path/uefi.rs +++ b/library/std/src/sys/path/uefi.rs @@ -21,6 +21,7 @@ pub fn parse_prefix(_: &OsStr) -> Option> { None } +pub const HAS_PREFIXES: bool = true; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; diff --git a/library/std/src/sys/path/unix.rs b/library/std/src/sys/path/unix.rs index 15530323a198d..611d250db4050 100644 --- a/library/std/src/sys/path/unix.rs +++ b/library/std/src/sys/path/unix.rs @@ -17,6 +17,7 @@ pub fn parse_prefix(_: &OsStr) -> Option> { None } +pub const HAS_PREFIXES: bool = false; pub const MAIN_SEP_STR: &str = "/"; pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/path/unsupported_backslash.rs b/library/std/src/sys/path/unsupported_backslash.rs index 30b06c132c98d..8ed1fdc36e23f 100644 --- a/library/std/src/sys/path/unsupported_backslash.rs +++ b/library/std/src/sys/path/unsupported_backslash.rs @@ -18,6 +18,7 @@ pub fn parse_prefix(_: &OsStr) -> Option> { None } +pub const HAS_PREFIXES: bool = true; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index f124e1e5a71c7..509b13b6ae812 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -9,6 +9,7 @@ mod tests; pub use super::windows_prefix::parse_prefix; +pub const HAS_PREFIXES: bool = true; pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; diff --git a/package-lock.json b/package-lock.json index d0297bf70b63f..72129f115845e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,10 @@ "browser-ui-test": "^0.22.2", "es-check": "^6.2.1", "eslint": "^8.57.1", - "eslint-js": "github:eslint/js", "typescript": "^5.8.3" + }, + "devDependencies": { + "@types/node": "^24.10.0" } }, "node_modules/@babel/code-frame": { @@ -57,6 +59,12 @@ "node": ">= 10" } }, + "node_modules/@caporal/core/node_modules/@types/node": { + "version": "13.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.3.tgz", + "integrity": "sha512-01s+ac4qerwd6RHD+mVbOEsraDHSgUaefQlEdBbUolnQFjKwCr7luvAlEwW1RFojh67u0z4OUTjPn9LEl4zIkA==", + "license": "MIT" + }, "node_modules/@colors/colors": { "version": "1.6.0", "license": "MIT", @@ -225,8 +233,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "13.9.3", - "license": "MIT" + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } }, "node_modules/@types/table": { "version": "5.0.0", @@ -944,13 +957,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-js": { - "version": "1.0.0", - "resolved": "git+ssh://git@github.com/eslint/js.git#9e5b4fabf073b915abc56d6c14cc24177036d43e", - "workspaces": [ - "packages/*" - ] - }, "node_modules/eslint-scope": { "version": "7.2.2", "license": "BSD-2-Clause", @@ -2575,6 +2581,12 @@ "through": "^2.3.8" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, "node_modules/untildify": { "version": "3.0.3", "license": "MIT", diff --git a/package.json b/package.json index 04e0f6af19a0c..7420c53fd8cca 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,9 @@ "browser-ui-test": "^0.22.2", "es-check": "^6.2.1", "eslint": "^8.57.1", - "eslint-js": "github:eslint/js", "typescript": "^5.8.3" + }, + "devDependencies": { + "@types/node": "^24.10.0" } } diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 6622aae069d5c..d6d6fc67ba5ae 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -1228,9 +1228,12 @@ impl Step for ErrorIndex { t!(fs::create_dir_all(&out)); tool::ErrorIndex::command(builder, self.compilers) .arg("html") - .arg(out) + .arg(&out) .arg(&builder.version) .run(builder); + + let index = out.join("error-index.html"); + builder.maybe_open_in_browser::(index); } fn metadata(&self) -> Option { diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md index be6e17883f4eb..d74dd843eb259 100644 --- a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md +++ b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md @@ -39,6 +39,12 @@ dynamically linked executables. # /opt/clang+llvm-18.1.0-cross-hexagon-unknown-linux-musl/x86_64-linux-gnu/bin/qemu-hexagon -L /opt/clang+llvm-18.1.0-cross-hexagon-unknown-linux-musl/x86_64-linux-gnu/target/hexagon-unknown-linux-musl/usr/ ./hello ``` +## Linking + +This target selects `rust-lld` by default. Another option to use is +[eld](https://github.com/qualcomm/eld), which is also provided with +the opensource hexagon toolchain and the Hexagon SDK. + ## Building the target Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target. diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md index b07b0bb08d60a..a906e895b7743 100644 --- a/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md +++ b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md @@ -25,6 +25,13 @@ Functions marked `extern "C"` use the [Hexagon architecture calling convention]( This target generates PIC ELF binaries. +## Linking + +This target selects `rust-lld` by default. Another option to use is +[eld](https://github.com/qualcomm/eld), which is also provided with +[the opensource hexagon toolchain](https://github.com/quic/toolchain_for_hexagon) +and the Hexagon SDK. + ## Building the target You can build Rust with support for the target by adding it to the `target` diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 3e9d88788655d..13c66ee8298b5 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -1,7 +1,7 @@ from __future__ import annotations import re import sys -from typing import List, TYPE_CHECKING +from typing import List, TYPE_CHECKING, Generator from lldb import ( SBData, @@ -13,7 +13,7 @@ ) if TYPE_CHECKING: - from lldb import SBValue, SBType, SBTypeStaticField + from lldb import SBValue, SBType, SBTypeStaticField, SBTarget # from lldb.formatters import Logger @@ -133,19 +133,18 @@ def has_children(self) -> bool: return False -def get_template_args(type_name: str) -> list[str]: +def get_template_args(type_name: str) -> Generator[str, None, None]: """ Takes a type name `T, D>` and returns a list of its generic args `["A", "tuple$", "D"]`. String-based replacement for LLDB's `SBType.template_args`, as LLDB is currently unable to populate this field for targets with PDB debug info. Also useful for manually altering the type - name of generics (e.g. `Vec` -> `Vec<&str>`). + name of generics (e.g. `Vec >` -> `Vec<&str>`). Each element of the returned list can be looked up for its `SBType` value via `SBTarget.FindFirstType()` """ - params = [] level = 0 start = 0 for i, c in enumerate(type_name): @@ -156,11 +155,55 @@ def get_template_args(type_name: str) -> list[str]: elif c == ">": level -= 1 if level == 0: - params.append(type_name[start:i].strip()) + yield type_name[start:i].strip() elif c == "," and level == 1: - params.append(type_name[start:i].strip()) + yield type_name[start:i].strip() start = i + 1 - return params + + +MSVC_PTR_PREFIX: List[str] = ["ref$<", "ref_mut$<", "ptr_const$<", "ptr_mut$<"] + + +def resolve_msvc_template_arg(arg_name: str, target: SBTarget) -> SBType: + """ + RECURSIVE when arrays or references are nested (e.g. `ref$ >`, `array$ >`) + + Takes the template arg's name (likely from `get_template_args`) and finds/creates its + corresponding SBType. + + For non-reference/pointer/array types this is identical to calling + `target.FindFirstType(arg_name)` + + LLDB internally interprets refs, pointers, and arrays C-style (`&u8` -> `u8 *`, + `*const u8` -> `u8 *`, `[u8; 5]` -> `u8 [5]`). Looking up these names still doesn't work in the + current version of LLDB, so instead the types are generated via `base_type.GetPointerType()` and + `base_type.GetArrayType()`, which bypass the PDB file and ask clang directly for the type node. + """ + result = target.FindFirstType(arg_name) + + if result.IsValid(): + return result + + for prefix in MSVC_PTR_PREFIX: + if arg_name.startswith(prefix): + arg_name = arg_name[len(prefix) : -1].strip() + + result = resolve_msvc_template_arg(arg_name, target) + return result.GetPointerType() + + if arg_name.startswith("array$<"): + arg_name = arg_name[7:-1].strip() + + template_args = get_template_args(arg_name) + + element_name = next(template_args) + length = next(template_args) + + result = resolve_msvc_template_arg(element_name, target) + + return result.GetArrayType(int(length)) + + return result def SizeSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str: @@ -815,6 +858,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque): # logger = Logger.Logger() # logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName()) self.valobj = valobj + self.element_type = None self.update() def num_children(self) -> int: @@ -848,8 +892,9 @@ def update(self): self.element_type = self.valobj.GetType().GetTemplateArgumentType(0) if not self.element_type.IsValid(): - element_name = get_template_args(self.valobj.GetTypeName())[0] - self.element_type = self.valobj.target.FindFirstType(element_name) + arg_name = next(get_template_args(self.valobj.GetTypeName())) + + self.element_type = resolve_msvc_template_arg(arg_name, self.valobj.target) self.element_type_size = self.element_type.GetByteSize() @@ -925,6 +970,7 @@ def __init__(self, valobj: SBValue, _dict: LLDBOpaque): # logger = Logger.Logger() # logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName()) self.valobj = valobj + self.element_type = None self.update() def num_children(self) -> int: @@ -961,6 +1007,12 @@ def update(self): ) self.element_type = self.valobj.GetType().GetTemplateArgumentType(0) + + if not self.element_type.IsValid(): + arg_name = next(get_template_args(self.valobj.GetTypeName())) + + self.element_type = resolve_msvc_template_arg(arg_name, self.valobj.target) + self.element_type_size = self.element_type.GetByteSize() def has_children(self) -> bool: @@ -1088,6 +1140,7 @@ def get_child_at_index(self, index: int) -> SBValue: element = self.data_ptr.CreateValueFromAddress( "[%s]" % index, address, self.pair_type ) + if self.show_values: return element else: @@ -1107,14 +1160,12 @@ def update(self): self.size = inner_table.GetChildMemberWithName("items").GetValueAsUnsigned() - template_args = table.type.template_args + self.pair_type = table.GetType().GetTemplateArgumentType(0) - if template_args is None: - type_name = table.GetTypeName() - args = get_template_args(type_name) - self.pair_type = self.valobj.target.FindFirstType(args[0]) - else: - self.pair_type = template_args[0] + if not self.pair_type.IsValid(): + arg_name = next(get_template_args(table.GetTypeName())) + + self.pair_type = resolve_msvc_template_arg(arg_name, self.valobj.target) if self.pair_type.IsTypedefType(): self.pair_type = self.pair_type.GetTypedefedType() diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 90ea2616890a4..0cf1ad348953b 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -194,7 +194,7 @@ fn check_rvalue<'tcx>( )) } }, - Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks, _) + Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::RuntimeChecks(_), _) | Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, cx.tcx); diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index e91b8d97ef729..3bbad01207dbc 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1347,13 +1347,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } #[inline(always)] - fn ub_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> { - interp_ok(ecx.tcx.sess.ub_checks()) - } - - #[inline(always)] - fn contract_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> { - interp_ok(ecx.tcx.sess.contract_checks()) + fn runtime_checks(ecx: &InterpCx<'tcx, Self>, r: mir::RuntimeChecks) -> InterpResult<'tcx, bool> { + interp_ok(r.value(&ecx.tcx.sess)) } #[inline(always)] diff --git a/tests/codegen-llvm/auxiliary/overflow_checks_add.rs b/tests/codegen-llvm/auxiliary/overflow_checks_add.rs new file mode 100644 index 0000000000000..ea9db1e9837e1 --- /dev/null +++ b/tests/codegen-llvm/auxiliary/overflow_checks_add.rs @@ -0,0 +1,10 @@ +//@ compile-flags: -Cdebug-assertions=yes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +/// Emulates the default behavior of `+` using `intrinsics::overflow_checks()`. +#[inline] +pub fn add(a: u8, b: u8) -> u8 { + if core::intrinsics::overflow_checks() { a.strict_add(b) } else { a.wrapping_add(b) } +} diff --git a/tests/codegen-llvm/overflow-checks.rs b/tests/codegen-llvm/overflow-checks.rs new file mode 100644 index 0000000000000..c8b10df507b0f --- /dev/null +++ b/tests/codegen-llvm/overflow-checks.rs @@ -0,0 +1,29 @@ +// With -Coverflow-checks=yes (enabled by default by -Cdebug-assertions=yes) we will produce a +// runtime check that panics when an operation would result in integer overflow. +// +// This test ensures that such a runtime check is *not* emitted when debug-assertions are enabled, +// but overflow-checks are explicitly disabled. It also ensures that even if a dependency is +// compiled with overflow checks, `intrinsics::overflow_checks()` will be treated with the +// overflow-checks setting of the current crate (when `#[rustc_inherit_overflow_checks]`) is used. + +//@ aux-build:overflow_checks_add.rs +//@ revisions: DEBUG NOCHECKS +//@ compile-flags: -O -Cdebug-assertions=yes +//@ [NOCHECKS] compile-flags: -Coverflow-checks=no + +#![crate_type = "lib"] + +extern crate overflow_checks_add; + +// CHECK-LABEL: @add( +#[no_mangle] +pub unsafe fn add(a: u8, b: u8) -> u8 { + // CHECK: i8 noundef %a, i8 noundef %b + // CHECK: add i8 %b, %a + // DEBUG: icmp ult i8 [[zero:[^,]+]], %a + // DEBUG: call core::num::overflow_panic::add + // DEBUG: unreachable + // NOCHECKS-NOT: unreachable + // NOCHECKS: ret i8 %0 + overflow_checks_add::add(a, b) +} diff --git a/tests/ui/binding/issue-53114-safety-checks.rs b/tests/ui/binding/issue-53114-safety-checks.rs index f4be2b482a7e6..07dfda77622a2 100644 --- a/tests/ui/binding/issue-53114-safety-checks.rs +++ b/tests/ui/binding/issue-53114-safety-checks.rs @@ -20,12 +20,12 @@ fn let_wild_gets_unsafe_field() { let u1 = U { a: I(0) }; let u2 = U { a: I(1) }; let p = P { a: &2, b: &3 }; - let _ = &p.b; //~ ERROR reference to packed field + let _ = &p.b; //~ ERROR reference to field of packed struct let _ = u1.a; //~ ERROR [E0133] let _ = &u2.a; //~ ERROR [E0133] // variation on above with `_` in substructure - let (_,) = (&p.b,); //~ ERROR reference to packed field + let (_,) = (&p.b,); //~ ERROR reference to field of packed struct let (_,) = (u1.a,); //~ ERROR [E0133] let (_,) = (&u2.a,); //~ ERROR [E0133] } @@ -34,12 +34,12 @@ fn let_ascribe_gets_unsafe_field() { let u1 = U { a: I(0) }; let u2 = U { a: I(1) }; let p = P { a: &2, b: &3 }; - let _: _ = &p.b; //~ ERROR reference to packed field + let _: _ = &p.b; //~ ERROR reference to field of packed struct let _: _ = u1.a; //~ ERROR [E0133] let _: _ = &u2.a; //~ ERROR [E0133] // variation on above with `_` in substructure - let (_,): _ = (&p.b,); //~ ERROR reference to packed field + let (_,): _ = (&p.b,); //~ ERROR reference to field of packed struct let (_,): _ = (u1.a,); //~ ERROR [E0133] let (_,): _ = (&u2.a,); //~ ERROR [E0133] } @@ -48,12 +48,12 @@ fn match_unsafe_field_to_wild() { let u1 = U { a: I(0) }; let u2 = U { a: I(1) }; let p = P { a: &2, b: &3 }; - match &p.b { _ => { } } //~ ERROR reference to packed field + match &p.b { _ => { } } //~ ERROR reference to field of packed struct match u1.a { _ => { } } //~ ERROR [E0133] match &u2.a { _ => { } } //~ ERROR [E0133] // variation on above with `_` in substructure - match (&p.b,) { (_,) => { } } //~ ERROR reference to packed field + match (&p.b,) { (_,) => { } } //~ ERROR reference to field of packed struct match (u1.a,) { (_,) => { } } //~ ERROR [E0133] match (&u2.a,) { (_,) => { } } //~ ERROR [E0133] } diff --git a/tests/ui/binding/issue-53114-safety-checks.stderr b/tests/ui/binding/issue-53114-safety-checks.stderr index 9d909e915c21b..3e8389b77c53f 100644 --- a/tests/ui/binding/issue-53114-safety-checks.stderr +++ b/tests/ui/binding/issue-53114-safety-checks.stderr @@ -1,20 +1,20 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:23:13 | LL | let _ = &p.b; | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:28:17 | LL | let (_,) = (&p.b,); | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) @@ -50,23 +50,23 @@ LL | let (_,) = (&u2.a,); | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:37:16 | LL | let _: _ = &p.b; | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:42:20 | LL | let (_,): _ = (&p.b,); | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) @@ -102,23 +102,23 @@ LL | let (_,): _ = (&u2.a,); | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:51:11 | LL | match &p.b { _ => { } } | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-53114-safety-checks.rs:56:12 | LL | match (&p.b,) { (_,) => { } } | ^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs index fe5106c57af68..4395b70a922fb 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs @@ -19,7 +19,7 @@ fn test_missing_unsafe_warning_on_repr_packed() { let c = || { println!("{}", foo.x); - //~^ ERROR: reference to packed field is unaligned + //~^ ERROR: reference to field of packed struct is unaligned let _z = foo.x; }; diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr index c9972c8e7e349..0e93e033c022c 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr @@ -1,10 +1,10 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/repr_packed.rs:21:24 | LL | println!("{}", foo.x); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const-eval/overflow_checks.rs b/tests/ui/consts/const-eval/overflow_checks.rs new file mode 100644 index 0000000000000..7f69157779906 --- /dev/null +++ b/tests/ui/consts/const-eval/overflow_checks.rs @@ -0,0 +1,8 @@ +//@ build-pass +//@ compile-flags: -O -C overflow-checks=no + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +// Always returns true during CTFE, even if overflow checks are disabled. +const _: () = assert!(core::intrinsics::overflow_checks()); diff --git a/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.rs b/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.rs deleted file mode 100644 index bdeacac4957b6..0000000000000 --- a/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.rs +++ /dev/null @@ -1,49 +0,0 @@ -//@ only-x86_64 -use std::sync::atomic::{AtomicIsize, Ordering}; - -fn main() { - // `fetch_update` testing - let x = AtomicIsize::new(0); - - // Allowed ordering combos - let _ = x.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Acquire, Ordering::Relaxed, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Acquire, Ordering::Acquire, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Release, Ordering::Relaxed, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::AcqRel, Ordering::Relaxed, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::AcqRel, Ordering::Acquire, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::SeqCst, Ordering::Relaxed, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::SeqCst, Ordering::Acquire, |old| Some(old + 1)); - let _ = x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + 1)); - - // AcqRel is always forbidden as a failure ordering - let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - - // Release is always forbidden as a failure ordering - let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` - -} diff --git a/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.stderr b/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.stderr deleted file mode 100644 index 33829d68fd5c7..0000000000000 --- a/tests/ui/lint/lint-invalid-atomic-ordering-fetch-update.stderr +++ /dev/null @@ -1,83 +0,0 @@ -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:26:47 - | -LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - = note: `#[deny(invalid_atomic_ordering)]` on by default - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:28:47 - | -LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:30:47 - | -LL | let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:32:46 - | -LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:34:46 - | -LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:38:47 - | -LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:40:47 - | -LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:42:47 - | -LL | let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:44:46 - | -LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:46:46 - | -LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ invalid failure ordering - | - = help: consider using `Acquire` or `Relaxed` failure ordering instead - -error: aborting due to 10 previous errors - diff --git a/tests/ui/lint/lint-invalid-atomic-ordering-update.rs b/tests/ui/lint/lint-invalid-atomic-ordering-update.rs new file mode 100644 index 0000000000000..ac41e7cee0c25 --- /dev/null +++ b/tests/ui/lint/lint-invalid-atomic-ordering-update.rs @@ -0,0 +1,144 @@ +//@ only-x86_64 +#![feature(atomic_try_update)] + +use std::sync::atomic::{AtomicIsize, Ordering}; + +fn main() { + // `fetch_update` testing + let x = AtomicIsize::new(0); + + // Allowed ordering combos + let _ = x.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Relaxed, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.update(Ordering::Relaxed, Ordering::Relaxed, |old| old + 1); + + let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.update(Ordering::Relaxed, Ordering::Acquire, |old| old + 1); + + let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.update(Ordering::Relaxed, Ordering::SeqCst, |old| old + 1); + + let _ = x.fetch_update(Ordering::Acquire, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Acquire, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.update(Ordering::Acquire, Ordering::Relaxed, |old| old + 1); + + let _ = x.fetch_update(Ordering::Acquire, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Acquire, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.update(Ordering::Acquire, Ordering::Acquire, |old| old + 1); + + let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.update(Ordering::Acquire, Ordering::SeqCst, |old| old + 1); + + let _ = x.fetch_update(Ordering::Release, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Release, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.update(Ordering::Release, Ordering::Relaxed, |old| old + 1); + + let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.update(Ordering::Release, Ordering::Acquire, |old| old + 1); + + let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.try_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.update(Ordering::Release, Ordering::SeqCst, |old| old + 1); + + let _ = x.fetch_update(Ordering::AcqRel, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.try_update(Ordering::AcqRel, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.update(Ordering::AcqRel, Ordering::Relaxed, |old| old + 1); + + let _ = x.fetch_update(Ordering::AcqRel, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.try_update(Ordering::AcqRel, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.update(Ordering::AcqRel, Ordering::Acquire, |old| old + 1); + + let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.try_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.update(Ordering::AcqRel, Ordering::SeqCst, |old| old + 1); + + let _ = x.fetch_update(Ordering::SeqCst, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.try_update(Ordering::SeqCst, Ordering::Relaxed, |old| Some(old + 1)); + let _ = x.update(Ordering::SeqCst, Ordering::Relaxed, |old| old + 1); + + let _ = x.fetch_update(Ordering::SeqCst, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.try_update(Ordering::SeqCst, Ordering::Acquire, |old| Some(old + 1)); + let _ = x.update(Ordering::SeqCst, Ordering::Acquire, |old| old + 1); + + let _ = x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.try_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + 1)); + let _ = x.update(Ordering::SeqCst, Ordering::SeqCst, |old| old + 1); + + // AcqRel is always forbidden as a failure ordering + + let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Relaxed, Ordering::AcqRel, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Acquire, Ordering::AcqRel, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Release, Ordering::AcqRel, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::AcqRel, Ordering::AcqRel, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::SeqCst, Ordering::AcqRel, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + // Release is always forbidden as a failure ordering + + let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Relaxed, Ordering::Release, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Acquire, Ordering::Release, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::Release, Ordering::Release, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::AcqRel, Ordering::Release, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` + + let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.try_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); + //~^ ERROR `try_update`'s failure ordering may not be `Release` or `AcqRel` + let _ = x.update(Ordering::SeqCst, Ordering::Release, |old| old + 1); + //~^ ERROR `update`'s failure ordering may not be `Release` or `AcqRel` +} diff --git a/tests/ui/lint/lint-invalid-atomic-ordering-update.stderr b/tests/ui/lint/lint-invalid-atomic-ordering-update.stderr new file mode 100644 index 0000000000000..8c266bacf3144 --- /dev/null +++ b/tests/ui/lint/lint-invalid-atomic-ordering-update.stderr @@ -0,0 +1,243 @@ +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:73:47 + | +LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + = note: `#[deny(invalid_atomic_ordering)]` on by default + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:75:45 + | +LL | let _ = x.try_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:77:41 + | +LL | let _ = x.update(Ordering::Relaxed, Ordering::AcqRel, |old| old + 1); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:80:47 + | +LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:82:45 + | +LL | let _ = x.try_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:84:41 + | +LL | let _ = x.update(Ordering::Acquire, Ordering::AcqRel, |old| old + 1); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:87:47 + | +LL | let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:89:45 + | +LL | let _ = x.try_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:91:41 + | +LL | let _ = x.update(Ordering::Release, Ordering::AcqRel, |old| old + 1); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:94:46 + | +LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:96:44 + | +LL | let _ = x.try_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:98:40 + | +LL | let _ = x.update(Ordering::AcqRel, Ordering::AcqRel, |old| old + 1); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:101:46 + | +LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:103:44 + | +LL | let _ = x.try_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:105:40 + | +LL | let _ = x.update(Ordering::SeqCst, Ordering::AcqRel, |old| old + 1); + | ^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:110:47 + | +LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:112:45 + | +LL | let _ = x.try_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:114:41 + | +LL | let _ = x.update(Ordering::Relaxed, Ordering::Release, |old| old + 1); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:117:47 + | +LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:119:45 + | +LL | let _ = x.try_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:121:41 + | +LL | let _ = x.update(Ordering::Acquire, Ordering::Release, |old| old + 1); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:124:47 + | +LL | let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:126:45 + | +LL | let _ = x.try_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:128:41 + | +LL | let _ = x.update(Ordering::Release, Ordering::Release, |old| old + 1); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:131:46 + | +LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:133:44 + | +LL | let _ = x.try_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:135:40 + | +LL | let _ = x.update(Ordering::AcqRel, Ordering::Release, |old| old + 1); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:138:46 + | +LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `try_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `try_update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:140:44 + | +LL | let _ = x.try_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: `update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `update` does not result in a write + --> $DIR/lint-invalid-atomic-ordering-update.rs:142:40 + | +LL | let _ = x.update(Ordering::SeqCst, Ordering::Release, |old| old + 1); + | ^^^^^^^^^^^^^^^^^ invalid failure ordering + | + = help: consider using `Acquire` or `Relaxed` failure ordering instead + +error: aborting due to 30 previous errors + diff --git a/tests/ui/lint/unaligned_references.current.stderr b/tests/ui/lint/unaligned_references.current.stderr index 0f980c5301f37..39ca072e848cc 100644 --- a/tests/ui/lint/unaligned_references.current.stderr +++ b/tests/ui/lint/unaligned_references.current.stderr @@ -1,130 +1,130 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:32:13 | LL | &self.x; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 2-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:44:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:46:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:51:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:81:17 | LL | let _ = &good.ptr; | ^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:82:17 | LL | let _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:84:17 | LL | let _ = &good.data as *const _; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:85:27 | LL | let _: *const _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:87:17 | LL | let _ = good.data.clone(); | ^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:89:17 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:98:17 | LL | let _ = &packed2.x; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 2-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:137:20 | LL | let _ref = &m1.1.a; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:140:20 | LL | let _ref = &m2.1.a; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/lint/unaligned_references.next.stderr b/tests/ui/lint/unaligned_references.next.stderr index 0f980c5301f37..39ca072e848cc 100644 --- a/tests/ui/lint/unaligned_references.next.stderr +++ b/tests/ui/lint/unaligned_references.next.stderr @@ -1,130 +1,130 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:32:13 | LL | &self.x; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 2-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:44:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:46:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:51:24 | LL | println!("{:?}", &*foo.0); | ^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:81:17 | LL | let _ = &good.ptr; | ^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:82:17 | LL | let _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:84:17 | LL | let _ = &good.data as *const _; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:85:27 | LL | let _: *const _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:87:17 | LL | let _ = good.data.clone(); | ^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:89:17 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:98:17 | LL | let _ = &packed2.x; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 2-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:137:20 | LL | let _ref = &m1.1.a; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references.rs:140:20 | LL | let _ref = &m2.1.a; | ^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/lint/unaligned_references.rs b/tests/ui/lint/unaligned_references.rs index 321e3ed135c47..af922a1031ab6 100644 --- a/tests/ui/lint/unaligned_references.rs +++ b/tests/ui/lint/unaligned_references.rs @@ -29,7 +29,7 @@ trait Foo { impl Foo for Packed2 { fn evil(&self) { unsafe { - &self.x; //~ ERROR reference to packed field + &self.x; //~ ERROR reference to field of packed struct } } } @@ -41,14 +41,14 @@ fn packed_dyn() { let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u64])); let foo: &Unaligned = &*local; - println!("{:?}", &*foo.0); //~ ERROR reference to packed field + println!("{:?}", &*foo.0); //~ ERROR reference to field of packed struct let foo: &Unaligned<[u64]> = &*local; - println!("{:?}", &*foo.0); //~ ERROR reference to packed field + println!("{:?}", &*foo.0); //~ ERROR reference to field of packed struct // Even if the actual alignment is 1, we cannot know that when looking at `dyn Debug.` let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u8])); let foo: &Unaligned = &*local; - println!("{:?}", &*foo.0); //~ ERROR reference to packed field + println!("{:?}", &*foo.0); //~ ERROR reference to field of packed struct // However, we *can* know the alignment when looking at a slice. let foo: &Unaligned<[u8]> = &*local; println!("{:?}", &*foo.0); // no error! @@ -78,15 +78,15 @@ fn main() { unsafe { let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] }; - let _ = &good.ptr; //~ ERROR reference to packed field - let _ = &good.data; //~ ERROR reference to packed field + let _ = &good.ptr; //~ ERROR reference to field of packed struct + let _ = &good.data; //~ ERROR reference to field of packed struct // Error even when turned into raw pointer immediately. - let _ = &good.data as *const _; //~ ERROR reference to packed field - let _: *const _ = &good.data; //~ ERROR reference to packed field + let _ = &good.data as *const _; //~ ERROR reference to field of packed struct + let _: *const _ = &good.data; //~ ERROR reference to field of packed struct // Error on method call. - let _ = good.data.clone(); //~ ERROR reference to packed field + let _ = good.data.clone(); //~ ERROR reference to field of packed struct // Error for nested fields. - let _ = &good.data2[0]; //~ ERROR reference to packed field + let _ = &good.data2[0]; //~ ERROR reference to field of packed struct let _ = &*good.ptr; // ok, behind a pointer let _ = &good.aligned; // ok, has align 1 @@ -95,7 +95,7 @@ fn main() { unsafe { let packed2 = Packed2 { x: 0, y: 0, z: 0 }; - let _ = &packed2.x; //~ ERROR reference to packed field + let _ = &packed2.x; //~ ERROR reference to field of packed struct let _ = &packed2.y; // ok, has align 2 in packed(2) struct let _ = &packed2.z; // ok, has align 1 packed2.evil(); @@ -134,9 +134,9 @@ fn main() { struct Misalign(u8, T); let m1 = Misalign(0, Wrapper { a: U16(10), b: HasDrop }); - let _ref = &m1.1.a; //~ ERROR reference to packed field + let _ref = &m1.1.a; //~ ERROR reference to field of packed struct let m2 = Misalign(0, Wrapper2 { a: U16(10), b: HasDrop }); - let _ref = &m2.1.a; //~ ERROR reference to packed field + let _ref = &m2.1.a; //~ ERROR reference to field of packed struct } } diff --git a/tests/ui/lint/unaligned_references_external_macro.rs b/tests/ui/lint/unaligned_references_external_macro.rs index 3a97e2112a144..2d6e493dd542f 100644 --- a/tests/ui/lint/unaligned_references_external_macro.rs +++ b/tests/ui/lint/unaligned_references_external_macro.rs @@ -2,7 +2,7 @@ extern crate unaligned_references_external_crate; -unaligned_references_external_crate::mac! { //~ERROR reference to packed field is unaligned +unaligned_references_external_crate::mac! { //~ERROR reference to field of packed struct is unaligned #[repr(packed)] pub struct X { pub field: u16 diff --git a/tests/ui/lint/unaligned_references_external_macro.stderr b/tests/ui/lint/unaligned_references_external_macro.stderr index 9945c78e8ba66..dd8788aec4b5c 100644 --- a/tests/ui/lint/unaligned_references_external_macro.stderr +++ b/tests/ui/lint/unaligned_references_external_macro.stderr @@ -1,4 +1,4 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/unaligned_references_external_macro.rs:5:1 | LL | / unaligned_references_external_crate::mac! { @@ -9,7 +9,7 @@ LL | | } LL | | } | |_^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) = note: this error originates in the macro `unaligned_references_external_crate::mac` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/macros/macro-hygiene-help-issue-148580.rs b/tests/ui/macros/macro-hygiene-help-issue-148580.rs new file mode 100644 index 0000000000000..8441290b17228 --- /dev/null +++ b/tests/ui/macros/macro-hygiene-help-issue-148580.rs @@ -0,0 +1,15 @@ +macro_rules! print_it { {} => { println!("{:?}", it); } } +//~^ ERROR cannot find value `it` in this scope + +fn main() { + { + let it = "hello"; + } + { + let it = "world"; + { + let it = (); + print_it!(); + } + } +} diff --git a/tests/ui/macros/macro-hygiene-help-issue-148580.stderr b/tests/ui/macros/macro-hygiene-help-issue-148580.stderr new file mode 100644 index 0000000000000..f6a4ae7dd1c66 --- /dev/null +++ b/tests/ui/macros/macro-hygiene-help-issue-148580.stderr @@ -0,0 +1,19 @@ +error[E0425]: cannot find value `it` in this scope + --> $DIR/macro-hygiene-help-issue-148580.rs:1:50 + | +LL | macro_rules! print_it { {} => { println!("{:?}", it); } } + | ^^ not found in this scope +... +LL | print_it!(); + | ----------- in this macro invocation + | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-help-issue-148580.rs:11:17 + | +LL | let it = (); + | ^^ + = note: this error originates in the macro `print_it` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/macros/macro-hygiene-scope-15167.stderr b/tests/ui/macros/macro-hygiene-scope-15167.stderr index 58112c52df159..332a58467cee1 100644 --- a/tests/ui/macros/macro-hygiene-scope-15167.stderr +++ b/tests/ui/macros/macro-hygiene-scope-15167.stderr @@ -7,6 +7,11 @@ LL | macro_rules! f { () => (n) } LL | println!("{}", f!()); | ---- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-scope-15167.rs:12:9 + | +LL | for n in 0..1 { + | ^ = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope @@ -18,6 +23,11 @@ LL | macro_rules! f { () => (n) } LL | println!("{}", f!()); | ---- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-scope-15167.rs:16:17 + | +LL | if let Some(n) = None { + | ^ = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope @@ -29,6 +39,11 @@ LL | macro_rules! f { () => (n) } LL | println!("{}", f!()); | ---- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-scope-15167.rs:21:24 + | +LL | } else if let Some(n) = None { + | ^ = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope @@ -40,6 +55,11 @@ LL | macro_rules! f { () => (n) } LL | println!("{}", f!()); | ---- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/macro-hygiene-scope-15167.rs:25:20 + | +LL | while let Some(n) = None { + | ^ = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/tests/ui/macros/metavar-expressions/concat-hygiene.stderr b/tests/ui/macros/metavar-expressions/concat-hygiene.stderr index f3150d385ee70..9520f5182f4a7 100644 --- a/tests/ui/macros/metavar-expressions/concat-hygiene.stderr +++ b/tests/ui/macros/metavar-expressions/concat-hygiene.stderr @@ -7,6 +7,11 @@ LL | ${concat($lhs, $rhs)} LL | let _another = join!(abc, def); | --------------- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/concat-hygiene.rs:11:9 + | +LL | let abcdef = 1; + | ^^^^^^ = note: this error originates in the macro `join` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/packed/issue-27060.rs b/tests/ui/packed/issue-27060.rs index a0e944caa0b55..7d8be9603b686 100644 --- a/tests/ui/packed/issue-27060.rs +++ b/tests/ui/packed/issue-27060.rs @@ -12,11 +12,11 @@ fn main() { aligned: [0; 32] }; - let _ = &good.data; //~ ERROR reference to packed field - let _ = &good.data2[0]; //~ ERROR reference to packed field + let _ = &good.data; //~ ERROR reference to field of packed struct + let _ = &good.data2[0]; //~ ERROR reference to field of packed struct - let _ = &good.data; //~ ERROR reference to packed field - let _ = &good.data2[0]; //~ ERROR reference to packed field + let _ = &good.data; //~ ERROR reference to field of packed struct + let _ = &good.data2[0]; //~ ERROR reference to field of packed struct let _ = &*good.data; // ok, behind a pointer let _ = &good.aligned; // ok, has align 1 let _ = &good.aligned[2]; // ok, has align 1 diff --git a/tests/ui/packed/issue-27060.stderr b/tests/ui/packed/issue-27060.stderr index 4dc31a283865c..3ede68cf93625 100644 --- a/tests/ui/packed/issue-27060.stderr +++ b/tests/ui/packed/issue-27060.stderr @@ -1,40 +1,40 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-27060.rs:15:13 | LL | let _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-27060.rs:16:13 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-27060.rs:18:13 | LL | let _ = &good.data; | ^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/issue-27060.rs:19:13 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/packed/packed-struct-borrow-element-64bit.rs b/tests/ui/packed/packed-struct-borrow-element-64bit.rs index 81eac07eaa894..59bd71c80e8c3 100644 --- a/tests/ui/packed/packed-struct-borrow-element-64bit.rs +++ b/tests/ui/packed/packed-struct-borrow-element-64bit.rs @@ -10,6 +10,6 @@ struct Foo4C { pub fn main() { let foo = Foo4C { bar: 1, baz: 2 }; - let brw = &foo.baz; //~ERROR reference to packed field is unaligned + let brw = &foo.baz; //~ERROR reference to field of packed struct is unaligned assert_eq!(*brw, 2); } diff --git a/tests/ui/packed/packed-struct-borrow-element-64bit.stderr b/tests/ui/packed/packed-struct-borrow-element-64bit.stderr index a464b18938784..dcf8e7a51f13d 100644 --- a/tests/ui/packed/packed-struct-borrow-element-64bit.stderr +++ b/tests/ui/packed/packed-struct-borrow-element-64bit.stderr @@ -1,10 +1,10 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/packed-struct-borrow-element-64bit.rs:13:15 | LL | let brw = &foo.baz; | ^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 4-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/packed/packed-struct-borrow-element.rs b/tests/ui/packed/packed-struct-borrow-element.rs index 24dadbcec7ca6..d639746e067bd 100644 --- a/tests/ui/packed/packed-struct-borrow-element.rs +++ b/tests/ui/packed/packed-struct-borrow-element.rs @@ -21,10 +21,10 @@ struct Foo4C { pub fn main() { let foo = Foo1 { bar: 1, baz: 2 }; - let brw = &foo.baz; //~ERROR reference to packed field is unaligned + let brw = &foo.baz; //~ERROR reference to field of packed struct is unaligned assert_eq!(*brw, 2); let foo = Foo2 { bar: 1, baz: 2 }; - let brw = &foo.baz; //~ERROR reference to packed field is unaligned + let brw = &foo.baz; //~ERROR reference to field of packed struct is unaligned assert_eq!(*brw, 2); } diff --git a/tests/ui/packed/packed-struct-borrow-element.stderr b/tests/ui/packed/packed-struct-borrow-element.stderr index c1f749d6fbbbd..ccdbb3aedc715 100644 --- a/tests/ui/packed/packed-struct-borrow-element.stderr +++ b/tests/ui/packed/packed-struct-borrow-element.stderr @@ -1,20 +1,20 @@ -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/packed-struct-borrow-element.rs:24:15 | LL | let brw = &foo.baz; | ^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) -error[E0793]: reference to packed field is unaligned +error[E0793]: reference to field of packed struct is unaligned --> $DIR/packed-struct-borrow-element.rs:28:15 | LL | let brw = &foo.baz; | ^^^^^^^^ | - = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses + = note: this struct is at most 2-byte aligned, but the type of this field may require higher alignment = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) diff --git a/tests/ui/packed/packed-union-borrow-element.rs b/tests/ui/packed/packed-union-borrow-element.rs new file mode 100644 index 0000000000000..e39d72b4a45c4 --- /dev/null +++ b/tests/ui/packed/packed-union-borrow-element.rs @@ -0,0 +1,26 @@ +#![allow(dead_code)] +//@ ignore-emscripten weird assertion? + +#[repr(packed)] +#[derive(Clone, Copy)] +struct Foo1(usize); + +#[repr(packed(4))] +#[derive(Clone, Copy)] +struct Foo4(usize); + +#[repr(packed(2))] +union Bar2 { + foo1: Foo1, + foo4: Foo4, +} + +pub fn main() { + let bar = Bar2 { foo1: Foo1(2) }; + let brw = unsafe { &bar.foo1.0 }; //~ERROR reference to field of packed struct is unaligned + assert_eq!(*brw, 2); + + let bar = Bar2 { foo4: Foo4(2) }; + let brw = unsafe { &bar.foo4.0 }; //~ERROR reference to field of packed union is unaligned + assert_eq!(*brw, 2); +} diff --git a/tests/ui/packed/packed-union-borrow-element.stderr b/tests/ui/packed/packed-union-borrow-element.stderr new file mode 100644 index 0000000000000..ace7620d97f72 --- /dev/null +++ b/tests/ui/packed/packed-union-borrow-element.stderr @@ -0,0 +1,23 @@ +error[E0793]: reference to field of packed struct is unaligned + --> $DIR/packed-union-borrow-element.rs:20:24 + | +LL | let brw = unsafe { &bar.foo1.0 }; + | ^^^^^^^^^^^ + | + = note: this struct is 1-byte aligned, but the type of this field may require higher alignment + = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +error[E0793]: reference to field of packed union is unaligned + --> $DIR/packed-union-borrow-element.rs:24:24 + | +LL | let brw = unsafe { &bar.foo4.0 }; + | ^^^^^^^^^^^ + | + = note: this union is at most 2-byte aligned, but the type of this field may require higher alignment + = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0793`. diff --git a/tests/ui/parser/better-expected.stderr b/tests/ui/parser/better-expected.stderr index 4646ce7eff0e0..6b64ec24da48d 100644 --- a/tests/ui/parser/better-expected.stderr +++ b/tests/ui/parser/better-expected.stderr @@ -4,11 +4,10 @@ error: expected `;` or `]`, found `3` LL | let x: [isize 3]; | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | -LL | let x: [isize ;3]; - | + +LL | let x: [isize; 3]; + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/error-pattern-issue-50571.stderr b/tests/ui/parser/issues/error-pattern-issue-50571.stderr index 47457cff461ce..dac4b5309d23a 100644 --- a/tests/ui/parser/issues/error-pattern-issue-50571.stderr +++ b/tests/ui/parser/issues/error-pattern-issue-50571.stderr @@ -4,7 +4,6 @@ error: expected `;` or `]`, found `,` LL | fn foo([a, b]: [i32; 2]) {} | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | LL - fn foo([a, b]: [i32; 2]) {} diff --git a/tests/ui/parser/recover/array-type-no-semi.rs b/tests/ui/parser/recover/array-type-no-semi.rs index 2cc5d979604c7..499d5719d730a 100644 --- a/tests/ui/parser/recover/array-type-no-semi.rs +++ b/tests/ui/parser/recover/array-type-no-semi.rs @@ -14,4 +14,6 @@ fn main() { //~| ERROR attempt to use a non-constant value in a constant [E0435] let e: [i32 5]; //~^ ERROR expected `;` or `]`, found `5` + let f: [i32: 1 - 1]; + //~^ ERROR expected `;` or `]`, found `:` } diff --git a/tests/ui/parser/recover/array-type-no-semi.stderr b/tests/ui/parser/recover/array-type-no-semi.stderr index 82330465144c8..45f39fefe5e34 100644 --- a/tests/ui/parser/recover/array-type-no-semi.stderr +++ b/tests/ui/parser/recover/array-type-no-semi.stderr @@ -4,7 +4,6 @@ error: expected `;` or `]`, found `,` LL | let b: [i32, 5]; | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | LL - let b: [i32, 5]; @@ -19,8 +18,6 @@ LL | let a: [i32, ]; | | | while parsing the type for `a` | help: use `=` if you meant to assign - | - = note: you might have meant to write a slice or array type error: expected `;` or `]`, found `,` --> $DIR/array-type-no-semi.rs:12:16 @@ -28,7 +25,6 @@ error: expected `;` or `]`, found `,` LL | let c: [i32, x]; | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | LL - let c: [i32, x]; @@ -41,11 +37,22 @@ error: expected `;` or `]`, found `5` LL | let e: [i32 5]; | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | -LL | let e: [i32 ;5]; - | + +LL | let e: [i32; 5]; + | + + +error: expected `;` or `]`, found `:` + --> $DIR/array-type-no-semi.rs:17:16 + | +LL | let f: [i32: 1 - 1]; + | ^ expected `;` or `]` + | +help: you might have meant to use `;` as the separator + | +LL - let f: [i32: 1 - 1]; +LL + let f: [i32; 1 - 1]; + | error[E0435]: attempt to use a non-constant value in a constant --> $DIR/array-type-no-semi.rs:12:18 @@ -65,7 +72,7 @@ error[E0423]: expected value, found builtin type `i32` LL | let a: [i32, ]; | ^^^ not a value -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0423, E0435. For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr index f584197c98e8d..3a5254d16b30c 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr @@ -4,11 +4,10 @@ error: expected `;` or `]`, found `*` LL | type v = [isize * 3]; | ^ expected `;` or `]` | - = note: you might have meant to write a slice or array type help: you might have meant to use `;` as the separator | LL - type v = [isize * 3]; -LL + type v = [isize ; 3]; +LL + type v = [isize; 3]; | warning: type `v` should have an upper camel case name diff --git a/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr b/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr index e904b43aaae06..17171ad5c5cc5 100644 --- a/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr +++ b/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr @@ -18,6 +18,11 @@ LL | gen_macro_rules!(); LL | generated!(); | ------------ in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/gen-macro-rules-hygiene.rs:19:13 + | +LL | let local_use = 1; + | ^^^^^^^^^ = note: this error originates in the macro `generated` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `local_def` in this scope diff --git a/tests/ui/proc-macro/mixed-site-span.stderr b/tests/ui/proc-macro/mixed-site-span.stderr index 2d2d55fe148d5..4bb2508416aaa 100644 --- a/tests/ui/proc-macro/mixed-site-span.stderr +++ b/tests/ui/proc-macro/mixed-site-span.stderr @@ -594,6 +594,11 @@ error[E0425]: cannot find value `local_use` in this scope LL | proc_macro_rules!(); | ^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def` | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/mixed-site-span.rs:21:13 + | +LL | let local_use = 1; + | ^^^^^^^^^ = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `local_def` in this scope diff --git a/tests/ui/proc-macro/weird-hygiene.stderr b/tests/ui/proc-macro/weird-hygiene.stderr index 0cfac3f89a045..aa3ef9556eb16 100644 --- a/tests/ui/proc-macro/weird-hygiene.stderr +++ b/tests/ui/proc-macro/weird-hygiene.stderr @@ -7,6 +7,11 @@ LL | Value = (stringify!($tokens + hidden_ident), 1).1 LL | other!(50); | ---------- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/weird-hygiene.rs:44:9 + | +LL | let hidden_ident = "Hello1"; + | ^^^^^^^^^^^^ = note: this error originates in the macro `inner` which comes from the expansion of the macro `other` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `hidden_ident` in this scope @@ -18,6 +23,11 @@ LL | hidden_ident LL | invoke_it!(25); | -------------- in this macro invocation | +help: an identifier with the same name exists, but is not accessible due to macro hygiene + --> $DIR/weird-hygiene.rs:44:9 + | +LL | let hidden_ident = "Hello1"; + | ^^^^^^^^^^^^ = note: this error originates in the macro `invoke_it` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/self/lot-of-references-self.rs b/tests/ui/self/lot-of-references-self.rs new file mode 100644 index 0000000000000..8f3e1a30616b0 --- /dev/null +++ b/tests/ui/self/lot-of-references-self.rs @@ -0,0 +1,28 @@ +struct A ; + +impl A { + fn a(&&self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn b(&&&&&&self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn c(&self) {} + fn d(&mut &self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn e(&mut &&&self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn f(&mut &mut &mut self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn g(&mut & &mut self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references + fn h(&mut & & & && & & self) {} + //~^ ERROR expected one of + //~| HELP `self` should be `self`, `&self` or `&mut self`, consider removing extra references +} + +fn main() {} diff --git a/tests/ui/self/lot-of-references-self.stderr b/tests/ui/self/lot-of-references-self.stderr new file mode 100644 index 0000000000000..41a401eb13102 --- /dev/null +++ b/tests/ui/self/lot-of-references-self.stderr @@ -0,0 +1,86 @@ +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:4:16 + | +LL | fn a(&&self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn a(&&self) {} +LL + fn a(&self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:7:20 + | +LL | fn b(&&&&&&self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn b(&&&&&&self) {} +LL + fn b(&self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:11:20 + | +LL | fn d(&mut &self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn d(&mut &self) {} +LL + fn d(&self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:14:22 + | +LL | fn e(&mut &&&self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn e(&mut &&&self) {} +LL + fn e(&self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:17:29 + | +LL | fn f(&mut &mut &mut self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn f(&mut &mut &mut self) {} +LL + fn f(&mut self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:20:26 + | +LL | fn g(&mut & &mut self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn g(&mut & &mut self) {} +LL + fn g(&mut self) {} + | + +error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` + --> $DIR/lot-of-references-self.rs:23:39 + | +LL | fn h(&mut & & & && & & self) {} + | ^ expected one of 9 possible tokens + | +help: `self` should be `self`, `&self` or `&mut self`, consider removing extra references + | +LL - fn h(&mut & & & && & & self) {} +LL + fn h(& self) {} + | + +error: aborting due to 7 previous errors + diff --git a/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs index a9c2c20ef374a..45f9f6bc5191d 100644 --- a/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs +++ b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs @@ -44,7 +44,7 @@ fn main() { //~^ ERROR ambiguous associated type [E0223] //~| HELP if there were a trait named `Example` with associated type `wrapping` - // this one ideally should suggest `downcast_mut_unchecked` + // this one ideally should suggest `downcast_unchecked_mut` ::downcast::mut_unchecked; //~^ ERROR ambiguous associated type [E0223] //~| HELP if there were a trait named `Example` with associated type `downcast`