diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fc32c4efce56..c009abd729da 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -5,7 +5,7 @@ use rustc_ast::*; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::{self as hir, HirId, IsAnonInPath, PredicateOrigin}; +use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; @@ -1868,7 +1868,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } GenericParamKind::Lifetime => { let lt_id = self.next_node_id(); - let lifetime = self.new_named_lifetime(id, lt_id, ident, IsAnonInPath::No); + let lifetime = + self.new_named_lifetime(id, lt_id, ident, LifetimeSource::Other, ident.into()); hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { lifetime, bounds, @@ -1901,7 +1902,11 @@ impl<'hir> LoweringContext<'_, 'hir> { }), WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => { hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { - lifetime: self.lower_lifetime(lifetime), + lifetime: self.lower_lifetime( + lifetime, + LifetimeSource::Other, + lifetime.ident.into(), + ), bounds: self.lower_param_bounds( bounds, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c40987541f4a..534e85e8bcb9 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -54,8 +54,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, IsAnonInPath, ItemLocalMap, LangItem, ParamName, - TraitCandidate, + self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource, + LifetimeSyntax, ParamName, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -1079,7 +1079,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { itctx: ImplTraitContext, ) -> hir::GenericArg<'hir> { match arg { - ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)), + ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime( + lt, + LifetimeSource::Path { with_angle_brackets: true }, + lt.ident.into(), + )), ast::GenericArg::Type(ty) => { // We cannot just match on `TyKind::Infer` as `(_)` is represented as // `TyKind::Paren(TyKind::Infer)` and should also be lowered to `GenericArg::Infer` @@ -1198,35 +1202,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Ref(region, mt) => { - let region = region.unwrap_or_else(|| { - let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = - self.resolver.get_lifetime_res(t.id) - { - debug_assert_eq!(start.plus(1), end); - start - } else { - self.next_node_id() - }; - let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi(); - Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id } - }); - let lifetime = self.lower_lifetime(®ion); + let lifetime = self.lower_ty_direct_lifetime(t, *region); hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx)) } TyKind::PinnedRef(region, mt) => { - let region = region.unwrap_or_else(|| { - let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = - self.resolver.get_lifetime_res(t.id) - { - debug_assert_eq!(start.plus(1), end); - start - } else { - self.next_node_id() - }; - let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi(); - Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id } - }); - let lifetime = self.lower_lifetime(®ion); + let lifetime = self.lower_ty_direct_lifetime(t, *region); let kind = hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx)); let span = self.lower_span(t.span); let arg = hir::Ty { kind, span, hir_id: self.next_id() }; @@ -1302,7 +1282,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericBound::Outlives(lifetime) => { if lifetime_bound.is_none() { - lifetime_bound = Some(this.lower_lifetime(lifetime)); + lifetime_bound = Some(this.lower_lifetime( + lifetime, + LifetimeSource::Other, + lifetime.ident.into(), + )); } None } @@ -1393,6 +1377,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) } } + fn lower_ty_direct_lifetime( + &mut self, + t: &Ty, + region: Option, + ) -> &'hir hir::Lifetime { + let (region, syntax) = match region { + Some(region) => (region, region.ident.into()), + + None => { + let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = + self.resolver.get_lifetime_res(t.id) + { + debug_assert_eq!(start.plus(1), end); + start + } else { + self.next_node_id() + }; + let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi(); + let region = Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }; + (region, LifetimeSyntax::Hidden) + } + }; + self.lower_lifetime(®ion, LifetimeSource::Reference, syntax) + } + /// Lowers a `ReturnPositionOpaqueTy` (`-> impl Trait`) or a `TypeAliasesOpaqueTy` (`type F = /// impl Trait`): this creates the associated Opaque Type (TAIT) definition and then returns a /// HIR type that references the TAIT. @@ -1474,9 +1483,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { precise_capturing_args: &[PreciseCapturingArg], ) -> &'hir [hir::PreciseCapturingArg<'hir>] { self.arena.alloc_from_iter(precise_capturing_args.iter().map(|arg| match arg { - PreciseCapturingArg::Lifetime(lt) => { - hir::PreciseCapturingArg::Lifetime(self.lower_lifetime(lt)) - } + PreciseCapturingArg::Lifetime(lt) => hir::PreciseCapturingArg::Lifetime( + self.lower_lifetime(lt, LifetimeSource::PreciseCapturing, lt.ident.into()), + ), PreciseCapturingArg::Arg(path, id) => { let [segment] = path.segments.as_slice() else { panic!(); @@ -1739,9 +1748,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::GenericBound<'hir> { match tpb { GenericBound::Trait(p) => hir::GenericBound::Trait(self.lower_poly_trait_ref(p, itctx)), - GenericBound::Outlives(lifetime) => { - hir::GenericBound::Outlives(self.lower_lifetime(lifetime)) - } + GenericBound::Outlives(lifetime) => hir::GenericBound::Outlives(self.lower_lifetime( + lifetime, + LifetimeSource::OutlivesBound, + lifetime.ident.into(), + )), GenericBound::Use(args, span) => hir::GenericBound::Use( self.lower_precise_capturing_args(args), self.lower_span(*span), @@ -1749,12 +1760,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime { - self.new_named_lifetime(l.id, l.id, l.ident, IsAnonInPath::No) + fn lower_lifetime( + &mut self, + l: &Lifetime, + source: LifetimeSource, + syntax: LifetimeSyntax, + ) -> &'hir hir::Lifetime { + self.new_named_lifetime(l.id, l.id, l.ident, source, syntax) } - fn lower_lifetime_anon_in_path(&mut self, id: NodeId, span: Span) -> &'hir hir::Lifetime { - self.new_named_lifetime(id, id, Ident::new(kw::UnderscoreLifetime, span), IsAnonInPath::Yes) + fn lower_lifetime_hidden_in_path( + &mut self, + id: NodeId, + span: Span, + with_angle_brackets: bool, + ) -> &'hir hir::Lifetime { + self.new_named_lifetime( + id, + id, + Ident::new(kw::UnderscoreLifetime, span), + LifetimeSource::Path { with_angle_brackets }, + LifetimeSyntax::Hidden, + ) } #[instrument(level = "debug", skip(self))] @@ -1763,7 +1790,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: NodeId, new_id: NodeId, ident: Ident, - is_anon_in_path: IsAnonInPath, + source: LifetimeSource, + syntax: LifetimeSyntax, ) -> &'hir hir::Lifetime { let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); let res = match res { @@ -1787,17 +1815,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }; - #[cfg(debug_assertions)] - if is_anon_in_path == IsAnonInPath::Yes { - debug_assert_eq!(ident.name, kw::UnderscoreLifetime); - } - debug!(?res); self.arena.alloc(hir::Lifetime::new( self.lower_node_id(new_id), self.lower_ident(ident), res, - is_anon_in_path, + source, + syntax, )) } @@ -2389,7 +2413,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.next_id(), Ident::new(kw::UnderscoreLifetime, self.lower_span(span)), hir::LifetimeKind::ImplicitObjectLifetimeDefault, - IsAnonInPath::No, + LifetimeSource::Other, + LifetimeSyntax::Hidden, ); debug!("elided_dyn_bound: r={:?}", r); self.arena.alloc(r) diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 8dfc11b56b9b..fabe40a9d041 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,10 +1,9 @@ use std::sync::Arc; use rustc_ast::{self as ast, *}; -use rustc_hir as hir; -use rustc_hir::GenericArg; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, GenericArg}; use rustc_middle::{span_bug, ty}; use rustc_session::parse::add_feature_diagnostics; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; @@ -433,23 +432,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Note: these spans are used for diagnostics when they can't be inferred. // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label - let elided_lifetime_span = if generic_args.span.is_empty() { + let (elided_lifetime_span, with_angle_brackets) = if generic_args.span.is_empty() { // If there are no brackets, use the identifier span. // HACK: we use find_ancestor_inside to properly suggest elided spans in paths // originating from macros, since the segment's span might be from a macro arg. - segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span) + (segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), false) } else if generic_args.is_empty() { // If there are brackets, but not generic arguments, then use the opening bracket - generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)) + (generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)), true) } else { // Else use an empty span right after the opening bracket. - generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo() + (generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), true) }; generic_args.args.insert_many( 0, (start..end).map(|id| { - let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span); + let l = self.lower_lifetime_hidden_in_path( + id, + elided_lifetime_span, + with_angle_brackets, + ); GenericArg::Lifetime(l) }), ); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 6959cbd87f1f..62a50c73855f 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -799,7 +799,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere has_bang, Some(*ident), macro_def.body.delim, - ¯o_def.body.tokens.clone(), + ¯o_def.body.tokens, true, sp, ); @@ -1468,7 +1468,7 @@ impl<'a> State<'a> { true, None, m.args.delim, - &m.args.tokens.clone(), + &m.args.tokens, true, m.span(), ); diff --git a/compiler/rustc_codegen_cranelift/example/example.rs b/compiler/rustc_codegen_cranelift/example/example.rs index 1ef2aa5dd8ea..aeb38331edb0 100644 --- a/compiler/rustc_codegen_cranelift/example/example.rs +++ b/compiler/rustc_codegen_cranelift/example/example.rs @@ -1,6 +1,6 @@ #![feature(no_core, unboxed_closures)] #![no_core] -#![allow(dead_code)] +#![allow(dead_code, unnecessary_transmutes)] extern crate mini_core; diff --git a/compiler/rustc_codegen_gcc/example/example.rs b/compiler/rustc_codegen_gcc/example/example.rs index 03470b74d0a1..888fa89201e1 100644 --- a/compiler/rustc_codegen_gcc/example/example.rs +++ b/compiler/rustc_codegen_gcc/example/example.rs @@ -1,6 +1,6 @@ #![feature(no_core, unboxed_closures)] #![no_core] -#![allow(dead_code)] +#![allow(dead_code, unnecessary_transmutes)] extern crate mini_core; @@ -11,11 +11,7 @@ fn abc(a: u8) -> u8 { } fn bcd(b: bool, a: u8) -> u8 { - if b { - a * 2 - } else { - a * 3 - } + if b { a * 2 } else { a * 3 } } fn call() { diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index e8c42d16733e..176fb72dfdc5 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -1,5 +1,4 @@ //! Set and unset common attributes on LLVM values. - use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::DefId; @@ -28,6 +27,22 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[ } } +pub(crate) fn has_attr(llfn: &Value, idx: AttributePlace, attr: AttributeKind) -> bool { + llvm::HasAttributeAtIndex(llfn, idx, attr) +} + +pub(crate) fn has_string_attr(llfn: &Value, name: &str) -> bool { + llvm::HasStringAttribute(llfn, name) +} + +pub(crate) fn remove_from_llfn(llfn: &Value, place: AttributePlace, kind: AttributeKind) { + llvm::RemoveRustEnumAttributeAtIndex(llfn, place, kind); +} + +pub(crate) fn remove_string_attr_from_llfn(llfn: &Value, name: &str) { + llvm::RemoveStringAttrFromFn(llfn, name); +} + /// Get LLVM attribute for the provided inline heuristic. #[inline] fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index a8b49e9552c3..39b3a23e0b1b 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -28,8 +28,9 @@ use crate::back::write::{ use crate::errors::{ DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro, }; +use crate::llvm::AttributePlace::Function; use crate::llvm::{self, build_string}; -use crate::{LlvmCodegenBackend, ModuleLlvm}; +use crate::{LlvmCodegenBackend, ModuleLlvm, SimpleCx, attributes}; /// We keep track of the computed LTO cache keys from the previous /// session to determine which CGUs we can reuse. @@ -584,12 +585,10 @@ fn thin_lto( } } -fn enable_autodiff_settings(ad: &[config::AutoDiff], module: &mut ModuleCodegen) { +fn enable_autodiff_settings(ad: &[config::AutoDiff]) { for &val in ad { + // We intentionally don't use a wildcard, to not forget handling anything new. match val { - config::AutoDiff::PrintModBefore => { - unsafe { llvm::LLVMDumpModule(module.module_llvm.llmod()) }; - } config::AutoDiff::PrintPerf => { llvm::set_print_perf(true); } @@ -603,17 +602,23 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff], module: &mut ModuleCodegen< llvm::set_inline(true); } config::AutoDiff::LooseTypes => { - llvm::set_loose_types(false); + llvm::set_loose_types(true); } config::AutoDiff::PrintSteps => { llvm::set_print(true); } - // We handle this below + // We handle this in the PassWrapper.cpp + config::AutoDiff::PrintPasses => {} + // We handle this in the PassWrapper.cpp + config::AutoDiff::PrintModBefore => {} + // We handle this in the PassWrapper.cpp config::AutoDiff::PrintModAfter => {} - // We handle this below + // We handle this in the PassWrapper.cpp config::AutoDiff::PrintModFinal => {} // This is required and already checked config::AutoDiff::Enable => {} + // We handle this below + config::AutoDiff::NoPostopt => {} } } // This helps with handling enums for now. @@ -647,27 +652,52 @@ pub(crate) fn run_pass_manager( // We then run the llvm_optimize function a second time, to optimize the code which we generated // in the enzyme differentiation pass. let enable_ad = config.autodiff.contains(&config::AutoDiff::Enable); - let stage = - if enable_ad { write::AutodiffStage::DuringAD } else { write::AutodiffStage::PostAD }; + let stage = if thin { + write::AutodiffStage::PreAD + } else { + if enable_ad { write::AutodiffStage::DuringAD } else { write::AutodiffStage::PostAD } + }; if enable_ad { - enable_autodiff_settings(&config.autodiff, module); + enable_autodiff_settings(&config.autodiff); } unsafe { write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?; } - if cfg!(llvm_enzyme) && enable_ad { - // This is the post-autodiff IR, mainly used for testing and educational purposes. - if config.autodiff.contains(&config::AutoDiff::PrintModAfter) { - unsafe { llvm::LLVMDumpModule(module.module_llvm.llmod()) }; + if cfg!(llvm_enzyme) && enable_ad && !thin { + let cx = + SimpleCx::new(module.module_llvm.llmod(), &module.module_llvm.llcx, cgcx.pointer_size); + + for function in cx.get_functions() { + let enzyme_marker = "enzyme_marker"; + if attributes::has_string_attr(function, enzyme_marker) { + // Sanity check: Ensure 'noinline' is present before replacing it. + assert!( + !attributes::has_attr(function, Function, llvm::AttributeKind::NoInline), + "Expected __enzyme function to have 'noinline' before adding 'alwaysinline'" + ); + + attributes::remove_from_llfn(function, Function, llvm::AttributeKind::NoInline); + attributes::remove_string_attr_from_llfn(function, enzyme_marker); + + assert!( + !attributes::has_string_attr(function, enzyme_marker), + "Expected function to not have 'enzyme_marker'" + ); + + let always_inline = llvm::AttributeKind::AlwaysInline.create_attr(cx.llcx); + attributes::apply_to_llfn(function, Function, &[always_inline]); + } } let opt_stage = llvm::OptStage::FatLTO; let stage = write::AutodiffStage::PostAD; - unsafe { - write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?; + if !config.autodiff.contains(&config::AutoDiff::NoPostopt) { + unsafe { + write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?; + } } // This is the final IR, so people should be able to inspect the optimized autodiff output, diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 18d221d232e8..4ac77c8f7f16 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -572,6 +572,10 @@ pub(crate) unsafe fn llvm_optimize( let consider_ad = cfg!(llvm_enzyme) && config.autodiff.contains(&config::AutoDiff::Enable); let run_enzyme = autodiff_stage == AutodiffStage::DuringAD; + let print_before_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModBefore); + let print_after_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModAfter); + let print_passes = config.autodiff.contains(&config::AutoDiff::PrintPasses); + let merge_functions; let unroll_loops; let vectorize_slp; let vectorize_loop; @@ -579,13 +583,20 @@ pub(crate) unsafe fn llvm_optimize( // When we build rustc with enzyme/autodiff support, we want to postpone size-increasing // optimizations until after differentiation. Our pipeline is thus: (opt + enzyme), (full opt). // We therefore have two calls to llvm_optimize, if autodiff is used. + // + // We also must disable merge_functions, since autodiff placeholder/dummy bodies tend to be + // identical. We run opts before AD, so there is a chance that LLVM will merge our dummies. + // In that case, we lack some dummy bodies and can't replace them with the real AD code anymore. + // We then would need to abort compilation. This was especially common in test cases. if consider_ad && autodiff_stage != AutodiffStage::PostAD { + merge_functions = false; unroll_loops = false; vectorize_slp = false; vectorize_loop = false; } else { unroll_loops = opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin; + merge_functions = config.merge_functions; vectorize_slp = config.vectorize_slp; vectorize_loop = config.vectorize_loop; } @@ -663,13 +674,16 @@ pub(crate) unsafe fn llvm_optimize( thin_lto_buffer, config.emit_thin_lto, config.emit_thin_lto_summary, - config.merge_functions, + merge_functions, unroll_loops, vectorize_slp, vectorize_loop, config.no_builtins, config.emit_lifetime_markers, run_enzyme, + print_before_enzyme, + print_after_enzyme, + print_passes, sanitizer_options.as_ref(), pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 27f7f95f100e..04c8118b6160 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -594,6 +594,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value { unsafe { let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED); + let align = align.min(self.cx().tcx.sess.target.max_reliable_alignment()); llvm::LLVMSetAlignment(load, align.bytes() as c_uint); load } @@ -807,6 +808,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { assert_eq!(self.cx.type_kind(self.cx.val_ty(ptr)), TypeKind::Pointer); unsafe { let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr); + let align = align.min(self.cx().tcx.sess.target.max_reliable_alignment()); let align = if flags.contains(MemFlags::UNALIGNED) { 1 } else { align.bytes() as c_uint }; llvm::LLVMSetAlignment(store, align); diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index e7c071d05aa8..c5c13ac097a2 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -361,6 +361,11 @@ fn generate_enzyme_call<'ll>( let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx); attributes::apply_to_llfn(ad_fn, Function, &[attr]); + // We add a made-up attribute just such that we can recognize it after AD to update + // (no)-inline attributes. We'll then also remove this attribute. + let enzyme_marker_attr = llvm::CreateAttrString(cx.llcx, "enzyme_marker"); + attributes::apply_to_llfn(outer_fn, Function, &[enzyme_marker_attr]); + // first, remove all calls from fnc let entry = llvm::LLVMGetFirstBasicBlock(outer_fn); let br = llvm::LLVMRustGetTerminator(entry); @@ -473,7 +478,7 @@ pub(crate) fn differentiate<'ll>( return Err(diag_handler.handle().emit_almost_fatal(AutoDiffWithoutEnable)); } - // Before dumping the module, we want all the TypeTrees to become part of the module. + // Here we replace the placeholder code with the actual autodiff code, which calls Enzyme. for item in diff_items.iter() { let name = item.source.clone(); let fn_def: Option<&llvm::Value> = cx.get_function(&name); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4ec699955189..ed50515b7071 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -698,6 +698,16 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) }) } + + pub(crate) fn get_functions(&self) -> Vec<&'ll Value> { + let mut functions = vec![]; + let mut func = unsafe { llvm::LLVMGetFirstFunction(self.llmod()) }; + while let Some(f) = func { + functions.push(f); + func = unsafe { llvm::LLVMGetNextFunction(f) } + } + functions + } } impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index a9b3bdf7344b..2ad39fc85381 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -19,6 +19,19 @@ unsafe extern "C" { pub(crate) fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool; pub(crate) fn LLVMRustHasAttributeAtIndex(V: &Value, i: c_uint, Kind: AttributeKind) -> bool; pub(crate) fn LLVMRustGetArrayNumElements(Ty: &Type) -> u64; + pub(crate) fn LLVMRustHasFnAttribute( + F: &Value, + Name: *const c_char, + NameLen: libc::size_t, + ) -> bool; + pub(crate) fn LLVMRustRemoveFnAttribute(F: &Value, Name: *const c_char, NameLen: libc::size_t); + pub(crate) fn LLVMGetFirstFunction(M: &Module) -> Option<&Value>; + pub(crate) fn LLVMGetNextFunction(Fn: &Value) -> Option<&Value>; + pub(crate) fn LLVMRustRemoveEnumAttributeAtIndex( + Fn: &Value, + index: c_uint, + kind: AttributeKind, + ); } unsafe extern "C" { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 9ff04f729030..ffb490dcdc22 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2454,6 +2454,9 @@ unsafe extern "C" { DisableSimplifyLibCalls: bool, EmitLifetimeMarkers: bool, RunEnzyme: bool, + PrintBeforeEnzyme: bool, + PrintAfterEnzyme: bool, + PrintPasses: bool, SanitizerOptions: Option<&SanitizerOptions>, PGOGenPath: *const c_char, PGOUsePath: *const c_char, diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 6ca81c651ed4..d14aab060731 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -41,6 +41,32 @@ pub(crate) fn AddFunctionAttributes<'ll>( } } +pub(crate) fn HasAttributeAtIndex<'ll>( + llfn: &'ll Value, + idx: AttributePlace, + kind: AttributeKind, +) -> bool { + unsafe { LLVMRustHasAttributeAtIndex(llfn, idx.as_uint(), kind) } +} + +pub(crate) fn HasStringAttribute<'ll>(llfn: &'ll Value, name: &str) -> bool { + unsafe { LLVMRustHasFnAttribute(llfn, name.as_c_char_ptr(), name.len()) } +} + +pub(crate) fn RemoveStringAttrFromFn<'ll>(llfn: &'ll Value, name: &str) { + unsafe { LLVMRustRemoveFnAttribute(llfn, name.as_c_char_ptr(), name.len()) } +} + +pub(crate) fn RemoveRustEnumAttributeAtIndex( + llfn: &Value, + place: AttributePlace, + kind: AttributeKind, +) { + unsafe { + LLVMRustRemoveEnumAttributeAtIndex(llfn, place.as_uint(), kind); + } +} + pub(crate) fn AddCallSiteAttributes<'ll>( callsite: &'ll Value, idx: AttributePlace, diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index b89ce90d1a1d..169036f51529 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -128,6 +128,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { (**self).borrow().llcx } + pub(crate) fn llmod(&self) -> &'ll llvm::Module { + (**self).borrow().llmod + } + pub(crate) fn isize_ty(&self) -> &'ll Type { (**self).borrow().isize_ty } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8de68925cabb..f0c47ac41e8a 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2015,6 +2015,12 @@ fn add_linked_symbol_object( file.set_mangling(object::write::Mangling::None); } + if file.format() == object::BinaryFormat::MachO { + // Divide up the sections into sub-sections via symbols for dead code stripping. + // Without this flag, unused `#[no_mangle]` or `#[used]` cannot be discard on MachO targets. + file.set_subsections_via_symbols(); + } + // ld64 requires a relocation to load undefined symbols, see below. // Not strictly needed if linking with lld, but might as well do it there too. let ld64_section_helper = if file.format() == object::BinaryFormat::MachO { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 4ca317e3a1e5..40c63f2b250f 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -158,6 +158,31 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_op(&val, dest)?; } + sym::fadd_algebraic + | sym::fsub_algebraic + | sym::fmul_algebraic + | sym::fdiv_algebraic + | sym::frem_algebraic => { + let a = self.read_immediate(&args[0])?; + let b = self.read_immediate(&args[1])?; + + let op = match intrinsic_name { + sym::fadd_algebraic => BinOp::Add, + sym::fsub_algebraic => BinOp::Sub, + sym::fmul_algebraic => BinOp::Mul, + sym::fdiv_algebraic => BinOp::Div, + sym::frem_algebraic => BinOp::Rem, + + _ => bug!(), + }; + + let res = self.binary_op(op, &a, &b)?; + // `binary_op` already called `generate_nan` if needed. + + // FIXME: Miri should add some non-determinism to the result here to catch any dependences on exact computations. This has previously been done, but the behaviour was removed as part of constification. + self.write_immediate(*res, dest)?; + } + sym::ctpop | sym::cttz | sym::cttz_nonzero diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d02c767ea677..2f8a85342478 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -36,43 +36,110 @@ pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::{FnKind, VisitorExt}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] -pub enum IsAnonInPath { - No, - Yes, +pub enum LifetimeSource { + /// E.g. `&Type`, `&'_ Type`, `&'a Type`, `&mut Type`, `&'_ mut Type`, `&'a mut Type` + Reference, + + /// E.g. `ContainsLifetime`, `ContainsLifetime<'_>`, `ContainsLifetime<'a>` + Path { + /// - true for `ContainsLifetime<'_>`, `ContainsLifetime<'a>`, + /// `ContainsLifetime<'_, T>`, `ContainsLifetime<'a, T>` + /// - false for `ContainsLifetime` + with_angle_brackets: bool, + }, + + /// E.g. `impl Trait + '_`, `impl Trait + 'a` + OutlivesBound, + + /// E.g. `impl Trait + use<'_>`, `impl Trait + use<'a>` + PreciseCapturing, + + /// Other usages which have not yet been categorized. Feel free to + /// add new sources that you find useful. + /// + /// Some non-exhaustive examples: + /// - `where T: 'a` + /// - `fn(_: dyn Trait + 'a)` + Other, } -/// A lifetime. The valid field combinations are non-obvious. The following -/// example shows some of them. See also the comments on `LifetimeKind`. +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] +pub enum LifetimeSyntax { + /// E.g. `&Type`, `ContainsLifetime` + Hidden, + + /// E.g. `&'_ Type`, `ContainsLifetime<'_>`, `impl Trait + '_`, `impl Trait + use<'_>` + Anonymous, + + /// E.g. `&'a Type`, `ContainsLifetime<'a>`, `impl Trait + 'a`, `impl Trait + use<'a>` + Named, +} + +impl From for LifetimeSyntax { + fn from(ident: Ident) -> Self { + let name = ident.name; + + if name == kw::Empty { + unreachable!("A lifetime name should never be empty"); + } else if name == kw::UnderscoreLifetime { + LifetimeSyntax::Anonymous + } else { + debug_assert!(name.as_str().starts_with('\'')); + LifetimeSyntax::Named + } + } +} + +/// A lifetime. The valid field combinations are non-obvious and not all +/// combinations are possible. The following example shows some of +/// them. See also the comments on `LifetimeKind` and `LifetimeSource`. +/// /// ``` /// #[repr(C)] -/// struct S<'a>(&'a u32); // res=Param, name='a, IsAnonInPath::No +/// struct S<'a>(&'a u32); // res=Param, name='a, source=Reference, syntax=Named /// unsafe extern "C" { -/// fn f1(s: S); // res=Param, name='_, IsAnonInPath::Yes -/// fn f2(s: S<'_>); // res=Param, name='_, IsAnonInPath::No -/// fn f3<'a>(s: S<'a>); // res=Param, name='a, IsAnonInPath::No +/// fn f1(s: S); // res=Param, name='_, source=Path, syntax=Hidden +/// fn f2(s: S<'_>); // res=Param, name='_, source=Path, syntax=Anonymous +/// fn f3<'a>(s: S<'a>); // res=Param, name='a, source=Path, syntax=Named /// } /// -/// struct St<'a> { x: &'a u32 } // res=Param, name='a, IsAnonInPath::No +/// struct St<'a> { x: &'a u32 } // res=Param, name='a, source=Reference, syntax=Named /// fn f() { -/// _ = St { x: &0 }; // res=Infer, name='_, IsAnonInPath::Yes -/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, IsAnonInPath::No +/// _ = St { x: &0 }; // res=Infer, name='_, source=Path, syntax=Hidden +/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, source=Path, syntax=Anonymous /// } /// -/// struct Name<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No -/// const A: Name = Name("a"); // res=Static, name='_, IsAnonInPath::Yes -/// const B: &str = ""; // res=Static, name='_, IsAnonInPath::No -/// static C: &'_ str = ""; // res=Static, name='_, IsAnonInPath::No -/// static D: &'static str = ""; // res=Static, name='static, IsAnonInPath::No +/// struct Name<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named +/// const A: Name = Name("a"); // res=Static, name='_, source=Path, syntax=Hidden +/// const B: &str = ""; // res=Static, name='_, source=Reference, syntax=Hidden +/// static C: &'_ str = ""; // res=Static, name='_, source=Reference, syntax=Anonymous +/// static D: &'static str = ""; // res=Static, name='static, source=Reference, syntax=Named /// /// trait Tr {} -/// fn tr(_: Box) {} // res=ImplicitObjectLifetimeDefault, name='_, IsAnonInPath::No +/// fn tr(_: Box) {} // res=ImplicitObjectLifetimeDefault, name='_, source=Other, syntax=Hidden +/// +/// fn capture_outlives<'a>() -> +/// impl FnOnce() + 'a // res=Param, ident='a, source=OutlivesBound, syntax=Named +/// { +/// || {} +/// } +/// +/// fn capture_precise<'a>() -> +/// impl FnOnce() + use<'a> // res=Param, ident='a, source=PreciseCapturing, syntax=Named +/// { +/// || {} +/// } /// /// // (commented out because these cases trigger errors) -/// // struct S1<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No -/// // struct S2(S1); // res=Error, name='_, IsAnonInPath::Yes -/// // struct S3(S1<'_>); // res=Error, name='_, IsAnonInPath::No -/// // struct S4(S1<'a>); // res=Error, name='a, IsAnonInPath::No +/// // struct S1<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named +/// // struct S2(S1); // res=Error, name='_, source=Path, syntax=Hidden +/// // struct S3(S1<'_>); // res=Error, name='_, source=Path, syntax=Anonymous +/// // struct S4(S1<'a>); // res=Error, name='a, source=Path, syntax=Named /// ``` +/// +/// Some combinations that cannot occur are `LifetimeSyntax::Hidden` with +/// `LifetimeSource::OutlivesBound` or `LifetimeSource::PreciseCapturing` +/// — there's no way to "elide" these lifetimes. #[derive(Debug, Copy, Clone, HashStable_Generic)] pub struct Lifetime { #[stable_hasher(ignore)] @@ -86,9 +153,13 @@ pub struct Lifetime { /// Semantics of this lifetime. pub kind: LifetimeKind, - /// Is the lifetime anonymous and in a path? Used only for error - /// suggestions. See `Lifetime::suggestion` for example use. - pub is_anon_in_path: IsAnonInPath, + /// The context in which the lifetime occurred. See `Lifetime::suggestion` + /// for example use. + pub source: LifetimeSource, + + /// The syntax that the user used to declare this lifetime. See + /// `Lifetime::suggestion` for example use. + pub syntax: LifetimeSyntax, } #[derive(Debug, Copy, Clone, HashStable_Generic)] @@ -185,9 +256,10 @@ impl Lifetime { hir_id: HirId, ident: Ident, kind: LifetimeKind, - is_anon_in_path: IsAnonInPath, + source: LifetimeSource, + syntax: LifetimeSyntax, ) -> Lifetime { - let lifetime = Lifetime { hir_id, ident, kind, is_anon_in_path }; + let lifetime = Lifetime { hir_id, ident, kind, source, syntax }; // Sanity check: elided lifetimes form a strict subset of anonymous lifetimes. #[cfg(debug_assertions)] @@ -209,23 +281,44 @@ impl Lifetime { self.ident.name == kw::UnderscoreLifetime } + pub fn is_syntactically_hidden(&self) -> bool { + matches!(self.syntax, LifetimeSyntax::Hidden) + } + + pub fn is_syntactically_anonymous(&self) -> bool { + matches!(self.syntax, LifetimeSyntax::Anonymous) + } + + pub fn is_static(&self) -> bool { + self.kind == LifetimeKind::Static + } + pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) { + use LifetimeSource::*; + use LifetimeSyntax::*; + debug_assert!(new_lifetime.starts_with('\'')); - match (self.is_anon_in_path, self.ident.span.is_empty()) { + match (self.syntax, self.source) { + // The user wrote `'a` or `'_`. + (Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")), + // The user wrote `Path`, and omitted the `'_,`. - (IsAnonInPath::Yes, true) => (self.ident.span, format!("{new_lifetime}, ")), + (Hidden, Path { with_angle_brackets: true }) => { + (self.ident.span, format!("{new_lifetime}, ")) + } // The user wrote `Path` and omitted the `<'_>`. - (IsAnonInPath::Yes, false) => { + (Hidden, Path { with_angle_brackets: false }) => { (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")) } // The user wrote `&type` or `&mut type`. - (IsAnonInPath::No, true) => (self.ident.span, format!("{new_lifetime} ")), + (Hidden, Reference) => (self.ident.span, format!("{new_lifetime} ")), - // The user wrote `'a` or `'_`. - (IsAnonInPath::No, false) => (self.ident.span, format!("{new_lifetime}")), + (Hidden, source) => { + unreachable!("can't suggest for a hidden lifetime of {source:?}") + } } } } diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index fcd0eafa4613..18f8c523f9d3 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -58,7 +58,8 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) { hir_id: HirId::INVALID, ident: Ident::new(sym::name, DUMMY_SP), kind: LifetimeKind::Static, - is_anon_in_path: IsAnonInPath::No, + source: LifetimeSource::Other, + syntax: LifetimeSyntax::Hidden, } }, syntax, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7e7079f09ada..7520782930a2 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -759,22 +759,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Byte string patterns behave the same way as array patterns // They can denote both statically and dynamically-sized byte arrays. + // Additionally, when `deref_patterns` is enabled, byte string literal patterns may have + // types `[u8]` or `[u8; N]`, in order to type, e.g., `deref!(b"..."): Vec`. let mut pat_ty = ty; if let hir::PatExprKind::Lit { lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, .. } = lt.kind { + let tcx = self.tcx; let expected = self.structurally_resolve_type(span, expected); - if let ty::Ref(_, inner_ty, _) = *expected.kind() - && self.try_structurally_resolve_type(span, inner_ty).is_slice() - { - let tcx = self.tcx; - trace!(?lt.hir_id.local_id, "polymorphic byte string lit"); - pat_ty = - Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8)); + match *expected.kind() { + // Allow `b"...": &[u8]` + ty::Ref(_, inner_ty, _) + if self.try_structurally_resolve_type(span, inner_ty).is_slice() => + { + trace!(?lt.hir_id.local_id, "polymorphic byte string lit"); + pat_ty = Ty::new_imm_ref( + tcx, + tcx.lifetimes.re_static, + Ty::new_slice(tcx, tcx.types.u8), + ); + } + // Allow `b"...": [u8; 3]` for `deref_patterns` + ty::Array(..) if tcx.features().deref_patterns() => { + pat_ty = match *ty.kind() { + ty::Ref(_, inner_ty, _) => inner_ty, + _ => span_bug!(span, "found byte string literal with non-ref type {ty:?}"), + } + } + // Allow `b"...": [u8]` for `deref_patterns` + ty::Slice(..) if tcx.features().deref_patterns() => { + pat_ty = Ty::new_slice(tcx, tcx.types.u8); + } + // Otherwise, `b"...": &[u8; 3]` + _ => {} } } + // When `deref_patterns` is enabled, in order to allow `deref!("..."): String`, we allow + // string literal patterns to have type `str`. This is accounted for when lowering to MIR. + if self.tcx.features().deref_patterns() + && let hir::PatExprKind::Lit { + lit: Spanned { node: ast::LitKind::Str(..), .. }, .. + } = lt.kind + && self.try_structurally_resolve_type(span, expected).is_str() + { + pat_ty = self.tcx.types.str_; + } + if self.tcx.features().string_deref_patterns() && let hir::PatExprKind::Lit { lit: Spanned { node: ast::LitKind::Str(..), .. }, .. diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 3b7c23a1fa3f..7b6a723b0b40 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,7 +1,9 @@ use std::iter; use std::ops::ControlFlow; -use rustc_abi::{BackendRepr, TagEncoding, VariantIdx, Variants, WrappingRange}; +use rustc_abi::{ + BackendRepr, Integer, IntegerType, TagEncoding, VariantIdx, Variants, WrappingRange, +}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; use rustc_hir::intravisit::VisitorExt; @@ -1243,6 +1245,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } + if let Some(IntegerType::Fixed(Integer::I128, _)) = def.repr().int { + return FfiUnsafe { + ty, + reason: fluent::lint_improper_ctypes_128bit, + help: None, + }; + } + use improper_ctypes::check_non_exhaustive_variant; let non_exhaustive = def.variant_list_has_applicable_non_exhaustive(); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a49eb76734fb..17d501c5730b 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -117,6 +117,7 @@ declare_lint_pass! { UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNNAMEABLE_TEST_ITEMS, UNNAMEABLE_TYPES, + UNNECESSARY_TRANSMUTES, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, UNSAFE_ATTR_OUTSIDE_UNSAFE, @@ -4909,6 +4910,30 @@ declare_lint! { "detects pointer to integer transmutes in const functions and associated constants", } +declare_lint! { + /// The `unnecessary_transmutes` lint detects transmutations that have safer alternatives. + /// + /// ### Example + /// + /// ```rust + /// fn bytes_at_home(x: [u8; 4]) -> u32 { + /// unsafe { std::mem::transmute(x) } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Using an explicit method is preferable over calls to + /// [`transmute`](https://doc.rust-lang.org/std/mem/fn.transmute.html) as + /// they more clearly communicate the intent, are easier to review, and + /// are less likely to accidentally result in unsoundness. + pub UNNECESSARY_TRANSMUTES, + Warn, + "detects transmutes that are shadowed by std methods" +} + declare_lint! { /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, /// that runs a custom `Drop` destructor. diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index e02c80c50b14..8bee051dd4c3 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -14,6 +14,7 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Verifier.h" +#include "llvm/IRPrinter/IRPrintingPasses.h" #include "llvm/LTO/LTO.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/TargetRegistry.h" @@ -703,7 +704,8 @@ extern "C" LLVMRustResult LLVMRustOptimize( bool LintIR, LLVMRustThinLTOBuffer **ThinLTOBufferRef, bool EmitThinLTO, bool EmitThinLTOSummary, bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize, bool DisableSimplifyLibCalls, - bool EmitLifetimeMarkers, bool RunEnzyme, + bool EmitLifetimeMarkers, bool RunEnzyme, bool PrintBeforeEnzyme, + bool PrintAfterEnzyme, bool PrintPasses, LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath, const char *PGOUsePath, bool InstrumentCoverage, const char *InstrProfileOutput, const char *PGOSampleUsePath, @@ -1048,14 +1050,38 @@ extern "C" LLVMRustResult LLVMRustOptimize( // now load "-enzyme" pass: #ifdef ENZYME if (RunEnzyme) { - registerEnzymeAndPassPipeline(PB, true); + + if (PrintBeforeEnzyme) { + // Handle the Rust flag `-Zautodiff=PrintModBefore`. + std::string Banner = "Module before EnzymeNewPM"; + MPM.addPass(PrintModulePass(outs(), Banner, true, false)); + } + + registerEnzymeAndPassPipeline(PB, false); if (auto Err = PB.parsePassPipeline(MPM, "enzyme")) { std::string ErrMsg = toString(std::move(Err)); LLVMRustSetLastError(ErrMsg.c_str()); return LLVMRustResult::Failure; } + + if (PrintAfterEnzyme) { + // Handle the Rust flag `-Zautodiff=PrintModAfter`. + std::string Banner = "Module after EnzymeNewPM"; + MPM.addPass(PrintModulePass(outs(), Banner, true, false)); + } } #endif + if (PrintPasses) { + // Print all passes from the PM: + std::string Pipeline; + raw_string_ostream SOS(Pipeline); + MPM.printPipeline(SOS, [&PIC](StringRef ClassName) { + auto PassName = PIC.getPassNameForClassName(ClassName); + return PassName.empty() ? ClassName : PassName; + }); + outs() << Pipeline; + outs() << "\n"; + } // Upgrade all calls to old intrinsics first. for (Module::iterator I = TheModule->begin(), E = TheModule->end(); I != E;) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 5f0e4d745e83..72369ab7b692 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -973,6 +973,27 @@ extern "C" LLVMMetadataRef LLVMRustDIGetInstMetadata(LLVMValueRef x) { return nullptr; } +extern "C" void +LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef F, size_t index, + LLVMRustAttributeKind RustAttr) { + LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr)); +} + +extern "C" bool LLVMRustHasFnAttribute(LLVMValueRef F, const char *Name, + size_t NameLen) { + if (auto *Fn = dyn_cast(unwrap(F))) { + return Fn->hasFnAttribute(StringRef(Name, NameLen)); + } + return false; +} + +extern "C" void LLVMRustRemoveFnAttribute(LLVMValueRef Fn, const char *Name, + size_t NameLen) { + if (auto *F = dyn_cast(unwrap(Fn))) { + F->removeFnAttr(StringRef(Name, NameLen)); + } +} + extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind, LLVMMetadataRef MD) { unwrap(Global)->addMetadata(Kind, *unwrap(MD)); diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index 91398f1a9da9..55228248188e 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -55,8 +55,7 @@ use synstructure::Structure; /// /// See rustc dev guide for more examples on using the `#[derive(Diagnostic)]`: /// -pub(super) fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream { - s.underscore_const(true); +pub(super) fn diagnostic_derive(s: Structure<'_>) -> TokenStream { DiagnosticDerive::new(s).into_tokens() } @@ -102,8 +101,7 @@ pub(super) fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream { /// /// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`: /// -pub(super) fn lint_diagnostic_derive(mut s: Structure<'_>) -> TokenStream { - s.underscore_const(true); +pub(super) fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { LintDiagnosticDerive::new(s).into_tokens() } @@ -153,7 +151,6 @@ pub(super) fn lint_diagnostic_derive(mut s: Structure<'_>) -> TokenStream { /// /// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident }); /// ``` -pub(super) fn subdiagnostic_derive(mut s: Structure<'_>) -> TokenStream { - s.underscore_const(true); +pub(super) fn subdiagnostic_derive(s: Structure<'_>) -> TokenStream { SubdiagnosticDerive::new().into_tokens(s) } diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs index 6b3210cad7be..a6396ba687d1 100644 --- a/compiler/rustc_macros/src/hash_stable.rs +++ b/compiler/rustc_macros/src/hash_stable.rs @@ -74,8 +74,6 @@ fn hash_stable_derive_with_mode( HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX), }; - s.underscore_const(true); - // no_context impl is able to derive by-field, which is closer to a perfect derive. s.add_bounds(match mode { HashStableMode::Normal | HashStableMode::Generic => synstructure::AddBounds::Generics, diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs index 341447f7e6f2..03ea396a42c7 100644 --- a/compiler/rustc_macros/src/lift.rs +++ b/compiler/rustc_macros/src/lift.rs @@ -4,7 +4,6 @@ use syn::parse_quote; pub(super) fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { s.add_bounds(synstructure::AddBounds::Generics); s.bind_with(|_| synstructure::BindStyle::Move); - s.underscore_const(true); let tcx: syn::Lifetime = parse_quote!('tcx); let newtcx: syn::GenericParam = parse_quote!('__lifted); diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 673e6cd618ff..c7aaaf0da467 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -12,7 +12,6 @@ pub(super) fn type_decodable_derive( let decoder_ty = quote! { __D }; s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_middle::ty::codec::TyDecoder<'tcx> }); s.add_bounds(synstructure::AddBounds::Fields); - s.underscore_const(true); decodable_body(s, decoder_ty) } @@ -26,7 +25,6 @@ pub(super) fn meta_decodable_derive( s.add_impl_generic(parse_quote! { '__a }); let decoder_ty = quote! { DecodeContext<'__a, 'tcx> }; s.add_bounds(synstructure::AddBounds::Generics); - s.underscore_const(true); decodable_body(s, decoder_ty) } @@ -35,7 +33,6 @@ pub(super) fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro let decoder_ty = quote! { __D }; s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_span::SpanDecoder }); s.add_bounds(synstructure::AddBounds::Generics); - s.underscore_const(true); decodable_body(s, decoder_ty) } @@ -46,13 +43,12 @@ pub(super) fn decodable_nocontext_derive( let decoder_ty = quote! { __D }; s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_serialize::Decoder }); s.add_bounds(synstructure::AddBounds::Fields); - s.underscore_const(true); decodable_body(s, decoder_ty) } fn decodable_body( - mut s: synstructure::Structure<'_>, + s: synstructure::Structure<'_>, decoder_ty: TokenStream, ) -> proc_macro2::TokenStream { if let syn::Data::Union(_) = s.ast().data { @@ -98,7 +94,6 @@ fn decodable_body( } } }; - s.underscore_const(true); s.bound_impl( quote!(::rustc_serialize::Decodable<#decoder_ty>), @@ -133,7 +128,6 @@ pub(super) fn type_encodable_derive( } s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_middle::ty::codec::TyEncoder<'tcx> }); s.add_bounds(synstructure::AddBounds::Fields); - s.underscore_const(true); encodable_body(s, encoder_ty, false) } @@ -147,7 +141,6 @@ pub(super) fn meta_encodable_derive( s.add_impl_generic(parse_quote! { '__a }); let encoder_ty = quote! { EncodeContext<'__a, 'tcx> }; s.add_bounds(synstructure::AddBounds::Generics); - s.underscore_const(true); encodable_body(s, encoder_ty, true) } @@ -156,7 +149,6 @@ pub(super) fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro let encoder_ty = quote! { __E }; s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_span::SpanEncoder }); s.add_bounds(synstructure::AddBounds::Generics); - s.underscore_const(true); encodable_body(s, encoder_ty, false) } @@ -167,7 +159,6 @@ pub(super) fn encodable_nocontext_derive( let encoder_ty = quote! { __E }; s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder }); s.add_bounds(synstructure::AddBounds::Fields); - s.underscore_const(true); encodable_body(s, encoder_ty, false) } @@ -181,7 +172,6 @@ fn encodable_body( panic!("cannot derive on union") } - s.underscore_const(true); s.bind_with(|binding| { // Handle the lack of a blanket reference impl. if let syn::Type::Reference(_) = binding.ast().ty { diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 85051311bee9..91b747f18569 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -6,8 +6,6 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m panic!("cannot derive on union") } - s.underscore_const(true); - if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { s.add_impl_generic(parse_quote! { 'tcx }); } diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs index fb37e1a39edb..f99c5113a605 100644 --- a/compiler/rustc_macros/src/type_visitable.rs +++ b/compiler/rustc_macros/src/type_visitable.rs @@ -8,8 +8,6 @@ pub(super) fn type_visitable_derive( panic!("cannot derive on union") } - s.underscore_const(true); - // ignore fields with #[type_visitable(ignore)] s.filter(|bi| { let mut ignored = false; diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 73cc3c86e22f..210b9cce581f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -146,6 +146,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut place = place; let mut block = block; match ty.kind() { + ty::Str => { + // String literal patterns may have type `str` if `deref_patterns` is + // enabled, in order to allow `deref!("..."): String`. In this case, `value` + // is of type `&str`, so we compare it to `&place`. + if !tcx.features().deref_patterns() { + span_bug!( + test.span, + "matching on `str` went through without enabling deref_patterns" + ); + } + let re_erased = tcx.lifetimes.re_erased; + let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_); + let ref_place = self.temp(ref_str_ty, test.span); + // `let ref_place: &str = &place;` + self.cfg.push_assign( + block, + self.source_info(test.span), + ref_place, + Rvalue::Ref(re_erased, BorrowKind::Shared, place), + ); + place = ref_place; + ty = ref_str_ty; + } ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => { if !tcx.features().string_deref_patterns() { span_bug!( diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index b3210813703c..b4fa55e1c1fd 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -37,13 +37,23 @@ pub(crate) fn lit_to_const<'tcx>( let str_bytes = s.as_str().as_bytes(); ty::ValTree::from_raw_bytes(tcx, str_bytes) } + (ast::LitKind::Str(s, _), ty::Str) if tcx.features().deref_patterns() => { + // String literal patterns may have type `str` if `deref_patterns` is enabled, in order + // to allow `deref!("..."): String`. + let str_bytes = s.as_str().as_bytes(); + ty::ValTree::from_raw_bytes(tcx, str_bytes) + } (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) - if matches!(inner_ty.kind(), ty::Slice(_)) => + if matches!(inner_ty.kind(), ty::Slice(_) | ty::Array(..)) => { let bytes = data as &[u8]; ty::ValTree::from_raw_bytes(tcx, bytes) } - (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { + (ast::LitKind::ByteStr(data, _), ty::Slice(_) | ty::Array(..)) + if tcx.features().deref_patterns() => + { + // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is + // enabled, in order to allow, e.g., `deref!(b"..."): Vec`. let bytes = data as &[u8]; ty::ValTree::from_raw_bytes(tcx, bytes) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index a40001bf7455..b7d203e3cd78 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -280,6 +280,16 @@ impl<'tcx> ConstToPat<'tcx> { slice: None, suffix: Box::new([]), }, + ty::Str => { + // String literal patterns may have type `str` if `deref_patterns` is enabled, in + // order to allow `deref!("..."): String`. Since we need a `&str` for the comparison + // when lowering to MIR in `Builder::perform_test`, treat the constant as a `&str`. + // This works because `str` and `&str` have the same valtree representation. + let ref_str_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty); + PatKind::Constant { + value: mir::Const::Ty(ref_str_ty, ty::Const::new_value(tcx, cv, ref_str_ty)), + } + } ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // `&str` is represented as a valtree, let's keep using this // optimization for now. diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index 5628f4c9381b..a1264471a2df 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -84,3 +84,4 @@ mir_transform_undefined_transmute = pointers cannot be transmuted to integers du .help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored +mir_transform_unnecessary_transmute = unnecessary transmute diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index b70cca148407..5115583f37c0 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -1,3 +1,4 @@ +use rustc_abi::Align; use rustc_index::IndexVec; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::PlaceContext; @@ -11,10 +12,6 @@ pub(super) struct CheckAlignment; impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { fn is_enabled(&self, sess: &Session) -> bool { - // FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows - if sess.target.llvm_target == "i686-pc-windows-msvc" { - return false; - } sess.ub_checks() } @@ -87,6 +84,33 @@ fn insert_alignment_check<'tcx>( ))), }); + // If this target does not have reliable alignment, further limit the mask by anding it with + // the mask for the highest reliable alignment. + #[allow(irrefutable_let_patterns)] + if let max_align = tcx.sess.target.max_reliable_alignment() + && max_align < Align::MAX + { + let max_mask = max_align.bytes() - 1; + let max_mask = Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::Val( + ConstValue::Scalar(Scalar::from_target_usize(max_mask, &tcx)), + tcx.types.usize, + ), + })); + stmts.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + alignment_mask, + Rvalue::BinaryOp( + BinOp::BitAnd, + Box::new((Operand::Copy(alignment_mask), max_mask)), + ), + ))), + }); + } + // BitAnd the alignment mask with the pointer let alignment_bits = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); diff --git a/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs b/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs new file mode 100644 index 000000000000..8be782dcbf0a --- /dev/null +++ b/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs @@ -0,0 +1,100 @@ +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{Body, Location, Operand, Terminator, TerminatorKind}; +use rustc_middle::ty::*; +use rustc_session::lint::builtin::UNNECESSARY_TRANSMUTES; +use rustc_span::source_map::Spanned; +use rustc_span::{Span, sym}; + +use crate::errors::UnnecessaryTransmute as Error; + +/// Check for transmutes that overlap with stdlib methods. +/// For example, transmuting `[u8; 4]` to `u32`. +pub(super) struct CheckUnnecessaryTransmutes; + +impl<'tcx> crate::MirLint<'tcx> for CheckUnnecessaryTransmutes { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let mut checker = UnnecessaryTransmuteChecker { body, tcx }; + checker.visit_body(body); + } +} + +struct UnnecessaryTransmuteChecker<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, +} + +impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> { + fn is_unnecessary_transmute( + &self, + function: &Operand<'tcx>, + arg: String, + span: Span, + ) -> Option { + let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder(); + let [input] = fn_sig.inputs() else { return None }; + + let err = |sugg| Error { span, sugg, help: None }; + + Some(match (input.kind(), fn_sig.output().kind()) { + // dont check the length; transmute does that for us. + // [u8; _] => primitive + (Array(t, _), Uint(_) | Float(_) | Int(_)) if *t.kind() == Uint(UintTy::U8) => Error { + sugg: format!("{}::from_ne_bytes({arg})", fn_sig.output()), + help: Some( + "there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order", + ), + span, + }, + // primitive => [u8; _] + (Uint(_) | Float(_) | Int(_), Array(t, _)) if *t.kind() == Uint(UintTy::U8) => Error { + sugg: format!("{input}::to_ne_bytes({arg})"), + help: Some( + "there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order", + ), + span, + }, + // char → u32 + (Char, Uint(UintTy::U32)) => err(format!("u32::from({arg})")), + // u32 → char + (Uint(UintTy::U32), Char) => Error { + sugg: format!("char::from_u32_unchecked({arg})"), + help: Some("consider `char::from_u32(…).unwrap()`"), + span, + }, + // uNN → iNN + (Uint(ty), Int(_)) => err(format!("{}::cast_signed({arg})", ty.name_str())), + // iNN → uNN + (Int(ty), Uint(_)) => err(format!("{}::cast_unsigned({arg})", ty.name_str())), + // fNN → uNN + (Float(ty), Uint(..)) => err(format!("{}::to_bits({arg})", ty.name_str())), + // uNN → fNN + (Uint(_), Float(ty)) => err(format!("{}::from_bits({arg})", ty.name_str())), + // bool → { x8 } + (Bool, Int(..) | Uint(..)) => err(format!("({arg}) as {}", fn_sig.output())), + // u8 → bool + (Uint(_), Bool) => err(format!("({arg} == 1)")), + _ => return None, + }) + } +} + +impl<'tcx> Visitor<'tcx> for UnnecessaryTransmuteChecker<'_, 'tcx> { + // Check each block's terminator for calls to pointer to integer transmutes + // in const functions or associated constants and emit a lint. + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + if let TerminatorKind::Call { func, args, .. } = &terminator.kind + && let [Spanned { span: arg, .. }] = **args + && let Some((func_def_id, _)) = func.const_fn_def() + && self.tcx.is_intrinsic(func_def_id, sym::transmute) + && let span = self.body.source_info(location).span + && let Some(lint) = self.is_unnecessary_transmute( + func, + self.tcx.sess.source_map().span_to_snippet(arg).expect("ok"), + span, + ) + && let Some(hir_id) = terminator.source_info.scope.lint_root(&self.body.source_scopes) + { + self.tcx.emit_node_span_lint(UNNECESSARY_TRANSMUTES, hir_id, span, lint); + } + } +} diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 29698b0c2e44..5b03a4987ed7 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -158,6 +158,26 @@ pub(crate) struct MustNotSuspendReason { pub reason: String, } +pub(crate) struct UnnecessaryTransmute { + pub span: Span, + pub sugg: String, + pub help: Option<&'static str>, +} + +// Needed for def_path_str +impl<'a> LintDiagnostic<'a, ()> for UnnecessaryTransmute { + fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) { + diag.primary_message(fluent::mir_transform_unnecessary_transmute); + diag.span_suggestion( + self.span, + "replace this with", + self.sugg, + lint::Applicability::MachineApplicable, + ); + self.help.map(|help| diag.help(help)); + } +} + #[derive(LintDiagnostic)] #[diag(mir_transform_undefined_transmute)] #[note] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 4d74ecddfb05..6977d23bd0e2 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -125,6 +125,7 @@ declare_passes! { mod check_null : CheckNull; mod check_packed_ref : CheckPackedRef; mod check_undefined_transmutes : CheckUndefinedTransmutes; + mod check_unnecessary_transmutes: CheckUnnecessaryTransmutes; // This pass is public to allow external drivers to perform MIR cleanup pub mod cleanup_post_borrowck : CleanupPostBorrowck; @@ -391,6 +392,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), &Lint(check_undefined_transmutes::CheckUndefinedTransmutes), + &Lint(check_unnecessary_transmutes::CheckUnnecessaryTransmutes), // What we need to do constant evaluation. &simplify::SimplifyCfg::Initial, &Lint(sanity_check::SanityCheck), diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 788e23ba82a9..ac8fc1d89d6f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1308,18 +1308,6 @@ where return true; } - // We don't consider a trait-bound global if it has a projection bound. - // - // See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs - // for an example where this is necessary. - for p in goal.param_env.caller_bounds().iter() { - if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() { - if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref { - return true; - } - } - } - false } _ => false, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 39251f1ce273..4be8a90368d2 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2058,6 +2058,17 @@ impl<'a> Parser<'a> { } self.expect_field_ty_separator()?; let ty = self.parse_ty()?; + if self.token == token::Colon && self.look_ahead(1, |&t| t != token::Colon) { + self.dcx() + .struct_span_err(self.token.span, "found single colon in a struct field type path") + .with_span_suggestion_verbose( + self.token.span, + "write a path separator here", + "::", + Applicability::MaybeIncorrect, + ) + .emit(); + } let default = if self.token == token::Eq { self.bump(); let const_expr = self.parse_expr_anon_const()?; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 1a02d45f0e3c..1093e4f4af0a 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -248,19 +248,13 @@ impl<'a> Parser<'a> { segments.push(segment); if self.is_import_coupler() || !self.eat_path_sep() { - let ok_for_recovery = self.may_recover() - && match style { - PathStyle::Expr => true, - PathStyle::Type if let Some((ident, _)) = self.prev_token.ident() => { - self.token == token::Colon - && ident.as_str().chars().all(|c| c.is_lowercase()) - && self.token.span.lo() == self.prev_token.span.hi() - && self - .look_ahead(1, |token| self.token.span.hi() == token.span.lo()) - } - _ => false, - }; - if ok_for_recovery + // IMPORTANT: We can *only ever* treat single colons as typo'ed double colons in + // expression contexts (!) since only there paths cannot possibly be followed by + // a colon and still form a syntactically valid construct. In pattern contexts, + // a path may be followed by a type annotation. E.g., `let pat:ty`. In type + // contexts, a path may be followed by a list of bounds. E.g., `where ty:bound`. + if self.may_recover() + && style == PathStyle::Expr // (!) && self.token == token::Colon && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index cc506b0164ee..43955cc23a9e 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -246,6 +246,10 @@ pub enum AutoDiff { /// Print the module after running autodiff and optimizations. PrintModFinal, + /// Print all passes scheduled by LLVM + PrintPasses, + /// Disable extra opt run after running autodiff + NoPostopt, /// Enzyme's loose type debug helper (can cause incorrect gradients!!) /// Usable in cases where Enzyme errors with `can not deduce type of X`. LooseTypes, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 36eee5f30865..5f4695fb1841 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -711,7 +711,7 @@ mod desc { pub(crate) const parse_list: &str = "a space-separated list of strings"; pub(crate) const parse_list_with_polarity: &str = "a comma-separated list of strings, with elements beginning with + or -"; - pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `LooseTypes`, `Inline`"; + pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`"; pub(crate) const parse_comma_list: &str = "a comma-separated list of strings"; pub(crate) const parse_opt_comma_list: &str = parse_comma_list; pub(crate) const parse_number: &str = "a number"; @@ -1360,6 +1360,8 @@ pub mod parse { "PrintModBefore" => AutoDiff::PrintModBefore, "PrintModAfter" => AutoDiff::PrintModAfter, "PrintModFinal" => AutoDiff::PrintModFinal, + "NoPostopt" => AutoDiff::NoPostopt, + "PrintPasses" => AutoDiff::PrintPasses, "LooseTypes" => AutoDiff::LooseTypes, "Inline" => AutoDiff::Inline, _ => { @@ -2098,6 +2100,8 @@ options! { `=PrintModBefore` `=PrintModAfter` `=PrintModFinal` + `=PrintPasses`, + `=NoPostopt` `=LooseTypes` `=Inline` Multiple options can be combined with commas."), diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index 77e5f3423d1e..771ff98d58d5 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -19,7 +19,6 @@ pub mod rustc_internal; -// Make this module private for now since external users should not call these directly. -mod rustc_smir; +pub mod rustc_smir; pub mod stable_mir; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 146ba17d14fc..2982a920b03d 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -18,9 +18,10 @@ use rustc_span::def_id::{CrateNum, DefId}; use scoped_tls::scoped_thread_local; use stable_mir::Error; use stable_mir::abi::Layout; +use stable_mir::compiler_interface::SmirInterface; use stable_mir::ty::IndexedVal; -use crate::rustc_smir::context::TablesWrapper; +use crate::rustc_smir::context::SmirCtxt; use crate::rustc_smir::{Stable, Tables}; use crate::stable_mir; @@ -196,12 +197,12 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum { // datastructures and stable MIR datastructures scoped_thread_local! (static TLV: Cell<*const ()>); -pub(crate) fn init<'tcx, F, T>(tables: &TablesWrapper<'tcx>, f: F) -> T +pub(crate) fn init<'tcx, F, T>(cx: &SmirCtxt<'tcx>, f: F) -> T where F: FnOnce() -> T, { assert!(!TLV.is_set()); - let ptr = tables as *const _ as *const (); + let ptr = cx as *const _ as *const (); TLV.set(&Cell::new(ptr), || f()) } @@ -212,8 +213,8 @@ pub(crate) fn with_tables(f: impl for<'tcx> FnOnce(&mut Tables<'tcx>) -> R) - TLV.with(|tlv| { let ptr = tlv.get(); assert!(!ptr.is_null()); - let wrapper = ptr as *const TablesWrapper<'_>; - let mut tables = unsafe { (*wrapper).0.borrow_mut() }; + let context = ptr as *const SmirCtxt<'_>; + let mut tables = unsafe { (*context).0.borrow_mut() }; f(&mut *tables) }) } @@ -222,7 +223,7 @@ pub fn run(tcx: TyCtxt<'_>, f: F) -> Result where F: FnOnce() -> T, { - let tables = TablesWrapper(RefCell::new(Tables { + let tables = SmirCtxt(RefCell::new(Tables { tcx, def_ids: IndexMap::default(), alloc_ids: IndexMap::default(), @@ -233,7 +234,12 @@ where mir_consts: IndexMap::default(), layouts: IndexMap::default(), })); - stable_mir::compiler_interface::run(&tables, || init(&tables, f)) + + let interface = SmirInterface { cx: tables }; + + // Pass the `SmirInterface` to compiler_interface::run + // and initialize the rustc-specific TLS with tables. + stable_mir::compiler_interface::run(&interface, || init(&interface.cx, f)) } /// Instantiate and run the compiler with the provided arguments and callback. @@ -256,7 +262,7 @@ where /// // Your code goes in here. /// # ControlFlow::Continue(()) /// } -/// # let args = vec!["--verbose".to_string()]; +/// # let args = &["--verbose".to_string()]; /// let result = run!(args, analyze_code); /// # assert_eq!(result, Err(CompilerError::Skipped)) /// # } @@ -278,7 +284,7 @@ where /// // Your code goes in here. /// # ControlFlow::Continue(()) /// } -/// # let args = vec!["--verbose".to_string()]; +/// # let args = &["--verbose".to_string()]; /// # let extra_args = vec![]; /// let result = run!(args, || analyze_code(extra_args)); /// # assert_eq!(result, Err(CompilerError::Skipped)) @@ -340,7 +346,6 @@ macro_rules! run_driver { C: Send, F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { - args: Vec, callback: Option, result: Option>, } @@ -352,14 +357,14 @@ macro_rules! run_driver { F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { /// Creates a new `StableMir` instance, with given test_function and arguments. - pub fn new(args: Vec, callback: F) -> Self { - StableMir { args, callback: Some(callback), result: None } + pub fn new(callback: F) -> Self { + StableMir { callback: Some(callback), result: None } } /// Runs the compiler against given target and tests it with `test_function` - pub fn run(&mut self) -> Result> { + pub fn run(&mut self, args: &[String]) -> Result> { let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> { - run_compiler(&self.args.clone(), self); + run_compiler(&args, self); Ok(()) }); match (compiler_result, self.result.take()) { @@ -409,7 +414,7 @@ macro_rules! run_driver { } } - StableMir::new($args, $callback).run() + StableMir::new($callback).run($args) }}; } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 240f6f7fe45a..9a4cac243bd3 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -1,7 +1,4 @@ -//! Implementation of `[stable_mir::compiler_interface::Context]` trait. -//! -//! This trait is currently the main interface between the Rust compiler, -//! and the `stable_mir` crate. +//! Implementation of StableMIR Context. #![allow(rustc::usage_of_qualified_ty)] @@ -20,7 +17,6 @@ use rustc_middle::ty::{ use rustc_middle::{mir, ty}; use rustc_span::def_id::LOCAL_CRATE; use stable_mir::abi::{FnAbi, Layout, LayoutShape}; -use stable_mir::compiler_interface::Context; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; use stable_mir::mir::{BinOp, Body, Place, UnOp}; @@ -37,8 +33,14 @@ use crate::rustc_smir::builder::BodyBuilder; use crate::rustc_smir::{Stable, Tables, alloc, filter_def_ids, new_item_kind, smir_crate}; use crate::stable_mir; -impl<'tcx> Context for TablesWrapper<'tcx> { - fn target_info(&self) -> MachineInfo { +/// Provides direct access to rustc's internal queries. +/// +/// The [`crate::stable_mir::compiler_interface::SmirInterface`] must go through +/// this context to obtain rustc-level information. +pub struct SmirCtxt<'tcx>(pub RefCell>); + +impl<'tcx> SmirCtxt<'tcx> { + pub fn target_info(&self) -> MachineInfo { let mut tables = self.0.borrow_mut(); MachineInfo { endian: tables.tcx.data_layout.endian.stable(&mut *tables), @@ -48,31 +50,35 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn entry_fn(&self) -> Option { + pub fn entry_fn(&self) -> Option { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; Some(tables.crate_item(tcx.entry_fn(())?.0)) } - fn all_local_items(&self) -> stable_mir::CrateItems { + /// Retrieve all items of the local crate that have a MIR associated with them. + pub fn all_local_items(&self) -> stable_mir::CrateItems { let mut tables = self.0.borrow_mut(); tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect() } - fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body { + /// Retrieve the body of a function. + /// This function will panic if the body is not available. + pub fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body { let mut tables = self.0.borrow_mut(); let def_id = tables[item]; tables.tcx.instance_mir(rustc_middle::ty::InstanceKind::Item(def_id)).stable(&mut tables) } - fn has_body(&self, def: DefId) -> bool { + /// Check whether the body of a function is available. + pub fn has_body(&self, def: DefId) -> bool { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.internal(&mut *tables, tcx); tables.item_has_body(def_id) } - fn foreign_modules(&self, crate_num: CrateNum) -> Vec { + pub fn foreign_modules(&self, crate_num: CrateNum) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; tcx.foreign_modules(crate_num.internal(&mut *tables, tcx)) @@ -81,21 +87,23 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn crate_functions(&self, crate_num: CrateNum) -> Vec { + /// Retrieve all functions defined in this crate. + pub fn crate_functions(&self, crate_num: CrateNum) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let krate = crate_num.internal(&mut *tables, tcx); filter_def_ids(tcx, krate, |def_id| tables.to_fn_def(def_id)) } - fn crate_statics(&self, crate_num: CrateNum) -> Vec { + /// Retrieve all static items defined in this crate. + pub fn crate_statics(&self, crate_num: CrateNum) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let krate = crate_num.internal(&mut *tables, tcx); filter_def_ids(tcx, krate, |def_id| tables.to_static(def_id)) } - fn foreign_module( + pub fn foreign_module( &self, mod_def: stable_mir::ty::ForeignModuleDef, ) -> stable_mir::ty::ForeignModule { @@ -105,7 +113,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { mod_def.stable(&mut *tables) } - fn foreign_items(&self, mod_def: stable_mir::ty::ForeignModuleDef) -> Vec { + pub fn foreign_items(&self, mod_def: stable_mir::ty::ForeignModuleDef) -> Vec { let mut tables = self.0.borrow_mut(); let def_id = tables[mod_def.def_id()]; tables @@ -119,12 +127,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn all_trait_decls(&self) -> stable_mir::TraitDecls { + pub fn all_trait_decls(&self) -> stable_mir::TraitDecls { let mut tables = self.0.borrow_mut(); tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect() } - fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls { + pub fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; tcx.traits(crate_num.internal(&mut *tables, tcx)) @@ -133,14 +141,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl { + pub fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl { let mut tables = self.0.borrow_mut(); let def_id = tables[trait_def.0]; let trait_def = tables.tcx.trait_def(def_id); trait_def.stable(&mut *tables) } - fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls { + pub fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; iter::once(LOCAL_CRATE) @@ -150,7 +158,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls { + pub fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; tcx.trait_impls_in_crate(crate_num.internal(&mut *tables, tcx)) @@ -159,21 +167,21 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait { + pub fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait { let mut tables = self.0.borrow_mut(); let def_id = tables[impl_def.0]; let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap(); impl_trait.stable(&mut *tables) } - fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics { + pub fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; let generics = tables.tcx.generics_of(def_id); generics.stable(&mut *tables) } - fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates { + pub fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id); @@ -191,7 +199,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn explicit_predicates_of( + pub fn explicit_predicates_of( &self, def_id: stable_mir::DefId, ) -> stable_mir::ty::GenericPredicates { @@ -212,17 +220,20 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn local_crate(&self) -> stable_mir::Crate { + /// Get information about the local crate. + pub fn local_crate(&self) -> stable_mir::Crate { let tables = self.0.borrow(); smir_crate(tables.tcx, LOCAL_CRATE) } - fn external_crates(&self) -> Vec { + /// Retrieve a list of all external crates. + pub fn external_crates(&self) -> Vec { let tables = self.0.borrow(); tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect() } - fn find_crates(&self, name: &str) -> Vec { + /// Find a crate with the given name. + pub fn find_crates(&self, name: &str) -> Vec { let tables = self.0.borrow(); let crates: Vec = [LOCAL_CRATE] .iter() @@ -235,7 +246,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { crates } - fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol { + /// Returns the name of given `DefId`. + pub fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol { let tables = self.0.borrow(); if trimmed { with_forced_trimmed_paths!(tables.tcx.def_path_str(tables[def_id])) @@ -244,7 +256,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn tool_attrs( + /// Return registered tool attributes with the given attribute name. + /// + /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool + /// attributes will simply return an empty list. + /// + /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`. + /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. + pub fn tool_attrs( &self, def_id: stable_mir::DefId, attr: &[stable_mir::Symbol], @@ -268,7 +287,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn all_tool_attrs(&self, def_id: stable_mir::DefId) -> Vec { + /// Get all tool attributes of a definition. + pub fn all_tool_attrs( + &self, + def_id: stable_mir::DefId, + ) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let did = tables[def_id]; @@ -292,12 +315,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn span_to_string(&self, span: stable_mir::ty::Span) -> String { + /// Returns printable, human readable form of `Span`. + pub fn span_to_string(&self, span: stable_mir::ty::Span) -> String { let tables = self.0.borrow(); tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span]) } - fn get_filename(&self, span: &Span) -> Filename { + /// Return filename from given `Span`, for diagnostic purposes. + pub fn get_filename(&self, span: &Span) -> Filename { let tables = self.0.borrow(); tables .tcx @@ -308,23 +333,27 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .to_string() } - fn get_lines(&self, span: &Span) -> LineInfo { + /// Return lines corresponding to this `Span`. + pub fn get_lines(&self, span: &Span) -> LineInfo { let tables = self.0.borrow(); let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]); LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 } } - fn item_kind(&self, item: CrateItem) -> ItemKind { + /// Returns the `kind` of given `DefId`. + pub fn item_kind(&self, item: CrateItem) -> ItemKind { let tables = self.0.borrow(); new_item_kind(tables.tcx.def_kind(tables[item.0])) } - fn is_foreign_item(&self, item: DefId) -> bool { + /// Returns whether this is a foreign item. + pub fn is_foreign_item(&self, item: DefId) -> bool { let tables = self.0.borrow(); tables.tcx.is_foreign_item(tables[item]) } - fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind { + /// Returns the kind of a given foreign item. + pub fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind { let mut tables = self.0.borrow_mut(); let def_id = tables[def.def_id()]; let tcx = tables.tcx; @@ -339,32 +368,37 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn adt_kind(&self, def: AdtDef) -> AdtKind { + /// Returns the kind of a given algebraic data type. + pub fn adt_kind(&self, def: AdtDef) -> AdtKind { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).adt_kind().stable(&mut *tables) } - fn adt_is_box(&self, def: AdtDef) -> bool { + /// Returns if the ADT is a box. + pub fn adt_is_box(&self, def: AdtDef) -> bool { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).is_box() } - fn adt_is_simd(&self, def: AdtDef) -> bool { + /// Returns whether this ADT is simd. + pub fn adt_is_simd(&self, def: AdtDef) -> bool { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).repr().simd() } - fn adt_is_cstr(&self, def: AdtDef) -> bool { + /// Returns whether this definition is a C string. + pub fn adt_is_cstr(&self, def: AdtDef) -> bool { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); tables.tcx.is_lang_item(def_id, LangItem::CStr) } - fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { + /// Retrieve the function signature for the given generic arguments. + pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); @@ -373,7 +407,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { sig.stable(&mut *tables) } - fn intrinsic(&self, def: DefId) -> Option { + /// Retrieve the intrinsic definition if the item corresponds one. + pub fn intrinsic(&self, def: DefId) -> Option { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.internal(&mut *tables, tcx); @@ -381,14 +416,16 @@ impl<'tcx> Context for TablesWrapper<'tcx> { intrinsic.map(|_| IntrinsicDef(def)) } - fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol { + /// Retrieve the plain function name of an intrinsic. + pub fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); tcx.intrinsic(def_id).unwrap().name.to_string() } - fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { + /// Retrieve the closure signature for the given generic arguments. + pub fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let args_ref = args.internal(&mut *tables, tcx); @@ -396,25 +433,28 @@ impl<'tcx> Context for TablesWrapper<'tcx> { sig.stable(&mut *tables) } - fn adt_variants_len(&self, def: AdtDef) -> usize { + /// The number of variants in this ADT. + pub fn adt_variants_len(&self, def: AdtDef) -> usize { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).variants().len() } - fn variant_name(&self, def: VariantDef) -> Symbol { + /// The name of a variant. + pub fn variant_name(&self, def: VariantDef) -> Symbol { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).name.to_string() } - fn variant_fields(&self, def: VariantDef) -> Vec { + pub fn variant_fields(&self, def: VariantDef) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).fields.iter().map(|f| f.stable(&mut *tables)).collect() } - fn eval_target_usize(&self, cnst: &MirConst) -> Result { + /// Evaluate constant as a target usize. + pub fn eval_target_usize(&self, cnst: &MirConst) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let mir_const = cnst.internal(&mut *tables, tcx); @@ -422,7 +462,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .try_eval_target_usize(tables.tcx, ty::TypingEnv::fully_monomorphized()) .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) } - fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result { + pub fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let mir_const = cnst.internal(&mut *tables, tcx); @@ -431,7 +471,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) } - fn try_new_const_zst(&self, ty: Ty) -> Result { + /// Create a new zero-sized constant. + pub fn try_new_const_zst(&self, ty: Ty) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty_internal = ty.internal(&mut *tables, tcx); @@ -456,7 +497,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .stable(&mut *tables)) } - fn new_const_str(&self, value: &str) -> MirConst { + /// Create a new constant that represents the given string value. + pub fn new_const_str(&self, value: &str) -> MirConst { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty = ty::Ty::new_static_str(tcx); @@ -467,12 +509,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { mir::Const::from_value(val, ty).stable(&mut tables) } - fn new_const_bool(&self, value: bool) -> MirConst { + /// Create a new constant that represents the given boolean value. + pub fn new_const_bool(&self, value: bool) -> MirConst { let mut tables = self.0.borrow_mut(); mir::Const::from_bool(tables.tcx, value).stable(&mut tables) } - fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { + /// Create a new constant that represents the given value. + pub fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx)); @@ -487,7 +531,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { Ok(mir::Const::from_scalar(tcx, mir::interpret::Scalar::Int(scalar), ty) .stable(&mut tables)) } - fn try_new_ty_const_uint( + pub fn try_new_ty_const_uint( &self, value: u128, uint_ty: UintTy, @@ -509,27 +553,35 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .stable(&mut *tables)) } - fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty { + /// Create a new type from the given kind. + pub fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let internal_kind = kind.internal(&mut *tables, tcx); tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables) } - fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty { + /// Create a new box type, `Box`, for the given inner type `T`. + pub fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let inner = ty.internal(&mut *tables, tcx); ty::Ty::new_box(tables.tcx, inner).stable(&mut *tables) } - fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty { + /// Returns the type of given crate item. + pub fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; tcx.type_of(item.internal(&mut *tables, tcx)).instantiate_identity().stable(&mut *tables) } - fn def_ty_with_args(&self, item: stable_mir::DefId, args: &GenericArgs) -> stable_mir::ty::Ty { + /// Returns the type of given definition instantiated with the given arguments. + pub fn def_ty_with_args( + &self, + item: stable_mir::DefId, + args: &GenericArgs, + ) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let args = args.internal(&mut *tables, tcx); @@ -544,33 +596,38 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .stable(&mut *tables) } - fn mir_const_pretty(&self, cnst: &stable_mir::ty::MirConst) -> String { + /// Returns literal value of a const as a string. + pub fn mir_const_pretty(&self, cnst: &stable_mir::ty::MirConst) -> String { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; cnst.internal(&mut *tables, tcx).to_string() } - fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span { + /// `Span` of an item. + pub fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span { let mut tables = self.0.borrow_mut(); tables.tcx.def_span(tables[def_id]).stable(&mut *tables) } - fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String { + /// Obtain the representation of a type. + pub fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String { let tables = self.0.borrow_mut(); tables.types[ty].to_string() } - fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind { + /// Obtain the representation of a type. + pub fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind { let mut tables = self.0.borrow_mut(); tables.types[ty].kind().stable(&mut *tables) } - fn ty_const_pretty(&self, ct: stable_mir::ty::TyConstId) -> String { + pub fn ty_const_pretty(&self, ct: stable_mir::ty::TyConstId) -> String { let tables = self.0.borrow_mut(); tables.ty_consts[ct].to_string() } - fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty { + /// Get the discriminant Ty for this Ty if there's one. + pub fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let internal_kind = ty.internal(&mut *tables, tcx); @@ -578,7 +635,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { internal_ty.discriminant_ty(tables.tcx).stable(&mut *tables) } - fn instance_body(&self, def: InstanceDef) -> Option { + /// Get the body of an Instance which is already monomorphized. + pub fn instance_body(&self, def: InstanceDef) -> Option { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; tables @@ -586,63 +644,74 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables)) } - fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty { + /// Get the instance type with generic instantiations applied and lifetimes erased. + pub fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; assert!(!instance.has_non_region_param(), "{instance:?} needs further instantiation"); instance.ty(tables.tcx, ty::TypingEnv::fully_monomorphized()).stable(&mut *tables) } - fn instance_args(&self, def: InstanceDef) -> GenericArgs { + /// Get the instantiation types. + pub fn instance_args(&self, def: InstanceDef) -> GenericArgs { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; instance.args.stable(&mut *tables) } - fn instance_abi(&self, def: InstanceDef) -> Result { + /// Get an instance ABI. + pub fn instance_abi(&self, def: InstanceDef) -> Result { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables)) } - fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { + /// Get the ABI of a function pointer. + pub fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let sig = fn_ptr.internal(&mut *tables, tcx); Ok(tables.fn_abi_of_fn_ptr(sig, List::empty())?.stable(&mut *tables)) } - fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId { + /// Get the instance. + pub fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId { let mut tables = self.0.borrow_mut(); let def_id = tables.instances[def].def_id(); tables.create_def_id(def_id) } - fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol { + /// Get the instance mangled name. + pub fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol { let tables = self.0.borrow_mut(); let instance = tables.instances[instance]; tables.tcx.symbol_name(instance).name.to_string() } - fn is_empty_drop_shim(&self, def: InstanceDef) -> bool { + /// Check if this is an empty DropGlue shim. + pub fn is_empty_drop_shim(&self, def: InstanceDef) -> bool { let tables = self.0.borrow_mut(); let instance = tables.instances[def]; matches!(instance.def, ty::InstanceKind::DropGlue(_, None)) } - fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool { + /// Check if this is an empty AsyncDropGlueCtor shim. + pub fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool { let tables = self.0.borrow_mut(); let instance = tables.instances[def]; matches!(instance.def, ty::InstanceKind::AsyncDropGlueCtorShim(_, None)) } - fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance { + /// Convert a non-generic crate item into an instance. + /// This function will panic if the item is generic. + pub fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; Instance::mono(tables.tcx, def_id).stable(&mut *tables) } - fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool { + /// Item requires monomorphization. + pub fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool { let tables = self.0.borrow(); let def_id = tables[def_id]; let generics = tables.tcx.generics_of(def_id); @@ -650,7 +719,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { result } - fn resolve_instance( + /// Resolve an instance from the given function definition and generic arguments. + pub fn resolve_instance( &self, def: stable_mir::ty::FnDef, args: &stable_mir::ty::GenericArgs, @@ -670,7 +740,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance { + /// Resolve an instance for drop_in_place for the given type. + pub fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let internal_ty = ty.internal(&mut *tables, tcx); @@ -678,7 +749,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { instance.stable(&mut *tables) } - fn resolve_for_fn_ptr( + /// Resolve instance for a function pointer. + pub fn resolve_for_fn_ptr( &self, def: FnDef, args: &GenericArgs, @@ -696,7 +768,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .stable(&mut *tables) } - fn resolve_closure( + /// Resolve instance for a closure with the requested type. + pub fn resolve_closure( &self, def: ClosureDef, args: &GenericArgs, @@ -713,7 +786,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ) } - fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result { + /// Try to evaluate an instance into a constant. + pub fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; let tcx = tables.tcx; @@ -733,21 +807,24 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .map_err(|e| e.stable(&mut *tables))? } - fn eval_static_initializer(&self, def: StaticDef) -> Result { + /// Evaluate a static's initializer. + pub fn eval_static_initializer(&self, def: StaticDef) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); tables.tcx.eval_static_initializer(def_id).stable(&mut *tables) } - fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc { + /// Retrieve global allocation for the given allocation ID. + pub fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let alloc_id = alloc.internal(&mut *tables, tcx); tables.tcx.global_alloc(alloc_id).stable(&mut *tables) } - fn vtable_allocation( + /// Retrieve the id for the virtual table. + pub fn vtable_allocation( &self, global_alloc: &GlobalAlloc, ) -> Option { @@ -765,7 +842,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { Some(alloc_id.stable(&mut *tables)) } - fn krate(&self, def_id: stable_mir::DefId) -> Crate { + pub fn krate(&self, def_id: stable_mir::DefId) -> Crate { let tables = self.0.borrow(); smir_crate(tables.tcx, tables[def_id].krate) } @@ -773,7 +850,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { /// Retrieve the instance name for diagnostic messages. /// /// This will return the specialized name, e.g., `Vec::new`. - fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol { + pub fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol { let tables = self.0.borrow_mut(); let instance = tables.instances[def]; if trimmed { @@ -787,7 +864,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn ty_layout(&self, ty: Ty) -> Result { + /// Get the layout of a type. + pub fn ty_layout(&self, ty: Ty) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty = ty.internal(&mut *tables, tcx); @@ -795,19 +873,22 @@ impl<'tcx> Context for TablesWrapper<'tcx> { Ok(layout.stable(&mut *tables)) } - fn layout_shape(&self, id: Layout) -> LayoutShape { + /// Get the layout shape. + pub fn layout_shape(&self, id: Layout) -> LayoutShape { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; id.internal(&mut *tables, tcx).0.stable(&mut *tables) } - fn place_pretty(&self, place: &Place) -> String { + /// Get a debug string representation of a place. + pub fn place_pretty(&self, place: &Place) -> String { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; format!("{:?}", place.internal(&mut *tables, tcx)) } - fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty { + /// Get the resulting type of binary operation. + pub fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let rhs_internal = rhs.internal(&mut *tables, tcx); @@ -816,7 +897,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ty.stable(&mut *tables) } - fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty { + /// Get the resulting type of unary operation. + pub fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let arg_internal = arg.internal(&mut *tables, tcx); @@ -824,7 +906,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ty.stable(&mut *tables) } - fn associated_items(&self, def_id: stable_mir::DefId) -> stable_mir::AssocItems { + /// Get all associated items of a definition. + pub fn associated_items(&self, def_id: stable_mir::DefId) -> stable_mir::AssocItems { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = tables[def_id]; @@ -840,8 +923,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } -pub(crate) struct TablesWrapper<'tcx>(pub RefCell>); - /// Implement error handling for extracting function ABI information. impl<'tcx> FnAbiOfHelpers<'tcx> for Tables<'tcx> { type FnAbiOfResult = Result<&'tcx rustc_target::callconv::FnAbi<'tcx, ty::Ty<'tcx>>, Error>; diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index dea8f54a6709..b5003baaf633 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -25,7 +25,7 @@ use crate::stable_mir; mod alloc; mod builder; -pub(crate) mod context; +pub mod context; mod convert; pub struct Tables<'tcx> { diff --git a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs index 33d950bb951c..cd61907dc6ba 100644 --- a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs +++ b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs @@ -5,6 +5,7 @@ use std::cell::Cell; +use rustc_smir::context::SmirCtxt; use stable_mir::abi::{FnAbi, Layout, LayoutShape}; use stable_mir::crate_def::Attribute; use stable_mir::mir::alloc::{AllocId, GlobalAlloc}; @@ -22,47 +23,116 @@ use stable_mir::{ ItemKind, Symbol, TraitDecls, mir, }; -use crate::stable_mir; +use crate::{rustc_smir, stable_mir}; + +/// Stable public API for querying compiler information. +/// +/// All queries are delegated to an internal [`SmirCtxt`] that provides +/// similar APIs but based on internal rustc constructs. +/// +/// Do not use this directly. This is currently used in the macro expansion. +pub(crate) struct SmirInterface<'tcx> { + pub(crate) cx: SmirCtxt<'tcx>, +} + +impl<'tcx> SmirInterface<'tcx> { + pub(crate) fn entry_fn(&self) -> Option { + self.cx.entry_fn() + } -/// This trait defines the interface between stable_mir and the Rust compiler. -/// Do not use this directly. -pub trait Context { - fn entry_fn(&self) -> Option; /// Retrieve all items of the local crate that have a MIR associated with them. - fn all_local_items(&self) -> CrateItems; + pub(crate) fn all_local_items(&self) -> CrateItems { + self.cx.all_local_items() + } + /// Retrieve the body of a function. /// This function will panic if the body is not available. - fn mir_body(&self, item: DefId) -> mir::Body; + pub(crate) fn mir_body(&self, item: DefId) -> mir::Body { + self.cx.mir_body(item) + } + /// Check whether the body of a function is available. - fn has_body(&self, item: DefId) -> bool; - fn foreign_modules(&self, crate_num: CrateNum) -> Vec; + pub(crate) fn has_body(&self, item: DefId) -> bool { + self.cx.has_body(item) + } + + pub(crate) fn foreign_modules(&self, crate_num: CrateNum) -> Vec { + self.cx.foreign_modules(crate_num) + } /// Retrieve all functions defined in this crate. - fn crate_functions(&self, crate_num: CrateNum) -> Vec; + pub(crate) fn crate_functions(&self, crate_num: CrateNum) -> Vec { + self.cx.crate_functions(crate_num) + } /// Retrieve all static items defined in this crate. - fn crate_statics(&self, crate_num: CrateNum) -> Vec; - fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule; - fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec; - fn all_trait_decls(&self) -> TraitDecls; - fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls; - fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl; - fn all_trait_impls(&self) -> ImplTraitDecls; - fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls; - fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait; - fn generics_of(&self, def_id: DefId) -> Generics; - fn predicates_of(&self, def_id: DefId) -> GenericPredicates; - fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates; + pub(crate) fn crate_statics(&self, crate_num: CrateNum) -> Vec { + self.cx.crate_statics(crate_num) + } + + pub(crate) fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule { + self.cx.foreign_module(mod_def) + } + + pub(crate) fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec { + self.cx.foreign_items(mod_def) + } + + pub(crate) fn all_trait_decls(&self) -> TraitDecls { + self.cx.all_trait_decls() + } + + pub(crate) fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls { + self.cx.trait_decls(crate_num) + } + + pub(crate) fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl { + self.cx.trait_decl(trait_def) + } + + pub(crate) fn all_trait_impls(&self) -> ImplTraitDecls { + self.cx.all_trait_impls() + } + + pub(crate) fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls { + self.cx.trait_impls(crate_num) + } + + pub(crate) fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait { + self.cx.trait_impl(trait_impl) + } + + pub(crate) fn generics_of(&self, def_id: DefId) -> Generics { + self.cx.generics_of(def_id) + } + + pub(crate) fn predicates_of(&self, def_id: DefId) -> GenericPredicates { + self.cx.predicates_of(def_id) + } + + pub(crate) fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates { + self.cx.explicit_predicates_of(def_id) + } + /// Get information about the local crate. - fn local_crate(&self) -> Crate; + pub(crate) fn local_crate(&self) -> Crate { + self.cx.local_crate() + } + /// Retrieve a list of all external crates. - fn external_crates(&self) -> Vec; + pub(crate) fn external_crates(&self) -> Vec { + self.cx.external_crates() + } /// Find a crate with the given name. - fn find_crates(&self, name: &str) -> Vec; + pub(crate) fn find_crates(&self, name: &str) -> Vec { + self.cx.find_crates(name) + } - /// Returns the name of given `DefId` - fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol; + /// Returns the name of given `DefId`. + pub(crate) fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol { + self.cx.def_name(def_id, trimmed) + } /// Return registered tool attributes with the given attribute name. /// @@ -71,218 +141,362 @@ pub trait Context { /// /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`. /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. - fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec; + pub(crate) fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec { + self.cx.tool_attrs(def_id, attr) + } /// Get all tool attributes of a definition. - fn all_tool_attrs(&self, def_id: DefId) -> Vec; + pub(crate) fn all_tool_attrs(&self, def_id: DefId) -> Vec { + self.cx.all_tool_attrs(def_id) + } - /// Returns printable, human readable form of `Span` - fn span_to_string(&self, span: Span) -> String; + /// Returns printable, human readable form of `Span`. + pub(crate) fn span_to_string(&self, span: Span) -> String { + self.cx.span_to_string(span) + } - /// Return filename from given `Span`, for diagnostic purposes - fn get_filename(&self, span: &Span) -> Filename; + /// Return filename from given `Span`, for diagnostic purposes. + pub(crate) fn get_filename(&self, span: &Span) -> Filename { + self.cx.get_filename(span) + } - /// Return lines corresponding to this `Span` - fn get_lines(&self, span: &Span) -> LineInfo; + /// Return lines corresponding to this `Span`. + pub(crate) fn get_lines(&self, span: &Span) -> LineInfo { + self.cx.get_lines(span) + } - /// Returns the `kind` of given `DefId` - fn item_kind(&self, item: CrateItem) -> ItemKind; + /// Returns the `kind` of given `DefId`. + pub(crate) fn item_kind(&self, item: CrateItem) -> ItemKind { + self.cx.item_kind(item) + } /// Returns whether this is a foreign item. - fn is_foreign_item(&self, item: DefId) -> bool; + pub(crate) fn is_foreign_item(&self, item: DefId) -> bool { + self.cx.is_foreign_item(item) + } /// Returns the kind of a given foreign item. - fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind; + pub(crate) fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind { + self.cx.foreign_item_kind(def) + } - /// Returns the kind of a given algebraic data type - fn adt_kind(&self, def: AdtDef) -> AdtKind; + /// Returns the kind of a given algebraic data type. + pub(crate) fn adt_kind(&self, def: AdtDef) -> AdtKind { + self.cx.adt_kind(def) + } /// Returns if the ADT is a box. - fn adt_is_box(&self, def: AdtDef) -> bool; + pub(crate) fn adt_is_box(&self, def: AdtDef) -> bool { + self.cx.adt_is_box(def) + } /// Returns whether this ADT is simd. - fn adt_is_simd(&self, def: AdtDef) -> bool; + pub(crate) fn adt_is_simd(&self, def: AdtDef) -> bool { + self.cx.adt_is_simd(def) + } /// Returns whether this definition is a C string. - fn adt_is_cstr(&self, def: AdtDef) -> bool; + pub(crate) fn adt_is_cstr(&self, def: AdtDef) -> bool { + self.cx.adt_is_cstr(def) + } /// Retrieve the function signature for the given generic arguments. - fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig; + pub(crate) fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { + self.cx.fn_sig(def, args) + } /// Retrieve the intrinsic definition if the item corresponds one. - fn intrinsic(&self, item: DefId) -> Option; + pub(crate) fn intrinsic(&self, item: DefId) -> Option { + self.cx.intrinsic(item) + } /// Retrieve the plain function name of an intrinsic. - fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol; + pub(crate) fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol { + self.cx.intrinsic_name(def) + } /// Retrieve the closure signature for the given generic arguments. - fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig; + pub(crate) fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { + self.cx.closure_sig(args) + } /// The number of variants in this ADT. - fn adt_variants_len(&self, def: AdtDef) -> usize; + pub(crate) fn adt_variants_len(&self, def: AdtDef) -> usize { + self.cx.adt_variants_len(def) + } /// The name of a variant. - fn variant_name(&self, def: VariantDef) -> Symbol; - fn variant_fields(&self, def: VariantDef) -> Vec; + pub(crate) fn variant_name(&self, def: VariantDef) -> Symbol { + self.cx.variant_name(def) + } + + pub(crate) fn variant_fields(&self, def: VariantDef) -> Vec { + self.cx.variant_fields(def) + } /// Evaluate constant as a target usize. - fn eval_target_usize(&self, cnst: &MirConst) -> Result; - fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result; + pub(crate) fn eval_target_usize(&self, cnst: &MirConst) -> Result { + self.cx.eval_target_usize(cnst) + } + + pub(crate) fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result { + self.cx.eval_target_usize_ty(cnst) + } /// Create a new zero-sized constant. - fn try_new_const_zst(&self, ty: Ty) -> Result; + pub(crate) fn try_new_const_zst(&self, ty: Ty) -> Result { + self.cx.try_new_const_zst(ty) + } /// Create a new constant that represents the given string value. - fn new_const_str(&self, value: &str) -> MirConst; + pub(crate) fn new_const_str(&self, value: &str) -> MirConst { + self.cx.new_const_str(value) + } /// Create a new constant that represents the given boolean value. - fn new_const_bool(&self, value: bool) -> MirConst; + pub(crate) fn new_const_bool(&self, value: bool) -> MirConst { + self.cx.new_const_bool(value) + } /// Create a new constant that represents the given value. - fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result; - fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result; + pub(crate) fn try_new_const_uint( + &self, + value: u128, + uint_ty: UintTy, + ) -> Result { + self.cx.try_new_const_uint(value, uint_ty) + } + + pub(crate) fn try_new_ty_const_uint( + &self, + value: u128, + uint_ty: UintTy, + ) -> Result { + self.cx.try_new_ty_const_uint(value, uint_ty) + } /// Create a new type from the given kind. - fn new_rigid_ty(&self, kind: RigidTy) -> Ty; + pub(crate) fn new_rigid_ty(&self, kind: RigidTy) -> Ty { + self.cx.new_rigid_ty(kind) + } /// Create a new box type, `Box`, for the given inner type `T`. - fn new_box_ty(&self, ty: Ty) -> Ty; + pub(crate) fn new_box_ty(&self, ty: Ty) -> Ty { + self.cx.new_box_ty(ty) + } /// Returns the type of given crate item. - fn def_ty(&self, item: DefId) -> Ty; + pub(crate) fn def_ty(&self, item: DefId) -> Ty { + self.cx.def_ty(item) + } /// Returns the type of given definition instantiated with the given arguments. - fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty; + pub(crate) fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty { + self.cx.def_ty_with_args(item, args) + } /// Returns literal value of a const as a string. - fn mir_const_pretty(&self, cnst: &MirConst) -> String; + pub(crate) fn mir_const_pretty(&self, cnst: &MirConst) -> String { + self.cx.mir_const_pretty(cnst) + } - /// `Span` of an item - fn span_of_an_item(&self, def_id: DefId) -> Span; + /// `Span` of an item. + pub(crate) fn span_of_an_item(&self, def_id: DefId) -> Span { + self.cx.span_of_an_item(def_id) + } - fn ty_const_pretty(&self, ct: TyConstId) -> String; + pub(crate) fn ty_const_pretty(&self, ct: TyConstId) -> String { + self.cx.ty_const_pretty(ct) + } /// Obtain the representation of a type. - fn ty_pretty(&self, ty: Ty) -> String; + pub(crate) fn ty_pretty(&self, ty: Ty) -> String { + self.cx.ty_pretty(ty) + } /// Obtain the representation of a type. - fn ty_kind(&self, ty: Ty) -> TyKind; + pub(crate) fn ty_kind(&self, ty: Ty) -> TyKind { + self.cx.ty_kind(ty) + } - // Get the discriminant Ty for this Ty if there's one. - fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty; + /// Get the discriminant Ty for this Ty if there's one. + pub(crate) fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty { + self.cx.rigid_ty_discriminant_ty(ty) + } /// Get the body of an Instance which is already monomorphized. - fn instance_body(&self, instance: InstanceDef) -> Option; + pub(crate) fn instance_body(&self, instance: InstanceDef) -> Option { + self.cx.instance_body(instance) + } /// Get the instance type with generic instantiations applied and lifetimes erased. - fn instance_ty(&self, instance: InstanceDef) -> Ty; + pub(crate) fn instance_ty(&self, instance: InstanceDef) -> Ty { + self.cx.instance_ty(instance) + } /// Get the instantiation types. - fn instance_args(&self, def: InstanceDef) -> GenericArgs; + pub(crate) fn instance_args(&self, def: InstanceDef) -> GenericArgs { + self.cx.instance_args(def) + } /// Get the instance. - fn instance_def_id(&self, instance: InstanceDef) -> DefId; + pub(crate) fn instance_def_id(&self, instance: InstanceDef) -> DefId { + self.cx.instance_def_id(instance) + } /// Get the instance mangled name. - fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol; + pub(crate) fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol { + self.cx.instance_mangled_name(instance) + } /// Check if this is an empty DropGlue shim. - fn is_empty_drop_shim(&self, def: InstanceDef) -> bool; + pub(crate) fn is_empty_drop_shim(&self, def: InstanceDef) -> bool { + self.cx.is_empty_drop_shim(def) + } /// Check if this is an empty AsyncDropGlueCtor shim. - fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool; + pub(crate) fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool { + self.cx.is_empty_async_drop_ctor_shim(def) + } /// Convert a non-generic crate item into an instance. /// This function will panic if the item is generic. - fn mono_instance(&self, def_id: DefId) -> Instance; + pub(crate) fn mono_instance(&self, def_id: DefId) -> Instance { + self.cx.mono_instance(def_id) + } /// Item requires monomorphization. - fn requires_monomorphization(&self, def_id: DefId) -> bool; + pub(crate) fn requires_monomorphization(&self, def_id: DefId) -> bool { + self.cx.requires_monomorphization(def_id) + } /// Resolve an instance from the given function definition and generic arguments. - fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option; + pub(crate) fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option { + self.cx.resolve_instance(def, args) + } /// Resolve an instance for drop_in_place for the given type. - fn resolve_drop_in_place(&self, ty: Ty) -> Instance; + pub(crate) fn resolve_drop_in_place(&self, ty: Ty) -> Instance { + self.cx.resolve_drop_in_place(ty) + } /// Resolve instance for a function pointer. - fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option; + pub(crate) fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option { + self.cx.resolve_for_fn_ptr(def, args) + } /// Resolve instance for a closure with the requested type. - fn resolve_closure( + pub(crate) fn resolve_closure( &self, def: ClosureDef, args: &GenericArgs, kind: ClosureKind, - ) -> Option; + ) -> Option { + self.cx.resolve_closure(def, args, kind) + } /// Evaluate a static's initializer. - fn eval_static_initializer(&self, def: StaticDef) -> Result; + pub(crate) fn eval_static_initializer(&self, def: StaticDef) -> Result { + self.cx.eval_static_initializer(def) + } /// Try to evaluate an instance into a constant. - fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result; + pub(crate) fn eval_instance( + &self, + def: InstanceDef, + const_ty: Ty, + ) -> Result { + self.cx.eval_instance(def, const_ty) + } /// Retrieve global allocation for the given allocation ID. - fn global_alloc(&self, id: AllocId) -> GlobalAlloc; + pub(crate) fn global_alloc(&self, id: AllocId) -> GlobalAlloc { + self.cx.global_alloc(id) + } /// Retrieve the id for the virtual table. - fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option; - fn krate(&self, def_id: DefId) -> Crate; - fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol; + pub(crate) fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option { + self.cx.vtable_allocation(global_alloc) + } + + pub(crate) fn krate(&self, def_id: DefId) -> Crate { + self.cx.krate(def_id) + } + + pub(crate) fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol { + self.cx.instance_name(def, trimmed) + } /// Return information about the target machine. - fn target_info(&self) -> MachineInfo; + pub(crate) fn target_info(&self) -> MachineInfo { + self.cx.target_info() + } /// Get an instance ABI. - fn instance_abi(&self, def: InstanceDef) -> Result; + pub(crate) fn instance_abi(&self, def: InstanceDef) -> Result { + self.cx.instance_abi(def) + } /// Get the ABI of a function pointer. - fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result; + pub(crate) fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { + self.cx.fn_ptr_abi(fn_ptr) + } /// Get the layout of a type. - fn ty_layout(&self, ty: Ty) -> Result; + pub(crate) fn ty_layout(&self, ty: Ty) -> Result { + self.cx.ty_layout(ty) + } /// Get the layout shape. - fn layout_shape(&self, id: Layout) -> LayoutShape; + pub(crate) fn layout_shape(&self, id: Layout) -> LayoutShape { + self.cx.layout_shape(id) + } /// Get a debug string representation of a place. - fn place_pretty(&self, place: &Place) -> String; + pub(crate) fn place_pretty(&self, place: &Place) -> String { + self.cx.place_pretty(place) + } /// Get the resulting type of binary operation. - fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty; + pub(crate) fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty { + self.cx.binop_ty(bin_op, rhs, lhs) + } /// Get the resulting type of unary operation. - fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty; + pub(crate) fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty { + self.cx.unop_ty(un_op, arg) + } /// Get all associated items of a definition. - fn associated_items(&self, def_id: DefId) -> AssocItems; + pub(crate) fn associated_items(&self, def_id: DefId) -> AssocItems { + self.cx.associated_items(def_id) + } } -// A thread local variable that stores a pointer to the tables mapping between TyCtxt -// datastructures and stable MIR datastructures +// A thread local variable that stores a pointer to [`SmirInterface`]. scoped_tls::scoped_thread_local!(static TLV: Cell<*const ()>); -pub fn run(context: &dyn Context, f: F) -> Result +pub(crate) fn run<'tcx, T, F>(interface: &SmirInterface<'tcx>, f: F) -> Result where F: FnOnce() -> T, { if TLV.is_set() { Err(Error::from("StableMIR already running")) } else { - let ptr: *const () = (&raw const context) as _; + let ptr: *const () = (interface as *const SmirInterface<'tcx>) as *const (); TLV.set(&Cell::new(ptr), || Ok(f())) } } -/// Execute the given function with access the compiler [Context]. +/// Execute the given function with access the [`SmirInterface`]. /// -/// I.e., This function will load the current context and calls a function with it. +/// I.e., This function will load the current interface and calls a function with it. /// Do not nest these, as that will ICE. -pub(crate) fn with(f: impl FnOnce(&dyn Context) -> R) -> R { +pub(crate) fn with(f: impl FnOnce(&SmirInterface<'_>) -> R) -> R { assert!(TLV.is_set()); TLV.with(|tlv| { let ptr = tlv.get(); assert!(!ptr.is_null()); - f(unsafe { *(ptr as *const &dyn Context) }) + f(unsafe { &*(ptr as *const SmirInterface<'_>) }) }) } diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 7ecc46cc69db..ae366e29e323 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -144,6 +144,7 @@ pub struct ArgAttributes { /// (corresponding to LLVM's dereferenceable_or_null attributes, i.e., it is okay for this to be /// set on a null pointer, but all non-null pointers must be dereferenceable). pub pointee_size: Size, + /// The minimum alignment of the pointee, if any. pub pointee_align: Option, } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 3c769dad630a..37ea0d6e7b58 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -42,7 +42,9 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{fmt, io}; -use rustc_abi::{Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors}; +use rustc_abi::{ + Align, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors, +}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_fs_util::try_canonicalize; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; @@ -3599,6 +3601,25 @@ impl Target { _ => return None, }) } + + /// Returns whether this target is known to have unreliable alignment: + /// native C code for the target fails to align some data to the degree + /// required by the C standard. We can't *really* do anything about that + /// since unsafe Rust code may assume alignment any time, but we can at least + /// inhibit some optimizations, and we suppress the alignment checks that + /// would detect this unsoundness. + /// + /// Every target that returns less than `Align::MAX` here is still has a soundness bug. + pub fn max_reliable_alignment(&self) -> Align { + // FIXME(#112480) MSVC on x86-32 is unsound and fails to properly align many types with + // more-than-4-byte-alignment on the stack. This makes alignments larger than 4 generally + // unreliable on 32bit Windows. + if self.is_like_windows && self.arch == "x86" { + Align::from_bytes(4).unwrap() + } else { + Align::MAX + } + } } /// Either a target tuple string or a path to a JSON file. diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 07005215e4f3..69c8b9119ab2 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -516,7 +516,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zawrs", Unstable(sym::riscv_target_feature), &[]), ("zba", Stable, &[]), ("zbb", Stable, &[]), - ("zbc", Stable, &[]), + ("zbc", Stable, &["zbkc"]), // Zbc ⊃ Zbkc ("zbkb", Stable, &[]), ("zbkc", Stable, &[]), ("zbkx", Stable, &[]), @@ -545,20 +545,20 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zknd", Stable, &[]), ("zkne", Stable, &[]), ("zknh", Stable, &[]), - ("zkr", Stable, &["zicsr"]), + ("zkr", Stable, &[]), ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]), ("zksed", Stable, &[]), ("zksh", Stable, &[]), ("zkt", Stable, &[]), ("ztso", Unstable(sym::riscv_target_feature), &[]), - ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), + ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), // Zvbb ⊃ Zvkb ("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]), ("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]), ("zve32x", Unstable(sym::riscv_target_feature), &["zvl32b", "zicsr"]), ("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]), ("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]), ("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]), - ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zfhmin"]), + ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin ("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]), ("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]), ("zvkg", Unstable(sym::riscv_target_feature), &["zve32x"]), @@ -567,7 +567,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zvkned", Unstable(sym::riscv_target_feature), &["zve32x"]), ("zvkng", Unstable(sym::riscv_target_feature), &["zvkn", "zvkg"]), ("zvknha", Unstable(sym::riscv_target_feature), &["zve32x"]), - ("zvknhb", Unstable(sym::riscv_target_feature), &["zve64x"]), + ("zvknhb", Unstable(sym::riscv_target_feature), &["zvknha", "zve64x"]), // Zvknhb ⊃ Zvknha ("zvks", Unstable(sym::riscv_target_feature), &["zvksed", "zvksh", "zvkb", "zvkt"]), ("zvksc", Unstable(sym::riscv_target_feature), &["zvks", "zvbc"]), ("zvksed", Unstable(sym::riscv_target_feature), &["zve32x"]), diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 756d9a57b935..1063115ed237 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -9,7 +9,7 @@ use rustc_errors::{ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty}; -use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, IsAnonInPath, Node}; +use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath}; use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, GenericArg, Region, Ty, TyCtxt}; @@ -551,19 +551,6 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { impl<'v> Visitor<'v> for ImplicitLifetimeFinder { fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) { - let make_suggestion = |lifetime: &hir::Lifetime| { - if lifetime.is_anon_in_path == IsAnonInPath::Yes - && lifetime.ident.span.is_empty() - { - format!("{}, ", self.suggestion_param_name) - } else if lifetime.ident.name == kw::UnderscoreLifetime - && lifetime.ident.span.is_empty() - { - format!("{} ", self.suggestion_param_name) - } else { - self.suggestion_param_name.clone() - } - }; match ty.kind { hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { for segment in path.segments { @@ -572,7 +559,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { matches!( arg, hir::GenericArg::Lifetime(lifetime) - if lifetime.is_anon_in_path == IsAnonInPath::Yes + if lifetime.is_syntactically_hidden() ) }) { self.suggestions.push(( @@ -591,10 +578,10 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { if let hir::GenericArg::Lifetime(lifetime) = arg && lifetime.is_anonymous() { - self.suggestions.push(( - lifetime.ident.span, - make_suggestion(lifetime), - )); + self.suggestions.push( + lifetime + .suggestion(&self.suggestion_param_name), + ); } } } @@ -602,7 +589,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { } } hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => { - self.suggestions.push((lifetime.ident.span, make_suggestion(lifetime))); + self.suggestions.push(lifetime.suggestion(&self.suggestion_param_name)); } _ => {} } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 4eecde00eaa1..f059bd007689 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -117,8 +117,7 @@ fn relate_mir_and_user_args<'tcx>( CRATE_DEF_ID, ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), ); - let instantiated_predicate = - ocx.normalize(&cause.clone(), param_env, instantiated_predicate); + let instantiated_predicate = ocx.normalize(&cause, param_env, instantiated_predicate); ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate)); } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 7a106796e2d6..e9984da00330 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -240,8 +240,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if !drcx.args_may_unify(obligation_args, bound_trait_ref.skip_binder().args) { continue; } - // FIXME(oli-obk): it is suspicious that we are dropping the constness and - // polarity here. let wc = self.where_clause_may_apply(stack, bound_trait_ref)?; if wc.may_apply() { candidates.vec.push(ParamCandidate(bound)); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 8315564b556a..f82257ab977b 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1,3 +1,8 @@ +//! Core logic responsible for determining what it means for various type system +//! primitives to be "well formed". Actually checking whether these primitives are +//! well formed is performed elsewhere (e.g. during type checking or item well formedness +//! checking). + use std::iter; use rustc_hir as hir; @@ -15,12 +20,13 @@ use tracing::{debug, instrument, trace}; use crate::infer::InferCtxt; use crate::traits; + /// Returns the set of obligations needed to make `arg` well-formed. /// If `arg` contains unresolved inference variables, this may include /// further WF obligations. However, if `arg` IS an unresolved /// inference variable, returns `None`, because we are not able to -/// make any progress at all. This is to prevent "livelock" where we -/// say "$0 is WF if $0 is WF". +/// make any progress at all. This is to prevent cycles where we +/// say "?0 is WF if ?0 is WF". pub fn obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -29,14 +35,14 @@ pub fn obligations<'tcx>( arg: GenericArg<'tcx>, span: Span, ) -> Option> { - // Handle the "livelock" case (see comment above) by bailing out if necessary. + // Handle the "cycle" case (see comment above) by bailing out if necessary. let arg = match arg.unpack() { GenericArgKind::Type(ty) => { match ty.kind() { ty::Infer(ty::TyVar(_)) => { let resolved_ty = infcx.shallow_resolve(ty); if resolved_ty == ty { - // No progress, bail out to prevent "livelock". + // No progress, bail out to prevent cycles. return None; } else { resolved_ty @@ -51,7 +57,7 @@ pub fn obligations<'tcx>( ty::ConstKind::Infer(_) => { let resolved = infcx.shallow_resolve_const(ct); if resolved == ct { - // No progress. + // No progress, bail out to prevent cycles. return None; } else { resolved @@ -74,7 +80,7 @@ pub fn obligations<'tcx>( recursion_depth, item: None, }; - wf.compute(arg); + wf.add_wf_preds_for_generic_arg(arg); debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out); let result = wf.normalize(infcx); @@ -97,7 +103,7 @@ pub fn unnormalized_obligations<'tcx>( // However, if `arg` IS an unresolved inference variable, returns `None`, // because we are not able to make any progress at all. This is to prevent - // "livelock" where we say "$0 is WF if $0 is WF". + // cycles where we say "?0 is WF if ?0 is WF". if arg.is_non_region_infer() { return None; } @@ -115,7 +121,7 @@ pub fn unnormalized_obligations<'tcx>( recursion_depth: 0, item: None, }; - wf.compute(arg); + wf.add_wf_preds_for_generic_arg(arg); Some(wf.out) } @@ -140,7 +146,7 @@ pub fn trait_obligations<'tcx>( recursion_depth: 0, item: Some(item), }; - wf.compute_trait_pred(trait_pred, Elaborate::All); + wf.add_wf_preds_for_trait_pred(trait_pred, Elaborate::All); debug!(obligations = ?wf.out); wf.normalize(infcx) } @@ -171,7 +177,7 @@ pub fn clause_obligations<'tcx>( // It's ok to skip the binder here because wf code is prepared for it match clause.kind().skip_binder() { ty::ClauseKind::Trait(t) => { - wf.compute_trait_pred(t, Elaborate::None); + wf.add_wf_preds_for_trait_pred(t, Elaborate::None); } ty::ClauseKind::HostEffect(..) => { // Technically the well-formedness of this predicate is implied by @@ -179,22 +185,22 @@ pub fn clause_obligations<'tcx>( } ty::ClauseKind::RegionOutlives(..) => {} ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { - wf.compute(ty.into()); + wf.add_wf_preds_for_generic_arg(ty.into()); } ty::ClauseKind::Projection(t) => { - wf.compute_alias_term(t.projection_term); - wf.compute(t.term.into_arg()); + wf.add_wf_preds_for_alias_term(t.projection_term); + wf.add_wf_preds_for_generic_arg(t.term.into_arg()); } ty::ClauseKind::ConstArgHasType(ct, ty) => { - wf.compute(ct.into()); - wf.compute(ty.into()); + wf.add_wf_preds_for_generic_arg(ct.into()); + wf.add_wf_preds_for_generic_arg(ty.into()); } ty::ClauseKind::WellFormed(arg) => { - wf.compute(arg); + wf.add_wf_preds_for_generic_arg(arg); } ty::ClauseKind::ConstEvaluatable(ct) => { - wf.compute(ct.into()); + wf.add_wf_preds_for_generic_arg(ct.into()); } } @@ -372,14 +378,18 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. - fn compute_trait_pred(&mut self, trait_pred: ty::TraitPredicate<'tcx>, elaborate: Elaborate) { + fn add_wf_preds_for_trait_pred( + &mut self, + trait_pred: ty::TraitPredicate<'tcx>, + elaborate: Elaborate, + ) { let tcx = self.tcx(); let trait_ref = trait_pred.trait_ref; // Negative trait predicates don't require supertraits to hold, just // that their args are WF. if trait_pred.polarity == ty::PredicatePolarity::Negative { - self.compute_negative_trait_pred(trait_ref); + self.add_wf_preds_for_negative_trait_pred(trait_ref); return; } @@ -445,15 +455,15 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // Compute the obligations that are required for `trait_ref` to be WF, // given that it is a *negative* trait predicate. - fn compute_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) { + fn add_wf_preds_for_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) { for arg in trait_ref.args { - self.compute(arg); + self.add_wf_preds_for_generic_arg(arg); } } /// Pushes the obligations required for an alias (except inherent) to be WF /// into `self.out`. - fn compute_alias_term(&mut self, data: ty::AliasTerm<'tcx>) { + fn add_wf_preds_for_alias_term(&mut self, data: ty::AliasTerm<'tcx>) { // A projection is well-formed if // // (a) its predicates hold (*) @@ -478,13 +488,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let obligations = self.nominal_obligations(data.def_id, data.args); self.out.extend(obligations); - self.compute_projection_args(data.args); + self.add_wf_preds_for_projection_args(data.args); } /// Pushes the obligations required for an inherent alias to be WF /// into `self.out`. // FIXME(inherent_associated_types): Merge this function with `fn compute_alias`. - fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) { + fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) { // An inherent projection is well-formed if // // (a) its predicates hold (*) @@ -511,7 +521,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { data.args.visit_with(self); } - fn compute_projection_args(&mut self, args: GenericArgsRef<'tcx>) { + fn add_wf_preds_for_projection_args(&mut self, args: GenericArgsRef<'tcx>) { let tcx = self.tcx(); let cause = self.cause(ObligationCauseCode::WellFormed(None)); let param_env = self.param_env; @@ -557,7 +567,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// Pushes all the predicates needed to validate that `ty` is WF into `out`. #[instrument(level = "debug", skip(self))] - fn compute(&mut self, arg: GenericArg<'tcx>) { + fn add_wf_preds_for_generic_arg(&mut self, arg: GenericArg<'tcx>) { arg.visit_with(self); debug!(?self.out); } @@ -596,7 +606,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { .collect() } - fn from_object_ty( + fn add_wf_preds_for_dyn_ty( &mut self, ty: Ty<'tcx>, data: &'tcx ty::List>, @@ -651,6 +661,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { outlives, )); } + + // We don't add any wf predicates corresponding to the trait ref's generic arguments + // which allows code like this to compile: + // ```rust + // trait Trait {} + // fn foo(_: &dyn Trait<[u32]>) {} + // ``` } } } @@ -761,7 +778,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.out.extend(obligations); } ty::Alias(ty::Inherent, data) => { - self.compute_inherent_projection(data); + self.add_wf_preds_for_inherent_projection(data); return; // Subtree handled by compute_inherent_projection. } @@ -895,7 +912,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { // // Here, we defer WF checking due to higher-ranked // regions. This is perhaps not ideal. - self.from_object_ty(t, data, r); + self.add_wf_preds_for_dyn_ty(t, data, r); // FIXME(#27579) RFC also considers adding trait // obligations that don't refer to Self and @@ -917,11 +934,11 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { // 1. Check if they have been resolved, and if so proceed with // THAT type. // 2. If not, we've at least simplified things (e.g., we went - // from `Vec<$0>: WF` to `$0: WF`), so we can + // from `Vec?0>: WF` to `?0: WF`), so we can // register a pending obligation and keep // moving. (Goal is that an "inductive hypothesis" // is satisfied to ensure termination.) - // See also the comment on `fn obligations`, describing "livelock" + // See also the comment on `fn obligations`, describing cycle // prevention, which happens before this can be reached. ty::Infer(_) => { let cause = self.cause(ObligationCauseCode::WellFormed(None)); diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 3d4ab33240af..63ea035bd0e8 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -347,7 +347,8 @@ fn adjust_for_rust_scalar<'tcx>( None }; if let Some(kind) = kind { - attrs.pointee_align = Some(pointee.align); + attrs.pointee_align = + Some(pointee.align.min(cx.tcx().sess.target.max_reliable_alignment())); // `Box` are not necessarily dereferenceable for the entire duration of the function as // they can be deallocated at any time. Same for non-frozen shared references (see diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 041f80c1f2c5..7ad9e59dfede 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -139,7 +139,7 @@ pub struct Iter<'a, T: 'a> { #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for Iter<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Iter").field(&self.iter.clone()).finish() + f.debug_tuple("Iter").field(&self.iter).finish() } } diff --git a/library/alloctests/tests/fmt.rs b/library/alloctests/tests/fmt.rs index c13074c53b73..a20e8c623360 100644 --- a/library/alloctests/tests/fmt.rs +++ b/library/alloctests/tests/fmt.rs @@ -1,6 +1,7 @@ #![deny(warnings)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] +#![cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] use std::cell::RefCell; use std::fmt::{self, Write}; diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 17231df731d1..c7657350a0d9 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -549,8 +549,6 @@ impl Cell { /// # Examples /// /// ``` - /// #![feature(cell_update)] - /// /// use std::cell::Cell; /// /// let c = Cell::new(5); @@ -558,7 +556,7 @@ impl Cell { /// assert_eq!(c.get(), 6); /// ``` #[inline] - #[unstable(feature = "cell_update", issue = "50186")] + #[stable(feature = "cell_update", since = "CURRENT_RUSTC_VERSION")] pub fn update(&self, f: impl FnOnce(T) -> T) { let old = self.get(); self.set(f(old)); diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index ac808038f890..d820965a7463 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -21,6 +21,7 @@ pub(super) const fn from_u32(i: u32) -> Option { /// Converts a `u32` to a `char`, ignoring validity. See [`char::from_u32_unchecked`]. #[inline] #[must_use] +#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char { // SAFETY: the caller must guarantee that `i` is a valid char value. unsafe { @@ -221,6 +222,7 @@ impl FromStr for char { } #[inline] +#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] const fn char_try_from_u32(i: u32) -> Result { // This is an optimized version of the check // (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF), diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index a01efb2adebe..a7563f918a24 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1497,6 +1497,7 @@ pub const fn forget(_: T); /// Turning raw bytes (`[u8; SZ]`) into `u32`, `f64`, etc.: /// /// ``` +/// # #![cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] /// let raw_bytes = [0x78, 0x56, 0x34, 0x12]; /// /// let num = unsafe { @@ -2429,35 +2430,35 @@ pub unsafe fn float_to_int_unchecked(value: Float) -> In /// Stabilized as [`f16::algebraic_add`], [`f32::algebraic_add`], [`f64::algebraic_add`] and [`f128::algebraic_add`]. #[rustc_nounwind] #[rustc_intrinsic] -pub fn fadd_algebraic(a: T, b: T) -> T; +pub const fn fadd_algebraic(a: T, b: T) -> T; /// Float subtraction that allows optimizations based on algebraic rules. /// /// Stabilized as [`f16::algebraic_sub`], [`f32::algebraic_sub`], [`f64::algebraic_sub`] and [`f128::algebraic_sub`]. #[rustc_nounwind] #[rustc_intrinsic] -pub fn fsub_algebraic(a: T, b: T) -> T; +pub const fn fsub_algebraic(a: T, b: T) -> T; /// Float multiplication that allows optimizations based on algebraic rules. /// /// Stabilized as [`f16::algebraic_mul`], [`f32::algebraic_mul`], [`f64::algebraic_mul`] and [`f128::algebraic_mul`]. #[rustc_nounwind] #[rustc_intrinsic] -pub fn fmul_algebraic(a: T, b: T) -> T; +pub const fn fmul_algebraic(a: T, b: T) -> T; /// Float division that allows optimizations based on algebraic rules. /// /// Stabilized as [`f16::algebraic_div`], [`f32::algebraic_div`], [`f64::algebraic_div`] and [`f128::algebraic_div`]. #[rustc_nounwind] #[rustc_intrinsic] -pub fn fdiv_algebraic(a: T, b: T) -> T; +pub const fn fdiv_algebraic(a: T, b: T) -> T; /// Float remainder that allows optimizations based on algebraic rules. /// /// Stabilized as [`f16::algebraic_rem`], [`f32::algebraic_rem`], [`f64::algebraic_rem`] and [`f128::algebraic_rem`]. #[rustc_nounwind] #[rustc_intrinsic] -pub fn frem_algebraic(a: T, b: T) -> T; +pub const fn frem_algebraic(a: T, b: T) -> T; /// Returns the number of bits set in an integer type `T` /// diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 2ee25969289f..b1119d4899ba 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -197,16 +197,22 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128; - /// One greater than the minimum possible normal power of 2 exponent. + /// One greater than the minimum possible *normal* power of 2 exponent + /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// - /// If x = `MIN_EXP`, then normal numbers - /// ≥ 0.5 × 2x. + /// This corresponds to the exact minimum possible *normal* power of 2 exponent + /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). + /// In other words, all normal numbers representable by this type are + /// greater than or equal to 0.5 × 2MIN_EXP. #[unstable(feature = "f128", issue = "116909")] pub const MIN_EXP: i32 = -16_381; - /// Maximum possible power of 2 exponent. + /// One greater than the maximum possible power of 2 exponent + /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// - /// If x = `MAX_EXP`, then normal numbers - /// < 1 × 2x. + /// This corresponds to the exact maximum possible power of 2 exponent + /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). + /// In other words, all numbers representable by this type are + /// strictly less than 2MAX_EXP. #[unstable(feature = "f128", issue = "116909")] pub const MAX_EXP: i32 = 16_384; @@ -804,7 +810,7 @@ impl f128 { } } - /// Calculates the middle point of `self` and `rhs`. + /// Calculates the midpoint (average) between `self` and `rhs`. /// /// This returns NaN when *either* argument is NaN or if a combination of /// +inf and -inf is provided as arguments. @@ -821,6 +827,7 @@ impl f128 { /// # } /// ``` #[inline] + #[doc(alias = "average")] #[unstable(feature = "f128", issue = "116909")] #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn midpoint(self, other: f128) -> f128 { @@ -903,6 +910,7 @@ impl f128 { #[inline] #[unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] pub const fn to_bits(self) -> u128 { // SAFETY: `u128` is a plain old datatype so we can always transmute to it. unsafe { mem::transmute(self) } @@ -950,6 +958,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] pub const fn from_bits(v: u128) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u128` is a plain old datatype so we can always transmute from it. @@ -1373,8 +1382,9 @@ impl f128 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_add(self, rhs: f128) -> f128 { + pub const fn algebraic_add(self, rhs: f128) -> f128 { intrinsics::fadd_algebraic(self, rhs) } @@ -1383,8 +1393,9 @@ impl f128 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_sub(self, rhs: f128) -> f128 { + pub const fn algebraic_sub(self, rhs: f128) -> f128 { intrinsics::fsub_algebraic(self, rhs) } @@ -1393,8 +1404,9 @@ impl f128 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_mul(self, rhs: f128) -> f128 { + pub const fn algebraic_mul(self, rhs: f128) -> f128 { intrinsics::fmul_algebraic(self, rhs) } @@ -1403,8 +1415,9 @@ impl f128 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_div(self, rhs: f128) -> f128 { + pub const fn algebraic_div(self, rhs: f128) -> f128 { intrinsics::fdiv_algebraic(self, rhs) } @@ -1413,8 +1426,9 @@ impl f128 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_rem(self, rhs: f128) -> f128 { + pub const fn algebraic_rem(self, rhs: f128) -> f128 { intrinsics::frem_algebraic(self, rhs) } } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 69882d13c177..54e38d9e1a6f 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -192,16 +192,22 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] pub const MAX: f16 = 6.5504e+4_f16; - /// One greater than the minimum possible normal power of 2 exponent. + /// One greater than the minimum possible *normal* power of 2 exponent + /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// - /// If x = `MIN_EXP`, then normal numbers - /// ≥ 0.5 × 2x. + /// This corresponds to the exact minimum possible *normal* power of 2 exponent + /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). + /// In other words, all normal numbers representable by this type are + /// greater than or equal to 0.5 × 2MIN_EXP. #[unstable(feature = "f16", issue = "116909")] pub const MIN_EXP: i32 = -13; - /// Maximum possible power of 2 exponent. + /// One greater than the maximum possible power of 2 exponent + /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// - /// If x = `MAX_EXP`, then normal numbers - /// < 1 × 2x. + /// This corresponds to the exact maximum possible power of 2 exponent + /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). + /// In other words, all numbers representable by this type are + /// strictly less than 2MAX_EXP. #[unstable(feature = "f16", issue = "116909")] pub const MAX_EXP: i32 = 16; @@ -792,7 +798,7 @@ impl f16 { } } - /// Calculates the middle point of `self` and `rhs`. + /// Calculates the midpoint (average) between `self` and `rhs`. /// /// This returns NaN when *either* argument is NaN or if a combination of /// +inf and -inf is provided as arguments. @@ -808,6 +814,7 @@ impl f16 { /// # } /// ``` #[inline] + #[doc(alias = "average")] #[unstable(feature = "f16", issue = "116909")] #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn midpoint(self, other: f16) -> f16 { @@ -891,6 +898,7 @@ impl f16 { #[inline] #[unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] pub const fn to_bits(self) -> u16 { // SAFETY: `u16` is a plain old datatype so we can always transmute to it. unsafe { mem::transmute(self) } @@ -937,6 +945,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] pub const fn from_bits(v: u16) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u16` is a plain old datatype so we can always transmute from it. @@ -1349,8 +1358,9 @@ impl f16 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_add(self, rhs: f16) -> f16 { + pub const fn algebraic_add(self, rhs: f16) -> f16 { intrinsics::fadd_algebraic(self, rhs) } @@ -1359,8 +1369,9 @@ impl f16 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_sub(self, rhs: f16) -> f16 { + pub const fn algebraic_sub(self, rhs: f16) -> f16 { intrinsics::fsub_algebraic(self, rhs) } @@ -1369,8 +1380,9 @@ impl f16 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_mul(self, rhs: f16) -> f16 { + pub const fn algebraic_mul(self, rhs: f16) -> f16 { intrinsics::fmul_algebraic(self, rhs) } @@ -1379,8 +1391,9 @@ impl f16 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_div(self, rhs: f16) -> f16 { + pub const fn algebraic_div(self, rhs: f16) -> f16 { intrinsics::fdiv_algebraic(self, rhs) } @@ -1389,8 +1402,9 @@ impl f16 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_rem(self, rhs: f16) -> f16 { + pub const fn algebraic_rem(self, rhs: f16) -> f16 { intrinsics::frem_algebraic(self, rhs) } } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 7e056a6c1f3f..e66fd3bb52b8 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -443,16 +443,22 @@ impl f32 { #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const MAX: f32 = 3.40282347e+38_f32; - /// One greater than the minimum possible normal power of 2 exponent. + /// One greater than the minimum possible *normal* power of 2 exponent + /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// - /// If x = `MIN_EXP`, then normal numbers - /// ≥ 0.5 × 2x. + /// This corresponds to the exact minimum possible *normal* power of 2 exponent + /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). + /// In other words, all normal numbers representable by this type are + /// greater than or equal to 0.5 × 2MIN_EXP. #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const MIN_EXP: i32 = -125; - /// Maximum possible power of 2 exponent. + /// One greater than the maximum possible power of 2 exponent + /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// - /// If x = `MAX_EXP`, then normal numbers - /// < 1 × 2x. + /// This corresponds to the exact maximum possible power of 2 exponent + /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). + /// In other words, all numbers representable by this type are + /// strictly less than 2MAX_EXP. #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const MAX_EXP: i32 = 128; @@ -710,8 +716,7 @@ impl f32 { pub const fn is_sign_negative(self) -> bool { // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus // applies to zeros and NaNs as well. - // SAFETY: This is just transmuting to get the sign bit, it's fine. - unsafe { mem::transmute::(self) & 0x8000_0000 != 0 } + self.to_bits() & 0x8000_0000 != 0 } /// Returns the least number greater than `self`. @@ -986,7 +991,7 @@ impl f32 { } } - /// Calculates the middle point of `self` and `rhs`. + /// Calculates the midpoint (average) between `self` and `rhs`. /// /// This returns NaN when *either* argument is NaN or if a combination of /// +inf and -inf is provided as arguments. @@ -998,6 +1003,7 @@ impl f32 { /// assert_eq!((-5.5f32).midpoint(8.0), 1.25); /// ``` #[inline] + #[doc(alias = "average")] #[stable(feature = "num_midpoint", since = "1.85.0")] #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] pub const fn midpoint(self, other: f32) -> f32 { @@ -1096,6 +1102,7 @@ impl f32 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")] #[inline] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] pub const fn to_bits(self) -> u32 { // SAFETY: `u32` is a plain old datatype so we can always transmute to it. unsafe { mem::transmute(self) } @@ -1141,6 +1148,7 @@ impl f32 { #[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")] #[must_use] #[inline] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] pub const fn from_bits(v: u32) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u32` is a plain old datatype so we can always transmute from it. @@ -1515,8 +1523,9 @@ impl f32 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_add(self, rhs: f32) -> f32 { + pub const fn algebraic_add(self, rhs: f32) -> f32 { intrinsics::fadd_algebraic(self, rhs) } @@ -1525,8 +1534,9 @@ impl f32 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_sub(self, rhs: f32) -> f32 { + pub const fn algebraic_sub(self, rhs: f32) -> f32 { intrinsics::fsub_algebraic(self, rhs) } @@ -1535,8 +1545,9 @@ impl f32 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_mul(self, rhs: f32) -> f32 { + pub const fn algebraic_mul(self, rhs: f32) -> f32 { intrinsics::fmul_algebraic(self, rhs) } @@ -1545,8 +1556,9 @@ impl f32 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_div(self, rhs: f32) -> f32 { + pub const fn algebraic_div(self, rhs: f32) -> f32 { intrinsics::fdiv_algebraic(self, rhs) } @@ -1555,8 +1567,9 @@ impl f32 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_rem(self, rhs: f32) -> f32 { + pub const fn algebraic_rem(self, rhs: f32) -> f32 { intrinsics::frem_algebraic(self, rhs) } } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index b9ebbb1d7649..2d791437b282 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -442,16 +442,22 @@ impl f64 { #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const MAX: f64 = 1.7976931348623157e+308_f64; - /// One greater than the minimum possible normal power of 2 exponent. + /// One greater than the minimum possible *normal* power of 2 exponent + /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// - /// If x = `MIN_EXP`, then normal numbers - /// ≥ 0.5 × 2x. + /// This corresponds to the exact minimum possible *normal* power of 2 exponent + /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). + /// In other words, all normal numbers representable by this type are + /// greater than or equal to 0.5 × 2MIN_EXP. #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const MIN_EXP: i32 = -1021; - /// Maximum possible power of 2 exponent. + /// One greater than the maximum possible power of 2 exponent + /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// - /// If x = `MAX_EXP`, then normal numbers - /// < 1 × 2x. + /// This corresponds to the exact maximum possible power of 2 exponent + /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). + /// In other words, all numbers representable by this type are + /// strictly less than 2MAX_EXP. #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const MAX_EXP: i32 = 1024; @@ -718,8 +724,7 @@ impl f64 { pub const fn is_sign_negative(self) -> bool { // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus // applies to zeros and NaNs as well. - // SAFETY: This is just transmuting to get the sign bit, it's fine. - unsafe { mem::transmute::(self) & Self::SIGN_MASK != 0 } + self.to_bits() & Self::SIGN_MASK != 0 } #[must_use] @@ -1004,7 +1009,7 @@ impl f64 { } } - /// Calculates the middle point of `self` and `rhs`. + /// Calculates the midpoint (average) between `self` and `rhs`. /// /// This returns NaN when *either* argument is NaN or if a combination of /// +inf and -inf is provided as arguments. @@ -1016,6 +1021,7 @@ impl f64 { /// assert_eq!((-5.5f64).midpoint(8.0), 1.25); /// ``` #[inline] + #[doc(alias = "average")] #[stable(feature = "num_midpoint", since = "1.85.0")] #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] pub const fn midpoint(self, other: f64) -> f64 { @@ -1094,6 +1100,7 @@ impl f64 { without modifying the original"] #[stable(feature = "float_bits_conv", since = "1.20.0")] #[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] #[inline] pub const fn to_bits(self) -> u64 { // SAFETY: `u64` is a plain old datatype so we can always transmute to it. @@ -1140,6 +1147,7 @@ impl f64 { #[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")] #[must_use] #[inline] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] pub const fn from_bits(v: u64) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u64` is a plain old datatype so we can always transmute from it. @@ -1514,8 +1522,9 @@ impl f64 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_add(self, rhs: f64) -> f64 { + pub const fn algebraic_add(self, rhs: f64) -> f64 { intrinsics::fadd_algebraic(self, rhs) } @@ -1524,8 +1533,9 @@ impl f64 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_sub(self, rhs: f64) -> f64 { + pub const fn algebraic_sub(self, rhs: f64) -> f64 { intrinsics::fsub_algebraic(self, rhs) } @@ -1534,8 +1544,9 @@ impl f64 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_mul(self, rhs: f64) -> f64 { + pub const fn algebraic_mul(self, rhs: f64) -> f64 { intrinsics::fmul_algebraic(self, rhs) } @@ -1544,8 +1555,9 @@ impl f64 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_div(self, rhs: f64) -> f64 { + pub const fn algebraic_div(self, rhs: f64) -> f64 { intrinsics::fdiv_algebraic(self, rhs) } @@ -1554,8 +1566,9 @@ impl f64 { /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "float_algebraic", issue = "136469")] + #[rustc_const_unstable(feature = "float_algebraic", issue = "136469")] #[inline] - pub fn algebraic_rem(self, rhs: f64) -> f64 { + pub const fn algebraic_rem(self, rhs: f64) -> f64 { intrinsics::frem_algebraic(self, rhs) } } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 05d8216ac27e..8d31a7b697a8 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -3675,6 +3675,7 @@ macro_rules! int_impl { /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes #[must_use = "this returns the result of the operation, \ @@ -3778,6 +3779,7 @@ macro_rules! int_impl { /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] #[must_use] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 348457e2c00f..ecc1c7bf9021 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -130,7 +130,7 @@ depending on the target pointer size. macro_rules! midpoint_impl { ($SelfT:ty, unsigned) => { - /// Calculates the middle point of `self` and `rhs`. + /// Calculates the midpoint (average) between `self` and `rhs`. /// /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a /// sufficiently-large unsigned integral type. This implies that the result is @@ -146,6 +146,8 @@ macro_rules! midpoint_impl { #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] + #[doc(alias = "average_floor")] + #[doc(alias = "average")] #[inline] pub const fn midpoint(self, rhs: $SelfT) -> $SelfT { // Use the well known branchless algorithm from Hacker's Delight to compute @@ -154,7 +156,7 @@ macro_rules! midpoint_impl { } }; ($SelfT:ty, signed) => { - /// Calculates the middle point of `self` and `rhs`. + /// Calculates the midpoint (average) between `self` and `rhs`. /// /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a /// sufficiently-large signed integral type. This implies that the result is @@ -173,6 +175,9 @@ macro_rules! midpoint_impl { #[rustc_const_stable(feature = "num_midpoint_signed", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] + #[doc(alias = "average_floor")] + #[doc(alias = "average_ceil")] + #[doc(alias = "average")] #[inline] pub const fn midpoint(self, rhs: Self) -> Self { // Use the well known branchless algorithm from Hacker's Delight to compute @@ -184,7 +189,7 @@ macro_rules! midpoint_impl { } }; ($SelfT:ty, $WideT:ty, unsigned) => { - /// Calculates the middle point of `self` and `rhs`. + /// Calculates the midpoint (average) between `self` and `rhs`. /// /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a /// sufficiently-large unsigned integral type. This implies that the result is @@ -200,13 +205,15 @@ macro_rules! midpoint_impl { #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] + #[doc(alias = "average_floor")] + #[doc(alias = "average")] #[inline] pub const fn midpoint(self, rhs: $SelfT) -> $SelfT { ((self as $WideT + rhs as $WideT) / 2) as $SelfT } }; ($SelfT:ty, $WideT:ty, signed) => { - /// Calculates the middle point of `self` and `rhs`. + /// Calculates the midpoint (average) between `self` and `rhs`. /// /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a /// sufficiently-large signed integral type. This implies that the result is @@ -225,6 +232,9 @@ macro_rules! midpoint_impl { #[rustc_const_stable(feature = "num_midpoint_signed", since = "1.87.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] + #[doc(alias = "average_floor")] + #[doc(alias = "average_ceil")] + #[doc(alias = "average")] #[inline] pub const fn midpoint(self, rhs: $SelfT) -> $SelfT { ((self as $WideT + rhs as $WideT) / 2) as $SelfT diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 1b79112aec1f..8a8b2733d5e8 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1589,7 +1589,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { super::int_log10::$Int(self.get()) } - /// Calculates the middle point of `self` and `rhs`. + /// Calculates the midpoint (average) between `self` and `rhs`. /// /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a /// sufficiently-large signed integral type. This implies that the result is @@ -1615,6 +1615,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] + #[doc(alias = "average_floor")] + #[doc(alias = "average")] #[inline] pub const fn midpoint(self, rhs: Self) -> Self { // SAFETY: The only way to get `0` with midpoint is to have two opposite or diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 3678bb091e7d..bc6cb9508167 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -3523,6 +3523,7 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes #[inline] @@ -3624,6 +3625,7 @@ macro_rules! uint_impl { /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] #[must_use] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index ac1115759383..ef548971aafa 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -12,7 +12,6 @@ #![feature(async_iterator)] #![feature(bigint_helper_methods)] #![feature(bstr)] -#![feature(cell_update)] #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(const_eval_select)] diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 0eef2bd225c0..9ad26e5d28ec 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -973,6 +973,9 @@ where /// Returns an array of length `N` with the results of each query. For soundness, at most one /// mutable reference will be returned to any value. `None` will be used if the key is missing. /// + /// This method performs a check to ensure there are no duplicate keys, which currently has a time-complexity of O(n^2), + /// so be careful when passing many keys. + /// /// # Panics /// /// Panics if any keys are overlapping. diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 0427feb29550..4f9259f39c1a 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -1100,3 +1100,39 @@ pub fn lchown>(dir: P, uid: Option, gid: Option) -> io: pub fn chroot>(dir: P) -> io::Result<()> { sys::fs::chroot(dir.as_ref()) } + +/// Create a FIFO special file at the specified path with the specified mode. +/// +/// # Examples +/// +/// ```no_run +/// # #![feature(unix_mkfifo)] +/// # #[cfg(not(unix))] +/// # fn main() {} +/// # #[cfg(unix)] +/// # fn main() -> std::io::Result<()> { +/// # use std::{ +/// # os::unix::fs::{mkfifo, PermissionsExt}, +/// # fs::{File, Permissions, remove_file}, +/// # io::{Write, Read}, +/// # }; +/// # let _ = remove_file("/tmp/fifo"); +/// mkfifo("/tmp/fifo", Permissions::from_mode(0o774))?; +/// +/// let mut wx = File::options().read(true).write(true).open("/tmp/fifo")?; +/// let mut rx = File::open("/tmp/fifo")?; +/// +/// wx.write_all(b"hello, world!")?; +/// drop(wx); +/// +/// let mut s = String::new(); +/// rx.read_to_string(&mut s)?; +/// +/// assert_eq!(s, "hello, world!"); +/// # Ok(()) +/// # } +/// ``` +#[unstable(feature = "unix_mkfifo", issue = "139324")] +pub fn mkfifo>(path: P, permissions: Permissions) -> io::Result<()> { + sys::fs::mkfifo(path.as_ref(), permissions.mode()) +} diff --git a/library/std/src/os/unix/fs/tests.rs b/library/std/src/os/unix/fs/tests.rs index db9621c8c205..1840bb38c17c 100644 --- a/library/std/src/os/unix/fs/tests.rs +++ b/library/std/src/os/unix/fs/tests.rs @@ -55,3 +55,23 @@ fn write_vectored_at() { let content = fs::read(&filename).unwrap(); assert_eq!(&content, expected); } + +#[test] +fn test_mkfifo() { + let tmp_dir = crate::test_helpers::tmpdir(); + + let fifo = tmp_dir.path().join("fifo"); + + mkfifo(&fifo, Permissions::from_mode(0o774)).unwrap(); + + let mut wx = fs::File::options().read(true).write(true).open(&fifo).unwrap(); + let mut rx = fs::File::open(fifo).unwrap(); + + wx.write_all(b"hello, world!").unwrap(); + drop(wx); + + let mut s = String::new(); + rx.read_to_string(&mut s).unwrap(); + + assert_eq!(s, "hello, world!"); +} diff --git a/library/std/src/sys/env_consts.rs b/library/std/src/sys/env_consts.rs index 018d7954db26..9683fd47cf96 100644 --- a/library/std/src/sys/env_consts.rs +++ b/library/std/src/sys/env_consts.rs @@ -389,6 +389,17 @@ pub mod os { pub const EXE_EXTENSION: &str = "exe"; } +#[cfg(target_os = "zkvm")] +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = ""; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".elf"; + pub const DLL_EXTENSION: &str = "elf"; + pub const EXE_SUFFIX: &str = ".elf"; + pub const EXE_EXTENSION: &str = "elf"; +} + // The fallback when none of the other gates match. #[else] pub mod os { diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 4c5e36ce67a3..d55e28074fe8 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -9,7 +9,7 @@ cfg_if::cfg_if! { if #[cfg(target_family = "unix")] { mod unix; use unix as imp; - pub use unix::{chown, fchown, lchown}; + pub use unix::{chown, fchown, lchown, mkfifo}; #[cfg(not(target_os = "fuchsia"))] pub use unix::chroot; pub(crate) use unix::debug_assert_fd_is_open; diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index bc8817bac704..351a9f9413f6 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -2137,6 +2137,12 @@ pub fn chroot(dir: &Path) -> io::Result<()> { Err(io::const_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks")) } +pub fn mkfifo(path: &Path, mode: u32) -> io::Result<()> { + run_path_with_cstr(path, &|path| { + cvt(unsafe { libc::mkfifo(path.as_ptr(), mode.try_into().unwrap()) }).map(|_| ()) + }) +} + pub use remove_dir_impl::remove_dir_all; // Fallback for REDOX, ESP-ID, Horizon, Vita, Vxworks and Miri diff --git a/library/std/src/sys/pal/zkvm/env.rs b/library/std/src/sys/pal/zkvm/env.rs deleted file mode 100644 index b85153642b1c..000000000000 --- a/library/std/src/sys/pal/zkvm/env.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = ""; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".elf"; - pub const DLL_EXTENSION: &str = "elf"; - pub const EXE_SUFFIX: &str = ".elf"; - pub const EXE_EXTENSION: &str = "elf"; -} diff --git a/library/stdarch b/library/stdarch index 4666c7376f25..1245618ccf5b 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 4666c7376f25a265c74535585d622da3da6dfeb1 +Subproject commit 1245618ccf5b2df7ab1ebb0279b9f3f726670161 diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 83083e12ef1f..9d07babe5196 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -683,7 +683,7 @@ impl Step for Editor { match EditorKind::prompt_user() { Ok(editor_kind) => { if let Some(editor_kind) = editor_kind { - while !t!(create_editor_settings_maybe(config, editor_kind.clone())) {} + while !t!(create_editor_settings_maybe(config, &editor_kind)) {} } else { println!("Ok, skipping editor setup!"); } @@ -695,7 +695,7 @@ impl Step for Editor { /// Create the recommended editor LSP config file for rustc development, or just print it /// If this method should be re-called, it returns `false`. -fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Result { +fn create_editor_settings_maybe(config: &Config, editor: &EditorKind) -> io::Result { let hashes = editor.hashes(); let (current_hash, historical_hashes) = hashes.split_last().unwrap(); let settings_path = editor.settings_path(config); @@ -752,7 +752,7 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu // exists but user modified, back it up Some(false) => { // exists and is not current version or outdated, so back it up - let backup = settings_path.clone().with_extension(editor.backup_extension()); + let backup = settings_path.with_extension(editor.backup_extension()); eprintln!( "WARNING: copying `{}` to `{}`", settings_path.file_name().unwrap().to_str().unwrap(), diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs index 6a6731cafc54..fd4918961adb 100644 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ b/src/bootstrap/src/core/build_steps/suggest.rs @@ -13,7 +13,6 @@ pub fn suggest(builder: &Builder<'_>, run: bool) { let git_config = builder.config.git_config(); let suggestions = builder .tool_cmd(Tool::SuggestTests) - .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository) .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch) .env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email) .run_capture_stdout(builder) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 096f7de65975..d4fccc535a6b 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2064,7 +2064,6 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the } let git_config = builder.config.git_config(); - cmd.arg("--git-repository").arg(git_config.git_repository); cmd.arg("--nightly-branch").arg(git_config.nightly_branch); cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email); cmd.force_coloring_in_ci(); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 419976c83b1d..23b623d9bab2 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2963,7 +2963,6 @@ impl Config { pub fn git_config(&self) -> GitConfig<'_> { GitConfig { - git_repository: &self.stage0_metadata.config.git_repository, nightly_branch: &self.stage0_metadata.config.nightly_branch, git_merge_commit_email: &self.stage0_metadata.config.git_merge_commit_email, } diff --git a/src/bootstrap/src/utils/tests/git.rs b/src/bootstrap/src/utils/tests/git.rs index 99e0793af466..bd40f398c7b1 100644 --- a/src/bootstrap/src/utils/tests/git.rs +++ b/src/bootstrap/src/utils/tests/git.rs @@ -135,7 +135,6 @@ impl GitCtx { fn git_config(&self) -> GitConfig<'_> { GitConfig { - git_repository: &self.git_repo, nightly_branch: &self.nightly_branch, git_merge_commit_email: &self.merge_bot_email, } diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 8d53a83ea317..438cd14389c1 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -5,7 +5,6 @@ use crate::ci::CiEnv; #[derive(Debug)] pub struct GitConfig<'a> { - pub git_repository: &'a str, pub nightly_branch: &'a str, pub git_merge_commit_email: &'a str, } diff --git a/src/build_helper/src/stage0_parser.rs b/src/build_helper/src/stage0_parser.rs index 2a0c12a1c91c..2723f4aa7b91 100644 --- a/src/build_helper/src/stage0_parser.rs +++ b/src/build_helper/src/stage0_parser.rs @@ -20,7 +20,6 @@ pub struct Stage0Config { pub artifacts_server: String, pub artifacts_with_llvm_assertions_server: String, pub git_merge_commit_email: String, - pub git_repository: String, pub nightly_branch: String, } @@ -49,7 +48,6 @@ pub fn parse_stage0_file() -> Stage0 { stage0.config.artifacts_with_llvm_assertions_server = value.to_owned() } "git_merge_commit_email" => stage0.config.git_merge_commit_email = value.to_owned(), - "git_repository" => stage0.config.git_repository = value.to_owned(), "nightly_branch" => stage0.config.nightly_branch = value.to_owned(), "compiler_date" => stage0.compiler.date = value.to_owned(), diff --git a/src/doc/rustc-dev-guide/src/tests/minicore.md b/src/doc/rustc-dev-guide/src/tests/minicore.md index e4853b6d40e3..507b259e0275 100644 --- a/src/doc/rustc-dev-guide/src/tests/minicore.md +++ b/src/doc/rustc-dev-guide/src/tests/minicore.md @@ -6,25 +6,37 @@ ui/codegen/assembly test suites. It provides `core` stubs for tests that need to build for cross-compiled targets but do not need/want to run. -A test can use [`minicore`] by specifying the `//@ add-core-stubs` directive. -Then, mark the test with `#![feature(no_core)]` + `#![no_std]` + `#![no_core]`. -Due to Edition 2015 extern prelude rules, you will probably need to declare -`minicore` as an extern crate. - -Due to the `no_std` + `no_core` nature of these tests, `//@ add-core-stubs` -implies and requires that the test will be built with `-C panic=abort`. -Unwinding panics are not supported. - -If you find a `core` item to be missing from the [`minicore`] stub, consider -adding it to the test auxiliary if it's likely to be used or is already needed -by more than one test. -
Please note that [`minicore`] is only intended for `core` items, and explicitly **not** `std` or `alloc` items because `core` items are applicable to a wider range of tests.
+A test can use [`minicore`] by specifying the `//@ add-core-stubs` directive. +Then, mark the test with `#![feature(no_core)]` + `#![no_std]` + `#![no_core]`. +Due to Edition 2015 extern prelude rules, you will probably need to declare +`minicore` as an extern crate. + +## Implied compiler flags + +Due to the `no_std` + `no_core` nature of these tests, `//@ add-core-stubs` +implies and requires that the test will be built with `-C panic=abort`. +**Unwinding panics are not supported.** + +Tests will also be built with `-C force-unwind-tables=yes` to preserve CFI +directives in assembly tests. + +TL;DR: `//@ add-core-stubs` implies two compiler flags: + +1. `-C panic=abort` +2. `-C force-unwind-tables=yes` + +## Adding more `core` stubs + +If you find a `core` item to be missing from the [`minicore`] stub, consider +adding it to the test auxiliary if it's likely to be used or is already needed +by more than one test. + ## Example codegen test that uses `minicore` ```rust,no_run diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 9870e5011ebf..50c7ae3ef8db 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -34,7 +34,7 @@ target | notes -------|------- [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+) -`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] +`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI] [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+) [`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+) @@ -43,6 +43,8 @@ target | notes [^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. Functions with the default Rust ABI are not affected. See [issue #115567][x86-32-float-return-issue]. +[^win32-msvc-alignment]: Due to non-standard behavior of MSVC, native C code on this target can cause types with an alignment of more than 4 bytes to be incorrectly aligned to only 4 bytes (this affects, e.g., `u64` and `i64`). Rust applies some mitigations to reduce the impact of this issue, but this can still cause unsoundness due to unsafe code that (correctly) assumes that references are always properly aligned. See [issue #112480](https://github.com/rust-lang/rust/issues/112480). + [77071]: https://github.com/rust-lang/rust/issues/77071 [x86-32-float-return-issue]: https://github.com/rust-lang/rust/issues/115567 @@ -95,7 +97,7 @@ target | notes [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) -[`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] +[`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17) `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17) [`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10, glibc 2.17) @@ -169,7 +171,7 @@ target | std | notes [`i686-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI] [`i686-unknown-freebsd`](platform-support/freebsd.md) | ✓ | 32-bit x86 FreeBSD (Pentium 4) [^x86_32-floats-return-ABI] `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 (Pentium 4) [^x86_32-floats-return-ABI] -[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI (Pentium 4, softfloat) +[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI (Pentium 4, softfloat) [^win32-msvc-alignment] [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI) [`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64S ABI) [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs] @@ -317,9 +319,9 @@ target | std | host | notes [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 (Pentium 4) [^x86_32-floats-return-ABI] [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD (Pentium 4) [^x86_32-floats-return-ABI] `i686-uwp-windows-gnu` | ✓ | | [^x86_32-floats-return-ABI] -[`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | [^x86_32-floats-return-ABI] +[`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | [^x86_32-floats-return-ABI] [^win32-msvc-alignment] [`i686-win7-windows-gnu`](platform-support/win7-windows-gnu.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] -[`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] +[`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] [^win32-msvc-alignment] [`i686-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [^x86_32-floats-return-ABI] [`loongarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | LoongArch64 OpenHarmony [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? | | Motorola 680x0 Linux diff --git a/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md b/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md index 60aaa371bbc1..e98aa996a6e5 100644 --- a/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md +++ b/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md @@ -20,8 +20,9 @@ The `target_os` of the target is `cygwin`, and it is `unix`. ## Building the target -For cross-compilation you want LLVM with [llvm/llvm-project#121439 (merged)](https://github.com/llvm/llvm-project/pull/121439) applied to fix the LLVM codegen on importing external global variables from DLLs. -No native builds on Cygwin now. It should be possible theoretically though, but might need a lot of patches. +For cross-compilation you want LLVM at least 20.1.0-rc1. +No native builds on Cygwin now. +The tracking issue for host tools on Cygwin is [#137819](https://github.com/rust-lang/rust/issues/137819). ## Building Rust programs diff --git a/src/doc/unstable-book/src/language-features/deref-patterns.md b/src/doc/unstable-book/src/language-features/deref-patterns.md index d0102a665b0b..d0a64538e8cc 100644 --- a/src/doc/unstable-book/src/language-features/deref-patterns.md +++ b/src/doc/unstable-book/src/language-features/deref-patterns.md @@ -54,4 +54,25 @@ if let [b] = &mut *v { assert_eq!(v, [Box::new(Some(2))]); ``` +Additionally, when `deref_patterns` is enabled, string literal patterns may be written where `str` +is expected. Likewise, byte string literal patterns may be written where `[u8]` or `[u8; _]` is +expected. This lets them be used in `deref!(_)` patterns: + +```rust +# #![feature(deref_patterns)] +# #![allow(incomplete_features)] +match ("test".to_string(), b"test".to_vec()) { + (deref!("test"), deref!(b"test")) => {} + _ => panic!(), +} + +// Matching on slices and arrays using literals is possible elsewhere as well: +match *"test" { + "test" => {} + _ => panic!(), +} +``` + +Implicit deref pattern syntax is not yet supported for string or byte string literals. + [smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors diff --git a/src/stage0 b/src/stage0 index 6e86501a72ab..06080e3a8c16 100644 --- a/src/stage0 +++ b/src/stage0 @@ -2,7 +2,6 @@ dist_server=https://static.rust-lang.org artifacts_server=https://ci-artifacts.rust-lang.org/rustc-builds artifacts_with_llvm_assertions_server=https://ci-artifacts.rust-lang.org/rustc-builds-alt git_merge_commit_email=bors@rust-lang.org -git_repository=rust-lang/rust nightly_branch=master # The configuration above this comment is editable, and can be changed diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs index d679084ae44b..680437cce4fa 100644 --- a/src/tools/bump-stage0/src/main.rs +++ b/src/tools/bump-stage0/src/main.rs @@ -61,7 +61,6 @@ impl Tool { artifacts_server, artifacts_with_llvm_assertions_server, git_merge_commit_email, - git_repository, nightly_branch, } = &self.config; @@ -72,7 +71,6 @@ impl Tool { artifacts_with_llvm_assertions_server )); file_content.push_str(&format!("git_merge_commit_email={}\n", git_merge_commit_email)); - file_content.push_str(&format!("git_repository={}\n", git_repository)); file_content.push_str(&format!("nightly_branch={}\n", nightly_branch)); file_content.push_str("\n"); diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed index c82276b358e1..e696896538e5 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed @@ -1,7 +1,13 @@ //@aux-build:proc_macro_attr.rs #![warn(clippy::blocks_in_conditions)] -#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)] +#![allow( + unused, + unnecessary_transmutes, + clippy::let_and_return, + clippy::needless_if, + clippy::missing_transmute_annotations +)] #![warn(clippy::nonminimal_bool)] macro_rules! blocky { diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs index 6a4a7c621068..8c8f3249b8a7 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs @@ -1,7 +1,13 @@ //@aux-build:proc_macro_attr.rs #![warn(clippy::blocks_in_conditions)] -#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)] +#![allow( + unused, + unnecessary_transmutes, + clippy::let_and_return, + clippy::needless_if, + clippy::missing_transmute_annotations +)] #![warn(clippy::nonminimal_bool)] macro_rules! blocky { diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr index e57eca5dceef..41ff59c683e8 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr @@ -1,5 +1,5 @@ error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions.rs:25:5 + --> tests/ui/blocks_in_conditions.rs:31:5 | LL | / if { LL | | @@ -20,13 +20,13 @@ LL ~ }; if res { | error: omit braces around single expression condition - --> tests/ui/blocks_in_conditions.rs:37:8 + --> tests/ui/blocks_in_conditions.rs:43:8 | LL | if { true } { 6 } else { 10 } | ^^^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> tests/ui/blocks_in_conditions.rs:43:8 + --> tests/ui/blocks_in_conditions.rs:49:8 | LL | if true && x == 3 { 6 } else { 10 } | ^^^^^^^^^^^^^^ help: try: `x == 3` diff --git a/src/tools/clippy/tests/ui/crashes/ice-1782.rs b/src/tools/clippy/tests/ui/crashes/ice-1782.rs index 4a1886c08af6..776b0a93bf7c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-1782.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-1782.rs @@ -1,6 +1,6 @@ //@ check-pass -#![allow(dead_code, unused_variables, invalid_null_arguments)] +#![allow(dead_code, unused_variables, invalid_null_arguments, unnecessary_transmutes)] #![allow(clippy::unnecessary_cast, clippy::missing_transmute_annotations)] /// Should not trigger an ICE in `SpanlessEq` / `consts::constant` diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index 8c8674ac356d..2b8b6c539ad3 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -3,6 +3,7 @@ #![allow( dead_code, clippy::borrow_as_ptr, + unnecessary_transmutes, clippy::needless_lifetimes, clippy::missing_transmute_annotations )] diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index 4219e09d2aba..1bb70151965c 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -1,5 +1,5 @@ error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:32:27 + --> tests/ui/transmute.rs:33:27 | LL | let _: *const T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` @@ -8,61 +8,61 @@ LL | let _: *const T = core::mem::transmute(t); = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:35:25 + --> tests/ui/transmute.rs:36:25 | LL | let _: *mut T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:38:27 + --> tests/ui/transmute.rs:39:27 | LL | let _: *const U = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:46:27 + --> tests/ui/transmute.rs:47:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:49:27 + --> tests/ui/transmute.rs:50:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:52:27 + --> tests/ui/transmute.rs:53:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:55:27 + --> tests/ui/transmute.rs:56:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:58:27 + --> tests/ui/transmute.rs:59:27 | LL | let _: Vec = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:61:31 + --> tests/ui/transmute.rs:62:31 | LL | let _: *const usize = std::mem::transmute(5_isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:66:31 + --> tests/ui/transmute.rs:67:31 | LL | let _: *const usize = std::mem::transmute(1 + 1usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:98:24 + --> tests/ui/transmute.rs:99:24 | LL | let _: Usize = core::mem::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,25 +71,25 @@ LL | let _: Usize = core::mem::transmute(int_const_ptr); = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:101:24 + --> tests/ui/transmute.rs:102:24 | LL | let _: Usize = core::mem::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> tests/ui/transmute.rs:104:31 + --> tests/ui/transmute.rs:105:31 | LL | let _: *const Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> tests/ui/transmute.rs:107:29 + --> tests/ui/transmute.rs:108:29 | LL | let _: *mut Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u8` to a `bool` - --> tests/ui/transmute.rs:114:28 + --> tests/ui/transmute.rs:115:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -98,7 +98,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `u16` to a `f16` - --> tests/ui/transmute.rs:121:31 + --> tests/ui/transmute.rs:122:31 | LL | let _: f16 = unsafe { std::mem::transmute(0_u16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` @@ -107,97 +107,97 @@ LL | let _: f16 = unsafe { std::mem::transmute(0_u16) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]` error: transmute from a `i16` to a `f16` - --> tests/ui/transmute.rs:124:31 + --> tests/ui/transmute.rs:125:31 | LL | let _: f16 = unsafe { std::mem::transmute(0_i16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_i16 as u16)` error: transmute from a `u32` to a `f32` - --> tests/ui/transmute.rs:127:31 + --> tests/ui/transmute.rs:128:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:130:31 + --> tests/ui/transmute.rs:131:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` error: transmute from a `u64` to a `f64` - --> tests/ui/transmute.rs:133:31 + --> tests/ui/transmute.rs:134:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)` error: transmute from a `i64` to a `f64` - --> tests/ui/transmute.rs:136:31 + --> tests/ui/transmute.rs:137:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `u128` to a `f128` - --> tests/ui/transmute.rs:139:32 + --> tests/ui/transmute.rs:140:32 | LL | let _: f128 = unsafe { std::mem::transmute(0_u128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_u128)` error: transmute from a `i128` to a `f128` - --> tests/ui/transmute.rs:142:32 + --> tests/ui/transmute.rs:143:32 | LL | let _: f128 = unsafe { std::mem::transmute(0_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` error: transmute from a `u16` to a `f16` - --> tests/ui/transmute.rs:147:39 + --> tests/ui/transmute.rs:148:39 | LL | const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` error: transmute from a `u32` to a `f32` - --> tests/ui/transmute.rs:150:39 + --> tests/ui/transmute.rs:151:39 | LL | const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` error: transmute from a `i64` to a `f64` - --> tests/ui/transmute.rs:153:39 + --> tests/ui/transmute.rs:154:39 | LL | const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `i128` to a `f128` - --> tests/ui/transmute.rs:156:41 + --> tests/ui/transmute.rs:157:41 | LL | const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` error: transmute from a `i16` to a `f16` - --> tests/ui/transmute.rs:160:22 + --> tests/ui/transmute.rs:161:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)` error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:165:22 + --> tests/ui/transmute.rs:166:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)` error: transmute from a `u64` to a `f64` - --> tests/ui/transmute.rs:170:22 + --> tests/ui/transmute.rs:171:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)` error: transmute from a `u128` to a `f128` - --> tests/ui/transmute.rs:175:22 + --> tests/ui/transmute.rs:176:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:184:30 + --> tests/ui/transmute.rs:185:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` @@ -206,121 +206,121 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8); = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:187:30 + --> tests/ui/transmute.rs:188:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:190:31 + --> tests/ui/transmute.rs:191:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:193:30 + --> tests/ui/transmute.rs:194:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:196:30 + --> tests/ui/transmute.rs:197:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:199:31 + --> tests/ui/transmute.rs:200:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:202:30 + --> tests/ui/transmute.rs:203:30 | LL | let _: [u8; 2] = std::mem::transmute(0.0f16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:205:30 + --> tests/ui/transmute.rs:206:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:208:30 + --> tests/ui/transmute.rs:209:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:211:31 + --> tests/ui/transmute.rs:212:31 | LL | let _: [u8; 16] = std::mem::transmute(0.0f128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:217:30 + --> tests/ui/transmute.rs:218:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:220:30 + --> tests/ui/transmute.rs:221:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:223:31 + --> tests/ui/transmute.rs:224:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:226:30 + --> tests/ui/transmute.rs:227:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:229:30 + --> tests/ui/transmute.rs:230:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:232:31 + --> tests/ui/transmute.rs:233:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:235:30 + --> tests/ui/transmute.rs:236:30 | LL | let _: [u8; 2] = std::mem::transmute(0.0f16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:238:30 + --> tests/ui/transmute.rs:239:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:241:30 + --> tests/ui/transmute.rs:242:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:244:31 + --> tests/ui/transmute.rs:245:31 | LL | let _: [u8; 16] = std::mem::transmute(0.0f128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:253:28 + --> tests/ui/transmute.rs:254:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -329,13 +329,13 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:256:32 + --> tests/ui/transmute.rs:257:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:259:30 + --> tests/ui/transmute.rs:260:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed index 1f97b997eaa0..844445907d7c 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed @@ -1,5 +1,5 @@ #![warn(clippy::transmute_float_to_int)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] #![feature(f128)] #![feature(f16)] diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.rs b/src/tools/clippy/tests/ui/transmute_float_to_int.rs index 788a7e1026c6..a1f3b15bbfee 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs @@ -1,5 +1,5 @@ #![warn(clippy::transmute_float_to_int)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] #![feature(f128)] #![feature(f16)] diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed index b5425a2e9e85..28644aa9ebbb 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed @@ -1,5 +1,5 @@ #![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] fn int_to_char() { let _: char = unsafe { std::char::from_u32(0_u32).unwrap() }; diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.rs b/src/tools/clippy/tests/ui/transmute_int_to_char.rs index b24bb177c9fc..8c83ecc8914b 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char.rs +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.rs @@ -1,5 +1,5 @@ #![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] fn int_to_char() { let _: char = unsafe { std::mem::transmute(0_u32) }; diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed index e525751e306e..e6e09a2be4bf 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed +++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed @@ -1,7 +1,7 @@ #![no_std] #![feature(lang_items)] #![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] use core::panic::PanicInfo; diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs index 7cb508ceaf3b..0f2106df00e6 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs +++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs @@ -1,7 +1,7 @@ #![no_std] #![feature(lang_items)] #![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations)] +#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] use core::panic::PanicInfo; diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index de93e2b99eed..e0132056d6c4 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -399,7 +399,6 @@ pub struct Config { pub nocapture: bool, // Needed both to construct build_helper::git::GitConfig - pub git_repository: String, pub nightly_branch: String, pub git_merge_commit_email: String, @@ -514,7 +513,6 @@ impl Config { pub fn git_config(&self) -> GitConfig<'_> { GitConfig { - git_repository: &self.git_repository, nightly_branch: &self.nightly_branch, git_merge_commit_email: &self.git_merge_commit_email, } diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 2525e0adc838..e7e5ff0ab009 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -175,7 +175,6 @@ impl ConfigBuilder { self.host.as_deref().unwrap_or("x86_64-unknown-linux-gnu"), "--target", self.target.as_deref().unwrap_or("x86_64-unknown-linux-gnu"), - "--git-repository=", "--nightly-branch=", "--git-merge-commit-email=", "--minicore-path=", diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 7948a273c1e8..0a3888a7d50a 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -188,7 +188,6 @@ pub fn parse_config(args: Vec) -> Config { "run tests which rely on commit version being compiled into the binaries", ) .optopt("", "edition", "default Rust edition", "EDITION") - .reqopt("", "git-repository", "name of the git repository", "ORG/REPO") .reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH") .reqopt( "", @@ -440,7 +439,6 @@ pub fn parse_config(args: Vec) -> Config { nocapture: matches.opt_present("no-capture"), - git_repository: matches.opt_str("git-repository").unwrap(), nightly_branch: matches.opt_str("nightly-branch").unwrap(), git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index cc09463c358a..fe23cce81e90 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1710,12 +1710,16 @@ impl<'test> TestCx<'test> { rustc.args(&self.props.compile_flags); // FIXME(jieyouxu): we should report a fatal error or warning if user wrote `-Cpanic=` with - // something that's not `abort`, however, by moving this last we should override previous - // `-Cpanic=`s + // something that's not `abort` and `-Cforce-unwind-tables` with a value that is not `yes`, + // however, by moving this last we should override previous `-Cpanic`s and + // `-Cforce-unwind-tables`s. Note that checking here is very fragile, because we'd have to + // account for all possible compile flag splittings (they have some... intricacies and are + // not yet normalized). // // `minicore` requires `#![no_std]` and `#![no_core]`, which means no unwinding panics. if self.props.add_core_stubs { rustc.arg("-Cpanic=abort"); + rustc.arg("-Cforce-unwind-tables=yes"); } rustc diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index a3525dcc77ae..7d60a7e5c489 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -391,32 +391,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } - #[rustfmt::skip] - | "fadd_algebraic" - | "fsub_algebraic" - | "fmul_algebraic" - | "fdiv_algebraic" - | "frem_algebraic" - => { - let [a, b] = check_intrinsic_arg_count(args)?; - let a = this.read_immediate(a)?; - let b = this.read_immediate(b)?; - let op = match intrinsic_name { - "fadd_algebraic" => mir::BinOp::Add, - "fsub_algebraic" => mir::BinOp::Sub, - "fmul_algebraic" => mir::BinOp::Mul, - "fdiv_algebraic" => mir::BinOp::Div, - "frem_algebraic" => mir::BinOp::Rem, - _ => bug!(), - }; - let res = this.binary_op(op, &a, &b)?; - // `binary_op` already called `generate_nan` if needed. - // Apply a relative error of 4ULP to simulate non-deterministic precision loss - // due to optimizations. - let res = apply_random_float_error_to_imm(this, res, 2 /* log2(4) */)?; - this.write_immediate(*res, dest)?; - } - #[rustfmt::skip] | "fadd_fast" | "fsub_fast" diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index b6b2684dc6da..e03611e9b509 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -1,6 +1,5 @@ #![feature(rustc_private)] #![feature(cfg_match)] -#![feature(cell_update)] #![feature(float_gamma)] #![feature(float_erf)] #![feature(map_try_insert)] diff --git a/src/tools/miri/tests/fail/validity/invalid_bool.rs b/src/tools/miri/tests/fail/validity/invalid_bool.rs index 4f11bb2629f5..bd448af834df 100644 --- a/src/tools/miri/tests/fail/validity/invalid_bool.rs +++ b/src/tools/miri/tests/fail/validity/invalid_bool.rs @@ -1,3 +1,4 @@ +#![allow(unnecessary_transmutes)] fn main() { let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR: expected a boolean } diff --git a/src/tools/miri/tests/fail/validity/invalid_bool_op.rs b/src/tools/miri/tests/fail/validity/invalid_bool_op.rs index fe9bb3bed7f0..0cbe2d76dc6c 100644 --- a/src/tools/miri/tests/fail/validity/invalid_bool_op.rs +++ b/src/tools/miri/tests/fail/validity/invalid_bool_op.rs @@ -2,6 +2,7 @@ // Make sure we find these even with many checks disabled. //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +#![allow(unnecessary_transmutes)] fn main() { let b = unsafe { std::mem::transmute::(2) }; let _x = b == std::hint::black_box(true); //~ ERROR: interpreting an invalid 8-bit value as a bool diff --git a/src/tools/miri/tests/fail/validity/invalid_char.rs b/src/tools/miri/tests/fail/validity/invalid_char.rs index 568892e59109..d57c933dac17 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char.rs +++ b/src/tools/miri/tests/fail/validity/invalid_char.rs @@ -1,3 +1,4 @@ +#![allow(unnecessary_transmutes)] fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); let _val = match unsafe { std::mem::transmute::(-1) } { diff --git a/src/tools/miri/tests/fail/validity/invalid_char_op.rs b/src/tools/miri/tests/fail/validity/invalid_char_op.rs index 699248229445..e3a5f837e189 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char_op.rs +++ b/src/tools/miri/tests/fail/validity/invalid_char_op.rs @@ -2,6 +2,7 @@ // Make sure we find these even with many checks disabled. //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +#![allow(unnecessary_transmutes)] fn main() { let c = 0xFFFFFFu32; assert!(std::char::from_u32(c).is_none()); diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index cd60b6bd563d..575d70579a4e 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -6,6 +6,7 @@ #![feature(f16)] #![allow(arithmetic_overflow)] #![allow(internal_features)] +#![allow(unnecessary_transmutes)] use std::any::type_name; use std::cmp::min; diff --git a/src/tools/miri/tests/pass/issues/issue-miri-184.rs b/src/tools/miri/tests/pass/issues/issue-miri-184.rs index 39c841403ef0..964d850298fb 100644 --- a/src/tools/miri/tests/pass/issues/issue-miri-184.rs +++ b/src/tools/miri/tests/pass/issues/issue-miri-184.rs @@ -1,3 +1,4 @@ +#![allow(unnecessary_transmutes)] pub fn main() { let bytes: [u8; 8] = unsafe { ::std::mem::transmute(0u64) }; let _val: &[u8] = &bytes; diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs index a629e2acfe99..882b5e3f7952 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs @@ -368,7 +368,7 @@ unsafe fn load_m256i_word(data: &[T], word_index: usize) -> __m256i { #[target_feature(enable = "avx512f")] unsafe fn load_m512i_word(data: &[T], word_index: usize) -> __m512i { let byte_offset = word_index * 64 / size_of::(); - let pointer = data.as_ptr().add(byte_offset) as *const i32; + let pointer = data.as_ptr().add(byte_offset) as *const __m512i; _mm512_loadu_si512(black_box(pointer)) } diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs index 6f7ab3b3c9fb..be3f961e10ff 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs @@ -1,5 +1,6 @@ // We're testing x86 target specific features //@only-target: x86_64 i686 +#![allow(unnecessary_transmutes)] #[cfg(target_arch = "x86")] use std::arch::x86::*; diff --git a/src/tools/suggest-tests/src/main.rs b/src/tools/suggest-tests/src/main.rs index ee212af36260..d84f8e9fa1ba 100644 --- a/src/tools/suggest-tests/src/main.rs +++ b/src/tools/suggest-tests/src/main.rs @@ -6,7 +6,6 @@ use suggest_tests::get_suggestions; fn main() -> ExitCode { let modified_files = get_git_modified_files( &GitConfig { - git_repository: &env("SUGGEST_TESTS_GIT_REPOSITORY"), nightly_branch: &env("SUGGEST_TESTS_NIGHTLY_BRANCH"), git_merge_commit_email: &env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL"), }, diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs index 2c39c830684e..165c11d22801 100644 --- a/tests/assembly/x86-return-float.rs +++ b/tests/assembly/x86-return-float.rs @@ -35,6 +35,7 @@ use minicore::*; pub fn return_f32(x: f32) -> f32 { // CHECK: movss {{.*}}(%ebp), %xmm0 // CHECK-NEXT: popl %ebp + // linux-NEXT: .cfi_def_cfa // CHECK-NEXT: retl x } @@ -44,6 +45,7 @@ pub fn return_f32(x: f32) -> f32 { pub fn return_f64(x: f64) -> f64 { // CHECK: movsd {{.*}}(%ebp), %xmm0 // CHECK-NEXT: popl %ebp + // linux-NEXT: .cfi_def_cfa // CHECK-NEXT: retl x } @@ -313,9 +315,13 @@ pub unsafe fn call_other_f64(x: &mut (usize, f64)) { #[no_mangle] pub fn return_f16(x: f16) -> f16 { // CHECK: pushl %ebp + // linux-NEXT: .cfi_def_cfa_offset + // linux-NEXT: .cfi_offset // CHECK-NEXT: movl %esp, %ebp + // linux-NEXT: .cfi_def_cfa_register // CHECK-NEXT: pinsrw $0, 8(%ebp), %xmm0 // CHECK-NEXT: popl %ebp + // linux-NEXT: .cfi_def_cfa // CHECK-NEXT: retl x } @@ -324,10 +330,14 @@ pub fn return_f16(x: f16) -> f16 { #[no_mangle] pub fn return_f128(x: f128) -> f128 { // CHECK: pushl %ebp + // linux-NEXT: .cfi_def_cfa_offset + // linux-NEXT: .cfi_offset // CHECK-NEXT: movl %esp, %ebp + // linux-NEXT: .cfi_def_cfa_register // linux-NEXT: movaps 8(%ebp), %xmm0 // win-NEXT: movups 8(%ebp), %xmm0 // CHECK-NEXT: popl %ebp + // linux-NEXT: .cfi_def_cfa // CHECK-NEXT: retl x } diff --git a/tests/codegen/align-struct.rs b/tests/codegen/align-struct.rs index cc65b08a9223..402a184d4c07 100644 --- a/tests/codegen/align-struct.rs +++ b/tests/codegen/align-struct.rs @@ -1,5 +1,7 @@ //@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -// +// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480) +//@ ignore-i686-pc-windows-msvc +//@ ignore-i686-pc-windows-gnu #![crate_type = "lib"] diff --git a/tests/codegen/autodiff/identical_fnc.rs b/tests/codegen/autodiff/identical_fnc.rs new file mode 100644 index 000000000000..1c3277f52b48 --- /dev/null +++ b/tests/codegen/autodiff/identical_fnc.rs @@ -0,0 +1,45 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme +// +// Each autodiff invocation creates a new placeholder function, which we will replace on llvm-ir +// level. If a user tries to differentiate two identical functions within the same compilation unit, +// then LLVM might merge them in release mode before AD. In that case we can't rewrite one of the +// merged placeholder function anymore, and compilation would fail. We prevent this by disabling +// LLVM's merge_function pass before AD. Here we implicetely test that our solution keeps working. +// We also explicetly test that we keep running merge_function after AD, by checking for two +// identical function calls in the LLVM-IR, while having two different calls in the Rust code. +#![feature(autodiff)] + +use std::autodiff::autodiff; + +#[autodiff(d_square, Reverse, Duplicated, Active)] +fn square(x: &f64) -> f64 { + x * x +} + +#[autodiff(d_square2, Reverse, Duplicated, Active)] +fn square2(x: &f64) -> f64 { + x * x +} + +// CHECK:; identical_fnc::main +// CHECK-NEXT:; Function Attrs: +// CHECK-NEXT:define internal void @_ZN13identical_fnc4main17hf4dbc69c8d2f9130E() +// CHECK-NEXT:start: +// CHECK-NOT:br +// CHECK-NOT:ret +// CHECK:; call identical_fnc::d_square +// CHECK-NEXT: call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx1) +// CHECK-NEXT:; call identical_fnc::d_square +// CHECK-NEXT: call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx2) + +fn main() { + let x = std::hint::black_box(3.0); + let mut dx1 = std::hint::black_box(1.0); + let mut dx2 = std::hint::black_box(1.0); + let _ = d_square(&x, &mut dx1, 1.0); + let _ = d_square2(&x, &mut dx2, 1.0); + assert_eq!(dx1, 6.0); + assert_eq!(dx2, 6.0); +} diff --git a/tests/codegen/autodiff/inline.rs b/tests/codegen/autodiff/inline.rs new file mode 100644 index 000000000000..e90faa4aa380 --- /dev/null +++ b/tests/codegen/autodiff/inline.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat -Zautodiff=NoPostopt +//@ no-prefer-dynamic +//@ needs-enzyme + +#![feature(autodiff)] + +use std::autodiff::autodiff; + +#[autodiff(d_square, Reverse, Duplicated, Active)] +fn square(x: &f64) -> f64 { + x * x +} + +// CHECK: ; inline::d_square +// CHECK-NEXT: ; Function Attrs: alwaysinline +// CHECK-NOT: noinline +// CHECK-NEXT: define internal fastcc void @_ZN6inline8d_square17h021c74e92c259cdeE +fn main() { + let x = std::hint::black_box(3.0); + let mut dx1 = std::hint::black_box(1.0); + let _ = d_square(&x, &mut dx1, 1.0); + assert_eq!(dx1, 6.0); +} diff --git a/tests/codegen/issues/issue-56927.rs b/tests/codegen/issues/issue-56927.rs index a40718689b3e..415ef073e03a 100644 --- a/tests/codegen/issues/issue-56927.rs +++ b/tests/codegen/issues/issue-56927.rs @@ -1,4 +1,7 @@ //@ compile-flags: -C no-prepopulate-passes +// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480) +//@ ignore-i686-pc-windows-msvc +//@ ignore-i686-pc-windows-gnu #![crate_type = "rlib"] diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index ebf2e333f085..71edf813a7be 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -145,7 +145,7 @@ fn get_item<'a>( fn main() { let path = "alloc_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index ae2609bbc122..692c24f05445 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -219,7 +219,7 @@ fn get_item<'a>( fn main() { let path = "alloc_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--edition=2021".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs index 9d611543b5aa..755bec8747bc 100644 --- a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs +++ b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs @@ -85,7 +85,7 @@ fn check_items(items: &[T], expected: &[&str]) { fn main() { let path = "assoc_items.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs index 4148fc0cb6a0..81d5399d88aa 100644 --- a/tests/ui-fulldeps/stable-mir/check_attribute.rs +++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs @@ -57,7 +57,7 @@ fn get_item<'a>( fn main() { let path = "attribute_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_binop.rs b/tests/ui-fulldeps/stable-mir/check_binop.rs index 6a141e9c5775..f9559d9958d2 100644 --- a/tests/ui-fulldeps/stable-mir/check_binop.rs +++ b/tests/ui-fulldeps/stable-mir/check_binop.rs @@ -81,7 +81,7 @@ impl<'a> MirVisitor for Visitor<'a> { fn main() { let path = "binop_input.rs"; generate_input(&path).unwrap(); - let args = vec!["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()]; + let args = &["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()]; run!(args, test_binops).unwrap(); } diff --git a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs index 31c47192d090..6863242f2257 100644 --- a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs @@ -84,7 +84,7 @@ fn contains(items: &[T], expected: &[&str]) { fn main() { let path = "crate_definitions.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_def_ty.rs b/tests/ui-fulldeps/stable-mir/check_def_ty.rs index 00a34f138673..f86a8e0ae618 100644 --- a/tests/ui-fulldeps/stable-mir/check_def_ty.rs +++ b/tests/ui-fulldeps/stable-mir/check_def_ty.rs @@ -76,7 +76,7 @@ fn check_fn_def(ty: Ty) { fn main() { let path = "defs_ty_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index 1ba73377d6e9..ab741378bb71 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -112,7 +112,7 @@ fn get_instances(body: mir::Body) -> Vec { fn main() { let path = "defs_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_foreign.rs b/tests/ui-fulldeps/stable-mir/check_foreign.rs index 4419050ceb2c..398024c4ff08 100644 --- a/tests/ui-fulldeps/stable-mir/check_foreign.rs +++ b/tests/ui-fulldeps/stable-mir/check_foreign.rs @@ -58,7 +58,7 @@ fn test_foreign() -> ControlFlow<()> { fn main() { let path = "foreign_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-type=lib".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 1510a622cdfd..b19e5b033c46 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -87,7 +87,7 @@ fn test_body(body: mir::Body) { fn main() { let path = "instance_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-type=lib".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs index 3f04abbb9d76..52424857dc19 100644 --- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -115,7 +115,7 @@ impl<'a> MirVisitor for CallsVisitor<'a> { fn main() { let path = "binop_input.rs"; generate_input(&path).unwrap(); - let args = vec!["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()]; + let args = &["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()]; run!(args, test_intrinsics).unwrap(); } diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs index bb8c00c64c95..d1124c75a899 100644 --- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs +++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs @@ -47,7 +47,7 @@ fn test_item_kind() -> ControlFlow<()> { fn main() { let path = "item_kind_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-type=lib".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_normalization.rs b/tests/ui-fulldeps/stable-mir/check_normalization.rs index 797cb4cd5d05..16e8c0339ed4 100644 --- a/tests/ui-fulldeps/stable-mir/check_normalization.rs +++ b/tests/ui-fulldeps/stable-mir/check_normalization.rs @@ -61,7 +61,7 @@ fn check_ty(ty: Ty) { fn main() { let path = "normalization_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-type=lib".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs index d9170d0c4081..fcf04a1fc3a3 100644 --- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs +++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs @@ -72,7 +72,7 @@ fn assert_impl(impl_names: &HashSet, target: &str) { fn main() { let path = "trait_queries.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs index 604cc72c3418..9087c1cf4502 100644 --- a/tests/ui-fulldeps/stable-mir/check_transform.rs +++ b/tests/ui-fulldeps/stable-mir/check_transform.rs @@ -120,7 +120,7 @@ fn get_item<'a>( fn main() { let path = "transform_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs index 23233f8406cf..18b9e32e4e80 100644 --- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -78,7 +78,7 @@ impl<'a> MirVisitor for PlaceVisitor<'a> { fn main() { let path = "ty_fold_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs index 39416636fd67..19b9c8b7de50 100644 --- a/tests/ui-fulldeps/stable-mir/compilation-result.rs +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -25,40 +25,42 @@ use std::io::Write; fn main() { let path = "input_compilation_result_test.rs"; generate_input(&path).unwrap(); - let args = vec!["rustc".to_string(), path.to_string()]; - test_continue(args.clone()); - test_break(args.clone()); - test_failed(args.clone()); - test_skipped(args.clone()); + let args = &["rustc".to_string(), path.to_string()]; + test_continue(args); + test_break(args); + test_failed(args); + test_skipped(args); test_captured(args) } -fn test_continue(args: Vec) { +fn test_continue(args: &[String]) { let result = run!(args, || ControlFlow::Continue::<(), bool>(true)); assert_eq!(result, Ok(true)); } -fn test_break(args: Vec) { +fn test_break(args: &[String]) { let result = run!(args, || ControlFlow::Break::(false)); assert_eq!(result, Err(stable_mir::CompilerError::Interrupted(false))); } #[allow(unreachable_code)] -fn test_skipped(mut args: Vec) { +fn test_skipped(args: &[String]) { + let mut args = args.to_vec(); args.push("--version".to_string()); - let result = run!(args, || unreachable!() as ControlFlow<()>); + let result = run!(&args, || unreachable!() as ControlFlow<()>); assert_eq!(result, Err(stable_mir::CompilerError::Skipped)); } #[allow(unreachable_code)] -fn test_failed(mut args: Vec) { +fn test_failed(args: &[String]) { + let mut args = args.to_vec(); args.push("--cfg=broken".to_string()); - let result = run!(args, || unreachable!() as ControlFlow<()>); + let result = run!(&args, || unreachable!() as ControlFlow<()>); assert_eq!(result, Err(stable_mir::CompilerError::Failed)); } /// Test that we are able to pass a closure and set the return according to the captured value. -fn test_captured(args: Vec) { +fn test_captured(args: &[String]) { let captured = "10".to_string(); let result = run!(args, || ControlFlow::Continue::<(), usize>(captured.len())); assert_eq!(result, Ok(captured.len())); diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index e2086d5e5790..7fc4edafb933 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -186,7 +186,7 @@ fn get_item<'a>( fn main() { let path = "input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index f3bd894ac690..103c97bc48e1 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -146,7 +146,7 @@ fn get_item<'a>( fn main() { let path = "input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index f9972dc27e3f..0519b9de6805 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -40,7 +40,7 @@ fn test_translation(tcx: TyCtxt<'_>) -> ControlFlow<()> { fn main() { let path = "internal_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), diff --git a/tests/ui-fulldeps/stable-mir/smir_serde.rs b/tests/ui-fulldeps/stable-mir/smir_serde.rs index 3b3d743ad326..0b39ec050024 100644 --- a/tests/ui-fulldeps/stable-mir/smir_serde.rs +++ b/tests/ui-fulldeps/stable-mir/smir_serde.rs @@ -46,7 +46,7 @@ fn serialize_to_json(_tcx: TyCtxt<'_>) -> ControlFlow<()> { fn main() { let path = "internal_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index d225d9773fe5..caf71de2556c 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -183,14 +183,14 @@ impl mir::MutMirVisitor for TestMutVisitor { fn main() { let path = "sim_visitor_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), path.to_string(), ]; - run!(args.clone(), test_visitor).unwrap(); + run!(args, test_visitor).unwrap(); run!(args, test_mut_visitor).unwrap(); } diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs index 9187de563620..20f1a9aae70a 100644 --- a/tests/ui/consts/const-eval/raw-bytes.rs +++ b/tests/ui/consts/const-eval/raw-bytes.rs @@ -2,7 +2,7 @@ //@ ignore-endian-big // ignore-tidy-linelength //@ normalize-stderr: "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼" -> "╾ALLOC_ID$1╼" -#![allow(invalid_value)] +#![allow(invalid_value, unnecessary_transmutes)] #![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)] use std::mem; diff --git a/tests/ui/consts/const-eval/transmute-const-promotion.rs b/tests/ui/consts/const-eval/transmute-const-promotion.rs index 1f0240d4b5ac..840334f43c09 100644 --- a/tests/ui/consts/const-eval/transmute-const-promotion.rs +++ b/tests/ui/consts/const-eval/transmute-const-promotion.rs @@ -1,3 +1,4 @@ +#![allow(unnecessary_transmutes)] use std::mem; fn main() { diff --git a/tests/ui/consts/const-eval/transmute-const-promotion.stderr b/tests/ui/consts/const-eval/transmute-const-promotion.stderr index 3603db03bb20..eb2fed091c34 100644 --- a/tests/ui/consts/const-eval/transmute-const-promotion.stderr +++ b/tests/ui/consts/const-eval/transmute-const-promotion.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/transmute-const-promotion.rs:4:37 + --> $DIR/transmute-const-promotion.rs:5:37 | LL | let x: &'static u32 = unsafe { &mem::transmute(3.0f32) }; | ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use diff --git a/tests/ui/consts/const-eval/transmute-const.rs b/tests/ui/consts/const-eval/transmute-const.rs index 1cfad00ca76d..fb6cb77675fa 100644 --- a/tests/ui/consts/const-eval/transmute-const.rs +++ b/tests/ui/consts/const-eval/transmute-const.rs @@ -1,3 +1,4 @@ +#![allow(unnecessary_transmutes)] use std::mem; static FOO: bool = unsafe { mem::transmute(3u8) }; diff --git a/tests/ui/consts/const-eval/transmute-const.stderr b/tests/ui/consts/const-eval/transmute-const.stderr index d72289487d7b..35a5cabaa671 100644 --- a/tests/ui/consts/const-eval/transmute-const.stderr +++ b/tests/ui/consts/const-eval/transmute-const.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/transmute-const.rs:3:1 + --> $DIR/transmute-const.rs:4:1 | LL | static FOO: bool = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs index 5be444e667a1..a5255ef95aa5 100644 --- a/tests/ui/consts/const-eval/ub-enum.rs +++ b/tests/ui/consts/const-eval/ub-enum.rs @@ -3,7 +3,7 @@ //@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" //@ normalize-stderr: "0x0+" -> "0x0" #![feature(never_type)] -#![allow(invalid_value)] +#![allow(invalid_value, unnecessary_transmutes)] use std::mem; diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs index a071a44272b4..4e2defc1a090 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.rs +++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs @@ -1,5 +1,5 @@ // ignore-tidy-linelength -#![allow(unused)] +#![allow(unused, unnecessary_transmutes)] #![feature(ptr_metadata)] use std::{ptr, mem}; diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs index 481f2ff88df6..c3bd8301d5ce 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs @@ -2,6 +2,7 @@ //@ [no_flag] check-pass //@ [with_flag] compile-flags: -Zextra-const-ub-checks #![feature(never_type)] +#![allow(unnecessary_transmutes)] use std::mem::transmute; use std::ptr::addr_of; diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr index 0100aafb6b7c..ea3b0e70b828 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:29:20 + --> $DIR/detect-extra-ub.rs:30:20 | LL | let _x: bool = transmute(3u8); | ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:35:21 + --> $DIR/detect-extra-ub.rs:36:21 | LL | let _x: usize = transmute(&3u8); | ^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected an integer @@ -14,7 +14,7 @@ LL | let _x: usize = transmute(&3u8); = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:41:28 + --> $DIR/detect-extra-ub.rs:42:28 | LL | let _x: PtrSizedEnum = transmute(&3u8); | ^^^^^^^^^^^^^^^ constructing invalid value at .: encountered a pointer, but expected an integer @@ -23,7 +23,7 @@ LL | let _x: PtrSizedEnum = transmute(&3u8); = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:48:30 + --> $DIR/detect-extra-ub.rs:49:30 | LL | let _x: (usize, usize) = transmute(x); | ^^^^^^^^^^^^ constructing invalid value at .0: encountered a pointer, but expected an integer @@ -32,19 +32,19 @@ LL | let _x: (usize, usize) = transmute(x); = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:54:20 + --> $DIR/detect-extra-ub.rs:55:20 | LL | let _x: &u32 = transmute(&[0u8; 4]); | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1) error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:62:13 + --> $DIR/detect-extra-ub.rs:63:13 | LL | let v = *addr_of!(data).cast::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:82:16 + --> $DIR/detect-extra-ub.rs:83:16 | LL | let _val = *(&mem as *const Align as *const [*const u8; 2]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a partial pointer or a mix of pointers @@ -53,7 +53,7 @@ LL | let _val = *(&mem as *const Align as *const [*const u8; 2]); = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: evaluation of constant value failed - --> $DIR/detect-extra-ub.rs:97:16 + --> $DIR/detect-extra-ub.rs:98:16 | LL | let _val = &*slice; | ^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object diff --git a/tests/ui/consts/issue-69532.rs b/tests/ui/consts/issue-69532.rs index 285cfe7213ba..43ab1d6cca74 100644 --- a/tests/ui/consts/issue-69532.rs +++ b/tests/ui/consts/issue-69532.rs @@ -1,8 +1,8 @@ //@ run-pass const fn make_nans() -> (f64, f64, f32, f32) { - let nan1: f64 = unsafe { std::mem::transmute(0x7FF0_0001_0000_0001u64) }; - let nan2: f64 = unsafe { std::mem::transmute(0x7FF0_0000_0000_0001u64) }; + let nan1 = f64::from_bits(0x7FF0_0001_0000_0001); + let nan2 = f64::from_bits(0x7FF0_0000_0000_0001); let nan1_32 = nan1 as f32; let nan2_32 = nan2 as f32; diff --git a/tests/ui/generics/single-colon-path-not-const-generics.stderr b/tests/ui/generics/single-colon-path-not-const-generics.stderr index 9eb62de27561..163ea4bbda6c 100644 --- a/tests/ui/generics/single-colon-path-not-const-generics.stderr +++ b/tests/ui/generics/single-colon-path-not-const-generics.stderr @@ -1,13 +1,15 @@ error: path separator must be a double colon --> $DIR/single-colon-path-not-const-generics.rs:8:18 | +LL | pub struct Foo { + | --- while parsing this struct LL | a: Vec, | ^ | help: use a double colon instead | LL | a: Vec, - | + + | + error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-25746-bool-transmute.rs b/tests/ui/issues/issue-25746-bool-transmute.rs index f8cdc980daa4..046dcf83f62d 100644 --- a/tests/ui/issues/issue-25746-bool-transmute.rs +++ b/tests/ui/issues/issue-25746-bool-transmute.rs @@ -1,4 +1,5 @@ //@ run-pass +#![allow(unnecessary_transmutes)] use std::mem::transmute; fn main() { diff --git a/tests/ui/linking/cdylib-no-mangle.rs b/tests/ui/linking/cdylib-no-mangle.rs new file mode 100644 index 000000000000..f442c3f584d6 --- /dev/null +++ b/tests/ui/linking/cdylib-no-mangle.rs @@ -0,0 +1,20 @@ +//@ only-apple +//@ build-fail +//@ dont-check-compiler-stderr +//@ dont-check-compiler-stdout + +// Regression test for . +// Functions in the dynamic library marked with no_mangle should not be GC-ed. + +#![crate_type = "cdylib"] + +unsafe extern "C" { + unsafe static THIS_SYMBOL_SHOULD_BE_UNDEFINED: usize; +} + +#[unsafe(no_mangle)] +pub unsafe fn function_marked_with_no_mangle() { + println!("FUNCTION_MARKED_WITH_NO_MANGLE = {}", unsafe { THIS_SYMBOL_SHOULD_BE_UNDEFINED }); +} + +//~? ERROR linking diff --git a/tests/ui/linking/executable-no-mangle-strip.rs b/tests/ui/linking/executable-no-mangle-strip.rs new file mode 100644 index 000000000000..cc283dc53ee3 --- /dev/null +++ b/tests/ui/linking/executable-no-mangle-strip.rs @@ -0,0 +1,27 @@ +//@ run-pass +//@ ignore-windows-gnu: only statics marked with used can be GC-ed on windows-gnu + +// Regression test for . +// Functions in the binary marked with no_mangle should be GC-ed if they +// are not indirectly referenced by main. + +#![feature(used_with_arg)] + +#[cfg_attr(windows, link(name = "this_lib_does_not_exist", kind = "raw-dylib"))] +unsafe extern "C" { + unsafe static THIS_SYMBOL_SHOULD_BE_UNDEFINED: usize; +} + +#[unsafe(no_mangle)] +pub unsafe fn function_marked_with_no_mangle() { + println!("FUNCTION_MARKED_WITH_NO_MANGLE = {}", unsafe { THIS_SYMBOL_SHOULD_BE_UNDEFINED }); +} + +#[used(compiler)] +pub static FUNCTION_MARKED_WITH_USED: unsafe fn() = || { + println!("FUNCTION_MARKED_WITH_USED = {}", unsafe { THIS_SYMBOL_SHOULD_BE_UNDEFINED }); +}; + +fn main() { + println!("MAIN"); +} diff --git a/tests/ui/lint/invalid_null_args.rs b/tests/ui/lint/invalid_null_args.rs index 7948f0d86d09..f40f06a0d362 100644 --- a/tests/ui/lint/invalid_null_args.rs +++ b/tests/ui/lint/invalid_null_args.rs @@ -1,19 +1,19 @@ // check-fail // run-rustfix +#![allow(unnecessary_transmutes)] -use std::ptr; -use std::mem; +use std::{mem, ptr}; unsafe fn null_ptr() { ptr::write( - //~^ ERROR calling this function with a null pointer is undefined behavior + //~^ ERROR calling this function with a null pointer is undefined behavior ptr::null_mut() as *mut u32, mem::transmute::<[u8; 4], _>([0, 0, 0, 255]), ); let null_ptr = ptr::null_mut(); ptr::write( - //~^ ERROR calling this function with a null pointer is undefined behavior + //~^ ERROR calling this function with a null pointer is undefined behavior null_ptr as *mut u32, mem::transmute::<[u8; 4], _>([0, 0, 0, 255]), ); @@ -38,10 +38,10 @@ unsafe fn null_ptr() { ptr::copy_nonoverlapping::(ptr::null(), ptr::NonNull::dangling().as_ptr(), 0); //~^ ERROR calling this function with a null pointer is undefined behavior ptr::copy_nonoverlapping::( - //~^ ERROR calling this function with a null pointer is undefined behavior + //~^ ERROR calling this function with a null pointer is undefined behavior ptr::NonNull::dangling().as_ptr(), ptr::null_mut(), - 0 + 0, ); #[derive(Copy, Clone)] diff --git a/tests/ui/lint/invalid_null_args.stderr b/tests/ui/lint/invalid_null_args.stderr index f95bc2afa829..11c6270cfb78 100644 --- a/tests/ui/lint/invalid_null_args.stderr +++ b/tests/ui/lint/invalid_null_args.stderr @@ -117,7 +117,7 @@ LL | | LL | | ptr::NonNull::dangling().as_ptr(), LL | | ptr::null_mut(), | | --------------- null pointer originates from here -LL | | 0 +LL | | 0, LL | | ); | |_____^ | diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/lint-ctypes-enum.rs index 0d19d5b53471..b2ef27b833bd 100644 --- a/tests/ui/lint/lint-ctypes-enum.rs +++ b/tests/ui/lint/lint-ctypes-enum.rs @@ -2,6 +2,8 @@ #![deny(improper_ctypes)] #![feature(ptr_internals)] #![feature(transparent_unions)] +#![feature(repr128)] +#![allow(incomplete_features)] use std::num; @@ -40,6 +42,20 @@ enum Isize { C, } +#[repr(u128)] +enum U128 { + A, + B, + C, +} + +#[repr(i128)] +enum I128 { + A, + B, + C, +} + #[repr(transparent)] struct TransparentStruct(T, std::marker::PhantomData); @@ -71,6 +87,8 @@ extern "C" { fn repr_c(x: ReprC); fn repr_u8(x: U8); fn repr_isize(x: Isize); + fn repr_u128(x: U128); //~ ERROR `extern` block uses type `U128` + fn repr_i128(x: I128); //~ ERROR `extern` block uses type `I128` fn option_ref(x: Option<&'static u8>); fn option_fn(x: Option); fn option_nonnull(x: Option>); diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index a491bd196056..d5fc844f7560 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -1,5 +1,5 @@ error: `extern` block uses type `U`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:68:14 + --> $DIR/lint-ctypes-enum.rs:84:14 | LL | fn uf(x: U); | ^ not FFI-safe @@ -7,7 +7,7 @@ LL | fn uf(x: U); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:9:1 + --> $DIR/lint-ctypes-enum.rs:11:1 | LL | enum U { | ^^^^^^ @@ -18,7 +18,7 @@ LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ error: `extern` block uses type `B`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:69:14 + --> $DIR/lint-ctypes-enum.rs:85:14 | LL | fn bf(x: B); | ^ not FFI-safe @@ -26,13 +26,13 @@ LL | fn bf(x: B); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:12:1 + --> $DIR/lint-ctypes-enum.rs:14:1 | LL | enum B { | ^^^^^^ error: `extern` block uses type `T`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:70:14 + --> $DIR/lint-ctypes-enum.rs:86:14 | LL | fn tf(x: T); | ^ not FFI-safe @@ -40,13 +40,39 @@ LL | fn tf(x: T); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:16:1 + --> $DIR/lint-ctypes-enum.rs:18:1 | LL | enum T { | ^^^^^^ +error: `extern` block uses type `U128`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:90:21 + | +LL | fn repr_u128(x: U128); + | ^^^^ not FFI-safe + | + = note: 128-bit integers don't currently have a known stable ABI +note: the type is defined here + --> $DIR/lint-ctypes-enum.rs:46:1 + | +LL | enum U128 { + | ^^^^^^^^^ + +error: `extern` block uses type `I128`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:91:21 + | +LL | fn repr_i128(x: I128); + | ^^^^ not FFI-safe + | + = note: 128-bit integers don't currently have a known stable ABI +note: the type is defined here + --> $DIR/lint-ctypes-enum.rs:53:1 + | +LL | enum I128 { + | ^^^^^^^^^ + error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:82:31 + --> $DIR/lint-ctypes-enum.rs:100:31 | LL | fn option_nonzero_u128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -54,7 +80,7 @@ LL | fn option_nonzero_u128(x: Option>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:89:31 + --> $DIR/lint-ctypes-enum.rs:107:31 | LL | fn option_nonzero_i128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -62,7 +88,7 @@ LL | fn option_nonzero_i128(x: Option>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:94:36 + --> $DIR/lint-ctypes-enum.rs:112:36 | LL | fn option_transparent_union(x: Option>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -71,7 +97,7 @@ LL | fn option_transparent_union(x: Option = note: enum has no representation hint error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:96:28 + --> $DIR/lint-ctypes-enum.rs:114:28 | LL | fn option_repr_rust(x: Option>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -80,7 +106,7 @@ LL | fn option_repr_rust(x: Option>>); = note: enum has no representation hint error: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:97:21 + --> $DIR/lint-ctypes-enum.rs:115:21 | LL | fn option_u8(x: Option); | ^^^^^^^^^^ not FFI-safe @@ -89,7 +115,7 @@ LL | fn option_u8(x: Option); = note: enum has no representation hint error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:107:33 + --> $DIR/lint-ctypes-enum.rs:125:33 | LL | fn result_nonzero_u128_t(x: Result, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -97,7 +123,7 @@ LL | fn result_nonzero_u128_t(x: Result, ()>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:114:33 + --> $DIR/lint-ctypes-enum.rs:132:33 | LL | fn result_nonzero_i128_t(x: Result, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -105,7 +131,7 @@ LL | fn result_nonzero_i128_t(x: Result, ()>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:119:38 + --> $DIR/lint-ctypes-enum.rs:137:38 | LL | fn result_transparent_union_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -114,7 +140,7 @@ LL | fn result_transparent_union_t(x: Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:121:30 + --> $DIR/lint-ctypes-enum.rs:139:30 | LL | fn result_repr_rust_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -123,7 +149,7 @@ LL | fn result_repr_rust_t(x: Result>, ()>); = note: enum has no representation hint error: `extern` block uses type `Result, U>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:125:51 + --> $DIR/lint-ctypes-enum.rs:143:51 | LL | fn result_1zst_exhaustive_single_variant_t(x: Result, U>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -132,7 +158,7 @@ LL | fn result_1zst_exhaustive_single_variant_t(x: Result, = note: enum has no representation hint error: `extern` block uses type `Result, B>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:127:53 + --> $DIR/lint-ctypes-enum.rs:145:53 | LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result, B>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -141,7 +167,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result = note: enum has no representation hint error: `extern` block uses type `Result, NonExhaustive>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:129:51 + --> $DIR/lint-ctypes-enum.rs:147:51 | LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result, NonExhaustive>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -150,7 +176,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result, = note: enum has no representation hint error: `extern` block uses type `Result, Field>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:132:49 + --> $DIR/lint-ctypes-enum.rs:150:49 | LL | fn result_1zst_exhaustive_single_field_t(x: Result, Field>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -159,7 +185,7 @@ LL | fn result_1zst_exhaustive_single_field_t(x: Result, Fi = note: enum has no representation hint error: `extern` block uses type `Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:134:30 + --> $DIR/lint-ctypes-enum.rs:152:30 | LL | fn result_cascading_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -168,7 +194,7 @@ LL | fn result_cascading_t(x: Result>, ()>); = note: enum has no representation hint error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:145:33 + --> $DIR/lint-ctypes-enum.rs:163:33 | LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -176,7 +202,7 @@ LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:152:33 + --> $DIR/lint-ctypes-enum.rs:170:33 | LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -184,7 +210,7 @@ LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Result<(), TransparentUnion>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:157:38 + --> $DIR/lint-ctypes-enum.rs:175:38 | LL | fn result_transparent_union_e(x: Result<(), TransparentUnion>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -193,7 +219,7 @@ LL | fn result_transparent_union_e(x: Result<(), TransparentUnion>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:159:30 + --> $DIR/lint-ctypes-enum.rs:177:30 | LL | fn result_repr_rust_e(x: Result<(), Rust>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -202,7 +228,7 @@ LL | fn result_repr_rust_e(x: Result<(), Rust>>); = note: enum has no representation hint error: `extern` block uses type `Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:163:51 + --> $DIR/lint-ctypes-enum.rs:181:51 | LL | fn result_1zst_exhaustive_single_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -211,7 +237,7 @@ LL | fn result_1zst_exhaustive_single_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:165:53 + --> $DIR/lint-ctypes-enum.rs:183:53 | LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -220,7 +246,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:167:51 + --> $DIR/lint-ctypes-enum.rs:185:51 | LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -229,7 +255,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:170:49 + --> $DIR/lint-ctypes-enum.rs:188:49 | LL | fn result_1zst_exhaustive_single_field_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -238,7 +264,7 @@ LL | fn result_1zst_exhaustive_single_field_e(x: Result>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:172:30 + --> $DIR/lint-ctypes-enum.rs:190:30 | LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -247,7 +273,7 @@ LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero>>); = note: enum has no representation hint error: `extern` block uses type `Result<(), ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:174:27 + --> $DIR/lint-ctypes-enum.rs:192:27 | LL | fn result_unit_t_e(x: Result<(), ()>); | ^^^^^^^^^^^^^^ not FFI-safe @@ -255,5 +281,5 @@ LL | fn result_unit_t_e(x: Result<(), ()>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: aborting due to 27 previous errors +error: aborting due to 29 previous errors diff --git a/tests/ui/parser/ty-path-followed-by-single-colon.rs b/tests/ui/parser/ty-path-followed-by-single-colon.rs new file mode 100644 index 000000000000..a9082ea317a7 --- /dev/null +++ b/tests/ui/parser/ty-path-followed-by-single-colon.rs @@ -0,0 +1,22 @@ +// Paths in type contexts may be followed by single colons. +// This means we can't generally assume that the user typo'ed a double colon. +// issue: +//@ check-pass +#![crate_type = "lib"] +#![expect(non_camel_case_types)] + +#[rustfmt::skip] +mod garden { + + fn f() where path:to::somewhere {} // OK! + + fn g(_: impl Take) {} // OK! + + #[cfg(any())] fn h() where a::path:to::nowhere {} // OK! + + fn i(_: impl Take:to::somewhere>) {} // OK! + + mod to { pub(super) trait somewhere {} } + trait Take { type path; } + +} diff --git a/tests/ui/pattern/byte-string-mutability-mismatch.rs b/tests/ui/pattern/byte-string-mutability-mismatch.rs new file mode 100644 index 000000000000..4ffdb5f9b99e --- /dev/null +++ b/tests/ui/pattern/byte-string-mutability-mismatch.rs @@ -0,0 +1,19 @@ +//! Byte string literal patterns use the mutability of the literal, rather than the mutability of +//! the pattern's scrutinee. Since byte string literals are always shared references, it's a +//! mismatch to use a byte string literal pattern to match on a mutable array or slice reference. + +fn main() { + let mut val = [97u8, 10u8]; + match &mut val { + b"a\n" => {}, + //~^ ERROR mismatched types + //~| types differ in mutability + _ => {}, + } + match &mut val[..] { + b"a\n" => {}, + //~^ ERROR mismatched types + //~| types differ in mutability + _ => {}, + } +} diff --git a/tests/ui/pattern/byte-string-mutability-mismatch.stderr b/tests/ui/pattern/byte-string-mutability-mismatch.stderr new file mode 100644 index 000000000000..ee796278e69d --- /dev/null +++ b/tests/ui/pattern/byte-string-mutability-mismatch.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/byte-string-mutability-mismatch.rs:8:9 + | +LL | match &mut val { + | -------- this expression has type `&mut [u8; 2]` +LL | b"a\n" => {}, + | ^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static _` + +error[E0308]: mismatched types + --> $DIR/byte-string-mutability-mismatch.rs:14:10 + | +LL | match &mut val[..] { + | ------------ this expression has type `&mut [u8]` +LL | b"a\n" => {}, + | ^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static _` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs b/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs new file mode 100644 index 000000000000..29a33e3e2c3b --- /dev/null +++ b/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs @@ -0,0 +1,34 @@ +//! Test type errors for byte string literal patterns. `deref_patterns` allows byte string literal +//! patterns to have type `[u8]` or `[u8; N]` when matching on a slice or array; this can affect the +//! "found" type reported in error messages when matching on a slice or array of the wrong type. + +#![feature(deref_patterns)] +#![expect(incomplete_features)] + +fn main() { + // Baseline 1: under normal circumstances, byte string literal patterns have type `&[u8; N]`, + // the same as byte string literals. + if let b"test" = () {} + //~^ ERROR mismatched types + //~| expected `()`, found `&[u8; 4]` + + // Baseline 2: there's a special case for byte string patterns in stable rust, allowing them to + // match on slice references. This affects the error when matching on a non-`&[u8]` slice ref, + // reporting the "found" type as `&[u8]`. + if let b"test" = &[] as &[i8] {} + //~^ ERROR mismatched types + //~| expected `&[i8]`, found `&[u8]` + + // Test matching on a non-`[u8]` slice: the pattern has type `[u8]` if a slice is expected. + if let b"test" = *(&[] as &[i8]) {} + //~^ ERROR mismatched types + //~| expected `[i8]`, found `[u8]` + + // Test matching on a non-`[u8;4]` array: the pattern has type `[u8;4]` if an array is expected. + if let b"test" = [()] {} + //~^ ERROR mismatched types + //~| expected `[(); 1]`, found `[u8; 4]` + if let b"test" = *b"this array is too long" {} + //~^ ERROR mismatched types + //~| expected an array with a size of 22, found one with a size of 4 +} diff --git a/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr b/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr new file mode 100644 index 000000000000..d29a5b59252c --- /dev/null +++ b/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr @@ -0,0 +1,52 @@ +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:11:12 + | +LL | if let b"test" = () {} + | ^^^^^^^ -- this expression has type `()` + | | + | expected `()`, found `&[u8; 4]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:18:12 + | +LL | if let b"test" = &[] as &[i8] {} + | ^^^^^^^ ------------ this expression has type `&[i8]` + | | + | expected `&[i8]`, found `&[u8]` + | + = note: expected reference `&[i8]` + found reference `&'static [u8]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:23:12 + | +LL | if let b"test" = *(&[] as &[i8]) {} + | ^^^^^^^ --------------- this expression has type `[i8]` + | | + | expected `[i8]`, found `[u8]` + | + = note: expected slice `[i8]` + found slice `[u8]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:28:12 + | +LL | if let b"test" = [()] {} + | ^^^^^^^ ---- this expression has type `[(); 1]` + | | + | expected `[(); 1]`, found `[u8; 4]` + | + = note: expected array `[(); 1]` + found array `[u8; 4]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:31:12 + | +LL | if let b"test" = *b"this array is too long" {} + | ^^^^^^^ -------------------------- this expression has type `[u8; 22]` + | | + | expected an array with a size of 22, found one with a size of 4 + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/needs-gate.rs b/tests/ui/pattern/deref-patterns/needs-gate.rs index 2d5ec45217fb..7944744ee839 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.rs +++ b/tests/ui/pattern/deref-patterns/needs-gate.rs @@ -12,4 +12,21 @@ fn main() { //~^ ERROR: mismatched types _ => {} } + + // `deref_patterns` allows string and byte string literals to have non-ref types. + match *"test" { + "test" => {} + //~^ ERROR: mismatched types + _ => {} + } + match *b"test" { + b"test" => {} + //~^ ERROR: mismatched types + _ => {} + } + match *(b"test" as &[u8]) { + b"test" => {} + //~^ ERROR: mismatched types + _ => {} + } } diff --git a/tests/ui/pattern/deref-patterns/needs-gate.stderr b/tests/ui/pattern/deref-patterns/needs-gate.stderr index 8687b5dc977d..e886ca980558 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.stderr +++ b/tests/ui/pattern/deref-patterns/needs-gate.stderr @@ -23,7 +23,31 @@ help: consider dereferencing to access the inner value using the Deref trait LL | match *Box::new(0) { | + -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:18:9 + | +LL | match *"test" { + | ------- this expression has type `str` +LL | "test" => {} + | ^^^^^^ expected `str`, found `&str` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:23:9 + | +LL | match *b"test" { + | -------- this expression has type `[u8; 4]` +LL | b"test" => {} + | ^^^^^^^ expected `[u8; 4]`, found `&[u8; 4]` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:28:9 + | +LL | match *(b"test" as &[u8]) { + | ------------------- this expression has type `[u8]` +LL | b"test" => {} + | ^^^^^^^ expected `[u8]`, found `&[u8; 4]` + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0308, E0658. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/strings.rs b/tests/ui/pattern/deref-patterns/strings.rs new file mode 100644 index 000000000000..536e943b3f67 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/strings.rs @@ -0,0 +1,66 @@ +//@ run-pass +//! Test deref patterns using string and bytestring literals. + +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +fn main() { + for (test_in, test_expect) in [("zero", 0), ("one", 1), ("two", 2)] { + // Test string literal patterns having type `str`. + let test_actual = match *test_in { + "zero" => 0, + "one" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test string literals in explicit `deref!(_)` patterns. + let test_actual = match test_in.to_string() { + deref!("zero") => 0, + deref!("one") => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + } + + // Test that we can still mutate in the match arm after using a literal to test equality: + let mut test = "test".to_string(); + if let deref!(s @ "test") = &mut test { + s.make_ascii_uppercase(); + } + assert_eq!(test, "TEST"); + + for (test_in, test_expect) in [(b"0", 0), (b"1", 1), (b"2", 2)] { + // Test byte string literal patterns having type `[u8; N]` + let test_actual = match *test_in { + b"0" => 0, + b"1" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test byte string literal patterns having type `[u8]` + let test_actual = match *(test_in as &[u8]) { + b"0" => 0, + b"1" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test byte string literals used as arrays in explicit `deref!(_)` patterns. + let test_actual = match Box::new(*test_in) { + deref!(b"0") => 0, + deref!(b"1") => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test byte string literals used as slices in explicit `deref!(_)` patterns. + let test_actual = match test_in.to_vec() { + deref!(b"0") => 0, + deref!(b"1") => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + } +} diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.rs b/tests/ui/pattern/deref-patterns/typeck_fail.rs index 4b9ad7d25f09..52d84f7a34de 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.rs +++ b/tests/ui/pattern/deref-patterns/typeck_fail.rs @@ -2,18 +2,14 @@ #![allow(incomplete_features)] fn main() { - // FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a - // place of type `str`. + // FIXME(deref_patterns): fails to typecheck because string literal patterns don't peel + // references from the scrutinee. match "foo".to_string() { - deref!("foo") => {} - //~^ ERROR: mismatched types "foo" => {} //~^ ERROR: mismatched types _ => {} } match &"foo".to_string() { - deref!("foo") => {} - //~^ ERROR: mismatched types "foo" => {} //~^ ERROR: mismatched types _ => {} diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.stderr b/tests/ui/pattern/deref-patterns/typeck_fail.stderr index 3e2f35618822..e87528c1c51a 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.stderr +++ b/tests/ui/pattern/deref-patterns/typeck_fail.stderr @@ -1,34 +1,16 @@ error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:8:16 + --> $DIR/typeck_fail.rs:8:9 | LL | match "foo".to_string() { | ----------------- this expression has type `String` -LL | deref!("foo") => {} - | ^^^^^ expected `str`, found `&str` - -error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:10:9 - | -LL | match "foo".to_string() { - | ----------------- this expression has type `String` -... LL | "foo" => {} | ^^^^^ expected `String`, found `&str` error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:15:16 + --> $DIR/typeck_fail.rs:13:9 | LL | match &"foo".to_string() { | ------------------ this expression has type `&String` -LL | deref!("foo") => {} - | ^^^^^ expected `str`, found `&str` - -error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:17:9 - | -LL | match &"foo".to_string() { - | ------------------ this expression has type `&String` -... LL | "foo" => {} | ^^^^^ expected `&String`, found `&str` | @@ -36,7 +18,7 @@ LL | "foo" => {} found reference `&'static str` error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:24:9 + --> $DIR/typeck_fail.rs:20:9 | LL | match Some(0) { | ------- this expression has type `Option<{integer}>` @@ -46,6 +28,6 @@ LL | Ok(0) => {} = note: expected enum `Option<{integer}>` found enum `Result<_, _>` -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.fixed b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.fixed deleted file mode 100644 index f5dbf0c8b6f4..000000000000 --- a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.fixed +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-rustfix - -use std::fmt; - -struct Hello; - -impl fmt::Display for Hello { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { //~ ERROR path separator must be a double colon - write!(f, "hello") - } -} - -fn main() { - let _ = Hello; -} diff --git a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.rs b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.rs deleted file mode 100644 index c41880a26f6e..000000000000 --- a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-rustfix - -use std::fmt; - -struct Hello; - -impl fmt::Display for Hello { - fn fmt(&self, f: &mut fmt:Formatter) -> fmt::Result { //~ ERROR path separator must be a double colon - write!(f, "hello") - } -} - -fn main() { - let _ = Hello; -} diff --git a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr deleted file mode 100644 index 713b071a625a..000000000000 --- a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: path separator must be a double colon - --> $DIR/argument-list-from-path-sep-error-129273.rs:8:30 - | -LL | fn fmt(&self, f: &mut fmt:Formatter) -> fmt::Result { - | ^ - | -help: use a double colon instead - | -LL | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - | + - -error: aborting due to 1 previous error - diff --git a/tests/ui/suggestions/struct-field-type-including-single-colon.rs b/tests/ui/suggestions/struct-field-type-including-single-colon.rs index a3111028895d..482641fc7cac 100644 --- a/tests/ui/suggestions/struct-field-type-including-single-colon.rs +++ b/tests/ui/suggestions/struct-field-type-including-single-colon.rs @@ -7,14 +7,14 @@ mod foo { struct Foo { a: foo:A, - //~^ ERROR path separator must be a double colon - //~| ERROR struct `A` is private + //~^ ERROR found single colon in a struct field type path + //~| ERROR expected `,`, or `}`, found `:` } struct Bar { b: foo::bar:B, - //~^ ERROR path separator must be a double colon - //~| ERROR module `bar` is private + //~^ ERROR found single colon in a struct field type path + //~| ERROR expected `,`, or `}`, found `:` } fn main() {} diff --git a/tests/ui/suggestions/struct-field-type-including-single-colon.stderr b/tests/ui/suggestions/struct-field-type-including-single-colon.stderr index b9302b0453d5..5ffc5b40849b 100644 --- a/tests/ui/suggestions/struct-field-type-including-single-colon.stderr +++ b/tests/ui/suggestions/struct-field-type-including-single-colon.stderr @@ -1,51 +1,40 @@ -error: path separator must be a double colon +error: found single colon in a struct field type path --> $DIR/struct-field-type-including-single-colon.rs:9:11 | LL | a: foo:A, | ^ | -help: use a double colon instead +help: write a path separator here | LL | a: foo::A, | + -error: path separator must be a double colon +error: expected `,`, or `}`, found `:` + --> $DIR/struct-field-type-including-single-colon.rs:9:11 + | +LL | struct Foo { + | --- while parsing this struct +LL | a: foo:A, + | ^ + +error: found single colon in a struct field type path --> $DIR/struct-field-type-including-single-colon.rs:15:16 | LL | b: foo::bar:B, | ^ | -help: use a double colon instead +help: write a path separator here | LL | b: foo::bar::B, | + -error[E0603]: struct `A` is private - --> $DIR/struct-field-type-including-single-colon.rs:9:12 - | -LL | a: foo:A, - | ^ private struct - | -note: the struct `A` is defined here - --> $DIR/struct-field-type-including-single-colon.rs:2:5 - | -LL | struct A; - | ^^^^^^^^^ - -error[E0603]: module `bar` is private - --> $DIR/struct-field-type-including-single-colon.rs:15:13 +error: expected `,`, or `}`, found `:` + --> $DIR/struct-field-type-including-single-colon.rs:15:16 | +LL | struct Bar { + | --- while parsing this struct LL | b: foo::bar:B, - | ^^^ - struct `B` is not publicly re-exported - | | - | private module - | -note: the module `bar` is defined here - --> $DIR/struct-field-type-including-single-colon.rs:3:5 - | -LL | mod bar { - | ^^^^^^^ + | ^ error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/transmute/unnecessary-transmutation.fixed b/tests/ui/transmute/unnecessary-transmutation.fixed new file mode 100644 index 000000000000..1a0df143cc5f --- /dev/null +++ b/tests/ui/transmute/unnecessary-transmutation.fixed @@ -0,0 +1,85 @@ +//@ run-rustfix +#![deny(unnecessary_transmutes)] +#![allow(unused_unsafe, unused_imports, unused_variables, unused_parens)] +use std::mem::transmute; + +pub fn bytes_at_home(x: u32) -> [u8; 4] { + unsafe { u32::to_ne_bytes(x) } + //~^ ERROR +} + +fn main() { + unsafe { + let x: u16 = u16::from_ne_bytes(*b"01"); + //~^ ERROR + let x: [u8; 2] = u16::to_ne_bytes(x); + //~^ ERROR + let x: u32 = u32::from_ne_bytes(*b"0123"); + //~^ ERROR + let x: [u8; 4] = u32::to_ne_bytes(x); + //~^ ERROR + let x: u64 = u64::from_ne_bytes(*b"feriscat"); + //~^ ERROR + let x: [u8; 8] = u64::to_ne_bytes(x); + //~^ ERROR + + let y: i16 = i16::from_ne_bytes(*b"01"); + //~^ ERROR + let y: [u8; 2] = i16::to_ne_bytes(y); + //~^ ERROR + let y: i32 = i32::from_ne_bytes(*b"0123"); + //~^ ERROR + let y: [u8; 4] = i32::to_ne_bytes(y); + //~^ ERROR + let y: i64 = i64::from_ne_bytes(*b"feriscat"); + //~^ ERROR + let y: [u8; 8] = i64::to_ne_bytes(y); + //~^ ERROR + + let z: f32 = f32::from_ne_bytes(*b"0123"); + //~^ ERROR + let z: [u8; 4] = f32::to_ne_bytes(z); + //~^ ERROR + let z: f64 = f64::from_ne_bytes(*b"feriscat"); + //~^ ERROR + let z: [u8; 8] = f64::to_ne_bytes(z); + //~^ ERROR + + let y: u32 = u32::from('🦀'); + //~^ ERROR + let y: char = char::from_u32_unchecked(y); + //~^ ERROR + + let x: u16 = i16::cast_unsigned(8i16); + //~^ ERROR + let x: i16 = u16::cast_signed(x); + //~^ ERROR + let x: u32 = i32::cast_unsigned(4i32); + //~^ ERROR + let x: i32 = u32::cast_signed(x); + //~^ ERROR + let x: u64 = i64::cast_unsigned(7i64); + //~^ ERROR + let x: i64 = u64::cast_signed(x); + //~^ ERROR + + let y: f32 = f32::from_bits(1u32); + //~^ ERROR + let y: u32 = f32::to_bits(y); + //~^ ERROR + let y: f64 = f64::from_bits(3u64); + //~^ ERROR + let y: u64 = f64::to_bits(2.0); + //~^ ERROR + + let z: bool = (1u8 == 1); + //~^ ERROR + let z: u8 = (z) as u8; + //~^ ERROR + + let z: bool = transmute(1i8); + // no error! + let z: i8 = (z) as i8; + //~^ ERROR + } +} diff --git a/tests/ui/transmute/unnecessary-transmutation.rs b/tests/ui/transmute/unnecessary-transmutation.rs new file mode 100644 index 000000000000..6b979263c56c --- /dev/null +++ b/tests/ui/transmute/unnecessary-transmutation.rs @@ -0,0 +1,85 @@ +//@ run-rustfix +#![deny(unnecessary_transmutes)] +#![allow(unused_unsafe, unused_imports, unused_variables, unused_parens)] +use std::mem::transmute; + +pub fn bytes_at_home(x: u32) -> [u8; 4] { + unsafe { transmute(x) } + //~^ ERROR +} + +fn main() { + unsafe { + let x: u16 = transmute(*b"01"); + //~^ ERROR + let x: [u8; 2] = transmute(x); + //~^ ERROR + let x: u32 = transmute(*b"0123"); + //~^ ERROR + let x: [u8; 4] = transmute(x); + //~^ ERROR + let x: u64 = transmute(*b"feriscat"); + //~^ ERROR + let x: [u8; 8] = transmute(x); + //~^ ERROR + + let y: i16 = transmute(*b"01"); + //~^ ERROR + let y: [u8; 2] = transmute(y); + //~^ ERROR + let y: i32 = transmute(*b"0123"); + //~^ ERROR + let y: [u8; 4] = transmute(y); + //~^ ERROR + let y: i64 = transmute(*b"feriscat"); + //~^ ERROR + let y: [u8; 8] = transmute(y); + //~^ ERROR + + let z: f32 = transmute(*b"0123"); + //~^ ERROR + let z: [u8; 4] = transmute(z); + //~^ ERROR + let z: f64 = transmute(*b"feriscat"); + //~^ ERROR + let z: [u8; 8] = transmute(z); + //~^ ERROR + + let y: u32 = transmute('🦀'); + //~^ ERROR + let y: char = transmute(y); + //~^ ERROR + + let x: u16 = transmute(8i16); + //~^ ERROR + let x: i16 = transmute(x); + //~^ ERROR + let x: u32 = transmute(4i32); + //~^ ERROR + let x: i32 = transmute(x); + //~^ ERROR + let x: u64 = transmute(7i64); + //~^ ERROR + let x: i64 = transmute(x); + //~^ ERROR + + let y: f32 = transmute(1u32); + //~^ ERROR + let y: u32 = transmute(y); + //~^ ERROR + let y: f64 = transmute(3u64); + //~^ ERROR + let y: u64 = transmute(2.0); + //~^ ERROR + + let z: bool = transmute(1u8); + //~^ ERROR + let z: u8 = transmute(z); + //~^ ERROR + + let z: bool = transmute(1i8); + // no error! + let z: i8 = transmute(z); + //~^ ERROR + } +} diff --git a/tests/ui/transmute/unnecessary-transmutation.stderr b/tests/ui/transmute/unnecessary-transmutation.stderr new file mode 100644 index 000000000000..b661aa13c985 --- /dev/null +++ b/tests/ui/transmute/unnecessary-transmutation.stderr @@ -0,0 +1,235 @@ +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:7:14 + | +LL | unsafe { transmute(x) } + | ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)` + | + = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order +note: the lint level is defined here + --> $DIR/unnecessary-transmutation.rs:2:9 + | +LL | #![deny(unnecessary_transmutes)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:13:22 + | +LL | let x: u16 = transmute(*b"01"); + | ^^^^^^^^^^^^^^^^^ help: replace this with: `u16::from_ne_bytes(*b"01")` + | + = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:15:26 + | +LL | let x: [u8; 2] = transmute(x); + | ^^^^^^^^^^^^ help: replace this with: `u16::to_ne_bytes(x)` + | + = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:17:22 + | +LL | let x: u32 = transmute(*b"0123"); + | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `u32::from_ne_bytes(*b"0123")` + | + = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:19:26 + | +LL | let x: [u8; 4] = transmute(x); + | ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)` + | + = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:21:22 + | +LL | let x: u64 = transmute(*b"feriscat"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `u64::from_ne_bytes(*b"feriscat")` + | + = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:23:26 + | +LL | let x: [u8; 8] = transmute(x); + | ^^^^^^^^^^^^ help: replace this with: `u64::to_ne_bytes(x)` + | + = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:26:22 + | +LL | let y: i16 = transmute(*b"01"); + | ^^^^^^^^^^^^^^^^^ help: replace this with: `i16::from_ne_bytes(*b"01")` + | + = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:28:26 + | +LL | let y: [u8; 2] = transmute(y); + | ^^^^^^^^^^^^ help: replace this with: `i16::to_ne_bytes(y)` + | + = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:30:22 + | +LL | let y: i32 = transmute(*b"0123"); + | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `i32::from_ne_bytes(*b"0123")` + | + = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:32:26 + | +LL | let y: [u8; 4] = transmute(y); + | ^^^^^^^^^^^^ help: replace this with: `i32::to_ne_bytes(y)` + | + = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:34:22 + | +LL | let y: i64 = transmute(*b"feriscat"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `i64::from_ne_bytes(*b"feriscat")` + | + = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:36:26 + | +LL | let y: [u8; 8] = transmute(y); + | ^^^^^^^^^^^^ help: replace this with: `i64::to_ne_bytes(y)` + | + = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:39:22 + | +LL | let z: f32 = transmute(*b"0123"); + | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `f32::from_ne_bytes(*b"0123")` + | + = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:41:26 + | +LL | let z: [u8; 4] = transmute(z); + | ^^^^^^^^^^^^ help: replace this with: `f32::to_ne_bytes(z)` + | + = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:43:22 + | +LL | let z: f64 = transmute(*b"feriscat"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `f64::from_ne_bytes(*b"feriscat")` + | + = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:45:26 + | +LL | let z: [u8; 8] = transmute(z); + | ^^^^^^^^^^^^ help: replace this with: `f64::to_ne_bytes(z)` + | + = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:48:22 + | +LL | let y: u32 = transmute('🦀'); + | ^^^^^^^^^^^^^^^ help: replace this with: `u32::from('🦀')` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:50:23 + | +LL | let y: char = transmute(y); + | ^^^^^^^^^^^^ help: replace this with: `char::from_u32_unchecked(y)` + | + = help: consider `char::from_u32(…).unwrap()` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:53:22 + | +LL | let x: u16 = transmute(8i16); + | ^^^^^^^^^^^^^^^ help: replace this with: `i16::cast_unsigned(8i16)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:55:22 + | +LL | let x: i16 = transmute(x); + | ^^^^^^^^^^^^ help: replace this with: `u16::cast_signed(x)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:57:22 + | +LL | let x: u32 = transmute(4i32); + | ^^^^^^^^^^^^^^^ help: replace this with: `i32::cast_unsigned(4i32)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:59:22 + | +LL | let x: i32 = transmute(x); + | ^^^^^^^^^^^^ help: replace this with: `u32::cast_signed(x)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:61:22 + | +LL | let x: u64 = transmute(7i64); + | ^^^^^^^^^^^^^^^ help: replace this with: `i64::cast_unsigned(7i64)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:63:22 + | +LL | let x: i64 = transmute(x); + | ^^^^^^^^^^^^ help: replace this with: `u64::cast_signed(x)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:66:22 + | +LL | let y: f32 = transmute(1u32); + | ^^^^^^^^^^^^^^^ help: replace this with: `f32::from_bits(1u32)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:68:22 + | +LL | let y: u32 = transmute(y); + | ^^^^^^^^^^^^ help: replace this with: `f32::to_bits(y)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:70:22 + | +LL | let y: f64 = transmute(3u64); + | ^^^^^^^^^^^^^^^ help: replace this with: `f64::from_bits(3u64)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:72:22 + | +LL | let y: u64 = transmute(2.0); + | ^^^^^^^^^^^^^^ help: replace this with: `f64::to_bits(2.0)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:75:23 + | +LL | let z: bool = transmute(1u8); + | ^^^^^^^^^^^^^^ help: replace this with: `(1u8 == 1)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:77:21 + | +LL | let z: u8 = transmute(z); + | ^^^^^^^^^^^^ help: replace this with: `(z) as u8` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:82:21 + | +LL | let z: i8 = transmute(z); + | ^^^^^^^^^^^^ help: replace this with: `(z) as i8` + +error: aborting due to 32 previous errors + diff --git a/triagebot.toml b/triagebot.toml index 189223f2feba..422996cb200d 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -585,6 +585,11 @@ trigger_files = [ "src/tools/compiletest" ] +[autolabel."A-test-infra-minicore"] +trigger_files = [ + "tests/auxiliary/minicore.rs", +] + [autolabel."A-rustc-dev-guide"] trigger_files = [ "src/doc/rustc-dev-guide", @@ -869,6 +874,10 @@ cc = ["@GuillaumeGomez"] message = "This PR modifies `run-make` tests." cc = ["@jieyouxu"] +[mentions."tests/auxiliary/minicore.rs"] +message = "This PR modifies `tests/auxiliary/minicore.rs`." +cc = ["@jieyouxu"] + [mentions."src/rustdoc-json-types"] message = """ rustdoc-json-types is a **public** (although nightly-only) API. \