diff --git a/Cargo.lock b/Cargo.lock index a18219b56837e..87a68270e3efb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "ar_archive_writer" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de11a9d32db3327f981143bdf699ade4d637c6887b13b97e6e91a9154666963c" +checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4" dependencies = [ "object 0.36.3", ] diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 30f90bada9adc..554a6d26ad901 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -629,6 +629,9 @@ pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> }; let hash_value = hex_encode(source_file.src_hash.hash_bytes()); + let source = + cx.sess().opts.unstable_opts.embed_source.then_some(()).and(source_file.src.as_ref()); + unsafe { llvm::LLVMRustDIBuilderCreateFile( DIB(cx), @@ -639,6 +642,8 @@ pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> hash_kind, hash_value.as_ptr().cast(), hash_value.len(), + source.map_or(ptr::null(), |x| x.as_ptr().cast()), + source.map_or(0, |x| x.len()), ) } } @@ -659,6 +664,8 @@ pub fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile { llvm::ChecksumKind::None, hash_value.as_ptr().cast(), hash_value.len(), + ptr::null(), + 0, ) }) } @@ -943,6 +950,8 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( llvm::ChecksumKind::None, ptr::null(), 0, + ptr::null(), + 0, ); let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index faabbcb020d5f..7a495174ff1aa 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1860,6 +1860,8 @@ extern "C" { CSKind: ChecksumKind, Checksum: *const c_char, ChecksumLen: size_t, + Source: *const c_char, + SourceLen: size_t, ) -> &'a DIFile; pub fn LLVMRustDIBuilderCreateSubroutineType<'a>( diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index e3033b332caee..56b75f9b3292d 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -ar_archive_writer = "0.4.0" +ar_archive_writer = "0.4.2" arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" cc = "1.0.90" diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 38a440a707a23..c8c1bd3e8f9c3 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -108,7 +108,11 @@ pub trait ArchiveBuilderBuilder { &exports, machine, !sess.target.is_like_msvc, - /*comdat=*/ false, + // Enable compatibility with MSVC's `/WHOLEARCHIVE` flag. + // Without this flag a duplicate symbol error would be emitted + // when linking a rust staticlib using `/WHOLEARCHIVE`. + // See #129020 + true, ) { sess.dcx() .emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 16eeb57b2b967..14c5f8d9f16da 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -529,7 +529,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe match tcx.named_bound_var(hir_id) { Some(ResolvedArg::EarlyBound(def_id)) => { - expected_captures.insert(def_id); + expected_captures.insert(def_id.to_def_id()); // Make sure we allow capturing these lifetimes through `Self` and // `T::Assoc` projection syntax, too. These will occur when we only @@ -538,7 +538,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe // feature -- see . if let DefKind::LifetimeParam = tcx.def_kind(def_id) && let Some(def_id) = tcx - .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local()) + .map_opaque_lifetime_to_parent_lifetime(def_id) .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id())) { shadowed_captures.insert(def_id); diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index ae0c70d232685..0cf9e128bceef 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -13,7 +13,6 @@ use rustc_ast::visit::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node}; use rustc_macros::extension; @@ -22,7 +21,7 @@ use rustc_middle::middle::resolve_bound_vars::*; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_middle::{bug, span_bug}; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -32,7 +31,7 @@ use crate::errors; impl ResolvedArg { fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { debug!("ResolvedArg::early: def_id={:?}", param.def_id); - (param.def_id, ResolvedArg::EarlyBound(param.def_id.to_def_id())) + (param.def_id, ResolvedArg::EarlyBound(param.def_id)) } fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { @@ -41,10 +40,10 @@ impl ResolvedArg { "ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}", idx, param, depth, param.def_id, ); - (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id.to_def_id())) + (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id)) } - fn id(&self) -> Option { + fn id(&self) -> Option { match *self { ResolvedArg::StaticLifetime | ResolvedArg::Error(_) => None, @@ -288,13 +287,14 @@ fn late_arg_as_bound_arg<'tcx>( ) -> ty::BoundVariableKind { match arg { ResolvedArg::LateBound(_, _, def_id) => { - let name = tcx.hir().name(tcx.local_def_id_to_hir_id(def_id.expect_local())); + let def_id = def_id.to_def_id(); + let name = tcx.item_name(def_id); match param.kind { GenericParamKind::Lifetime { .. } => { - ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name)) + ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) } GenericParamKind::Type { .. } => { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(*def_id, name)) + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) } GenericParamKind::Const { .. } => ty::BoundVariableKind::Const, } @@ -717,7 +717,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // In the future, this should be fixed and this error should be removed. let def = self.map.defs.get(&lifetime.hir_id).copied(); let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue }; - let Some(lifetime_def_id) = lifetime_def_id.as_local() else { continue }; let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id)) @@ -1150,7 +1149,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { .param_def_id_to_index(self.tcx, region_def_id.to_def_id()) .is_some() { - break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id())); + break Some(ResolvedArg::EarlyBound(region_def_id)); } break None; } @@ -1259,7 +1258,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { kind => span_bug!( use_span, "did not expect to resolve lifetime to {}", - kind.descr(param_def_id) + kind.descr(param_def_id.to_def_id()) ), }; def = ResolvedArg::Error(guar); @@ -1277,10 +1276,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { kind: hir::ImplItemKind::Fn(..), .. }) => { - def = ResolvedArg::Free(owner_id.to_def_id(), def.id().unwrap()); + def = ResolvedArg::Free(owner_id.def_id, def.id().unwrap()); } Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) => { - def = ResolvedArg::Free(closure.def_id.to_def_id(), def.id().unwrap()); + def = ResolvedArg::Free(closure.def_id, def.id().unwrap()); } _ => {} } @@ -1351,7 +1350,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { .param_def_id_to_index(self.tcx, param_def_id.to_def_id()) .is_some() { - break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id())); + break Some(ResolvedArg::EarlyBound(param_def_id)); } break None; } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2fb1bcf2dbfff..5c8ecf254a54e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -296,25 +296,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static, Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { - let name = lifetime_name(def_id.expect_local()); + let name = lifetime_name(def_id); let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), - kind: ty::BrNamed(def_id, name), + kind: ty::BrNamed(def_id.to_def_id(), name), }; ty::Region::new_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(def_id)) => { - let name = tcx.hir().ty_param_name(def_id.expect_local()); - let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); + let name = tcx.hir().ty_param_name(def_id); + let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; + let index = generics.param_def_id_to_index[&def_id.to_def_id()]; ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name }) } Some(rbv::ResolvedArg::Free(scope, id)) => { - let name = lifetime_name(id.expect_local()); - ty::Region::new_late_param(tcx, scope, ty::BrNamed(id, name)) + let name = lifetime_name(id); + ty::Region::new_late_param( + tcx, + scope.to_def_id(), + ty::BrNamed(id.to_def_id(), name), + ) // (*) -- not late-bound, won't change } @@ -1953,15 +1957,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); match tcx.named_bound_var(hir_id) { Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { - let name = tcx.item_name(def_id); + let name = tcx.item_name(def_id.to_def_id()); let br = ty::BoundTy { var: ty::BoundVar::from_u32(index), - kind: ty::BoundTyKind::Param(def_id, name), + kind: ty::BoundTyKind::Param(def_id.to_def_id(), name), }; Ty::new_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(def_id)) => { - let def_id = def_id.expect_local(); let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; @@ -1982,10 +1985,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(rbv::ResolvedArg::EarlyBound(def_id)) => { // Find the name and index of the const parameter by indexing the generics of // the parent item and construct a `ParamConst`. - let item_def_id = tcx.parent(def_id); + let item_def_id = tcx.local_parent(def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - let name = tcx.item_name(def_id); + let index = generics.param_def_id_to_index[&def_id.to_def_id()]; + let name = tcx.item_name(def_id.to_def_id()); ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 34f2dca7c42ff..486136a2bcc10 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -774,6 +774,7 @@ fn test_unstable_options_tracking_hash() { tracked!(direct_access_external_data, Some(true)); tracked!(dual_proc_macros, true); tracked!(dwarf_version, Some(5)); + tracked!(embed_source, true); tracked!(emit_thin_lto, false); tracked!(export_executable_symbols, true); tracked!(fewer_names, Some(true)); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 85132dd4f98f0..d8482567bbe5b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1925,8 +1925,8 @@ impl ExplicitOutlivesRequirements { fn lifetimes_outliving_lifetime<'tcx>( tcx: TyCtxt<'tcx>, inferred_outlives: impl Iterator, Span)>, - item: DefId, - lifetime: DefId, + item: LocalDefId, + lifetime: LocalDefId, ) -> Vec> { let item_generics = tcx.generics_of(item); @@ -1934,7 +1934,7 @@ impl ExplicitOutlivesRequirements { .filter_map(|(clause, _)| match clause.kind().skip_binder() { ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { ty::ReEarlyParam(ebr) - if item_generics.region_param(ebr, tcx).def_id == lifetime => + if item_generics.region_param(ebr, tcx).def_id == lifetime.to_def_id() => { Some(b) } @@ -1982,7 +1982,7 @@ impl ExplicitOutlivesRequirements { let is_inferred = match tcx.named_bound_var(lifetime.hir_id) { Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives .iter() - .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id })), + .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id.to_def_id() })), _ => false, }; @@ -2097,7 +2097,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { inferred_outlives .iter() .filter(|(_, span)| !predicate.span.contains(*span)), - item.owner_id.to_def_id(), + item.owner_id.def_id, region_def_id, ), &predicate.bounds, diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 990fb2d16f9dd..2e0da69e92070 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -300,16 +300,17 @@ impl<'tcx> TypeVisitor> for VisitOpaqueTypes<'tcx> { Some( ResolvedArg::EarlyBound(def_id) | ResolvedArg::LateBound(_, _, def_id), ) => { - if self.tcx.def_kind(self.tcx.parent(def_id)) == DefKind::OpaqueTy { + if self.tcx.def_kind(self.tcx.local_parent(def_id)) == DefKind::OpaqueTy + { let def_id = self .tcx - .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local()) + .map_opaque_lifetime_to_parent_lifetime(def_id) .opt_param_def_id(self.tcx, self.parent_def_id.to_def_id()) .expect("variable should have been duplicated from parent"); explicitly_captured.insert(def_id); } else { - explicitly_captured.insert(def_id); + explicitly_captured.insert(def_id.to_def_id()); } } _ => { diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 79a68b2ff0e67..ed12318c88dae 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -913,14 +913,19 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile(LLVMRustDIBuilderRef Builder, const char *Filename, size_t FilenameLen, const char *Directory, size_t DirectoryLen, LLVMRustChecksumKind CSKind, - const char *Checksum, size_t ChecksumLen) { + const char *Checksum, size_t ChecksumLen, + const char *Source, size_t SourceLen) { std::optional llvmCSKind = fromRust(CSKind); std::optional> CSInfo{}; if (llvmCSKind) CSInfo.emplace(*llvmCSKind, StringRef{Checksum, ChecksumLen}); + std::optional oSource{}; + if (Source) + oSource = StringRef(Source, SourceLen); return wrap(Builder->createFile(StringRef(Filename, FilenameLen), - StringRef(Directory, DirectoryLen), CSInfo)); + StringRef(Directory, DirectoryLen), CSInfo, + oSource)); } extern "C" LLVMMetadataRef diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index a4f6d7afe4d11..32e2f3b4b1685 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{ItemLocalId, OwnerId}; use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; @@ -11,9 +11,9 @@ use crate::ty; #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum ResolvedArg { StaticLifetime, - EarlyBound(/* decl */ DefId), - LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ DefId), - Free(DefId, /* lifetime decl */ DefId), + EarlyBound(/* decl */ LocalDefId), + LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ LocalDefId), + Free(LocalDefId, /* lifetime decl */ LocalDefId), Error(ErrorGuaranteed), } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9b39b84970420..cad3515f06809 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3035,13 +3035,13 @@ impl<'tcx> TyCtxt<'tcx> { match self.named_bound_var(lifetime.hir_id) { Some(resolve_bound_vars::ResolvedArg::EarlyBound(ebv)) => { - let new_parent = self.parent(ebv); + let new_parent = self.local_parent(ebv); // If we map to another opaque, then it should be a parent // of the opaque we mapped from. Continue mapping. if matches!(self.def_kind(new_parent), DefKind::OpaqueTy) { - debug_assert_eq!(self.parent(parent.to_def_id()), new_parent); - opaque_lifetime_param_def_id = ebv.expect_local(); + debug_assert_eq!(self.local_parent(parent), new_parent); + opaque_lifetime_param_def_id = ebv; continue; } @@ -3050,20 +3050,20 @@ impl<'tcx> TyCtxt<'tcx> { self, ty::EarlyParamRegion { index: generics - .param_def_id_to_index(self, ebv) + .param_def_id_to_index(self, ebv.to_def_id()) .expect("early-bound var should be present in fn generics"), - name: self.hir().name(self.local_def_id_to_hir_id(ebv.expect_local())), + name: self.item_name(ebv.to_def_id()), }, ); } Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => { - let new_parent = self.parent(lbv); + let new_parent = self.local_parent(lbv); return ty::Region::new_late_param( self, - new_parent, + new_parent.to_def_id(), ty::BoundRegionKind::BrNamed( - lbv, - self.hir().name(self.local_def_id_to_hir_id(lbv.expect_local())), + lbv.to_def_id(), + self.item_name(lbv.to_def_id()), ), ); } diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index b84280a3ccf3f..01c371ee49884 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -14,6 +14,10 @@ session_crate_name_empty = crate name must not be empty session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen +session_embed_source_insufficient_dwarf_version = `-Zembed-source=y` requires at least `-Z dwarf-version=5` but DWARF version is {$dwarf_version} + +session_embed_source_requires_debug_info = `-Zembed-source=y` requires debug information to be enabled + session_expr_parentheses_needed = parentheses are required to parse this as an expression session_failed_to_create_profiler = failed to create profiler: {$err} diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 5cc54a5855bbe..15bbd4ff7bf4b 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -165,6 +165,16 @@ pub(crate) struct UnsupportedDwarfVersion { pub(crate) dwarf_version: u32, } +#[derive(Diagnostic)] +#[diag(session_embed_source_insufficient_dwarf_version)] +pub(crate) struct EmbedSourceInsufficientDwarfVersion { + pub(crate) dwarf_version: u32, +} + +#[derive(Diagnostic)] +#[diag(session_embed_source_requires_debug_info)] +pub(crate) struct EmbedSourceRequiresDebugInfo; + #[derive(Diagnostic)] #[diag(session_target_stack_protector_not_supported)] pub(crate) struct StackProtectorNotSupportedForTarget<'a> { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index df72e2430fd50..23231fbffbfdb 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1701,6 +1701,8 @@ options! { them only if an error has not been emitted"), ehcont_guard: bool = (false, parse_bool, [TRACKED], "generate Windows EHCont Guard tables"), + embed_source: bool = (false, parse_bool, [TRACKED], + "embed source text in DWARF debug sections (default: no)"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), emit_thin_lto: bool = (true, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 693867c3853da..68efd0faea5c1 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -37,8 +37,9 @@ use rustc_target::spec::{ use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use crate::config::{ - self, CoverageLevel, CrateType, ErrorOutputType, FunctionReturn, Input, InstrumentCoverage, - OptLevel, OutFileName, OutputType, RemapPathScopeComponents, SwitchWithOptPath, + self, CoverageLevel, CrateType, DebugInfo, ErrorOutputType, FunctionReturn, Input, + InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents, + SwitchWithOptPath, }; use crate::parse::{add_feature_diagnostics, ParseSess}; use crate::search_paths::{PathKind, SearchPath}; @@ -1306,6 +1307,19 @@ fn validate_commandline_args_with_session_available(sess: &Session) { .emit_err(errors::SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() }); } + if sess.opts.unstable_opts.embed_source { + let dwarf_version = + sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version); + + if dwarf_version < 5 { + sess.dcx().emit_warn(errors::EmbedSourceInsufficientDwarfVersion { dwarf_version }); + } + + if sess.opts.debuginfo == DebugInfo::None { + sess.dcx().emit_warn(errors::EmbedSourceRequiresDebugInfo); + } + } + if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray { sess.dcx().emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() }); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs index 3f35391be1355..cd61747917a88 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs @@ -101,7 +101,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // region at the right depth with the same index (Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); - if id == def_id { + if id.to_def_id() == def_id { return ControlFlow::Break(arg); } } @@ -118,7 +118,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { debruijn_index ); debug!("LateBound id={:?} def_id={:?}", id, def_id); - if debruijn_index == self.current_index && id == def_id { + if debruijn_index == self.current_index && id.to_def_id() == def_id { return ControlFlow::Break(arg); } } @@ -192,7 +192,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { // the lifetime of the TyPath! (Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); - if id == def_id { + if id.to_def_id() == def_id { return ControlFlow::Break(()); } } @@ -201,7 +201,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,); debug!("id={:?}", id); debug!("def_id={:?}", def_id); - if debruijn_index == self.current_index && id == def_id { + if debruijn_index == self.current_index && id.to_def_id() == def_id { return ControlFlow::Break(()); } } diff --git a/library/Cargo.lock b/library/Cargo.lock index 30f5076e1e223..f2f446b61085d 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -58,9 +58,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.118" +version = "0.1.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92afe7344b64cccf3662ca26d5d1c0828ab826f04206b97d856e3625e390e4b5" +checksum = "38c44e9c76d996d8049dee591a997eab801069ad86ed892ed3039f68b73d301c" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index bdf16257c7cd0..43799acc02736 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.118", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.120", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 41bd34a270238..bb0cc1c60ba5a 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -261,7 +261,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let nan = f16::NAN; /// let f = 7.0_f16; @@ -293,7 +293,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let f = 7.0f16; /// let inf = f16::INFINITY; @@ -319,7 +319,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let f = 7.0f16; /// let inf: f16 = f16::INFINITY; @@ -347,7 +347,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let min = f16::MIN_POSITIVE; // 6.1035e-5 /// let max = f16::MAX; @@ -377,7 +377,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let min = f16::MIN_POSITIVE; // 6.1035e-5 /// let max = f16::MAX; @@ -409,7 +409,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// use std::num::FpCategory; /// @@ -867,7 +867,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let value = 4.6_f16; /// let rounded = unsafe { value.to_int_unchecked::() }; @@ -910,7 +910,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// # // FIXME(f16_f128): enable this once const casting works /// # // assert_ne!((1f16).to_bits(), 1f16 as u128); // to_bits() is not casting! @@ -958,7 +958,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let v = f16::from_bits(0x4a40); /// assert_eq!(v, 12.5); @@ -1071,7 +1071,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let value = f16::from_be_bytes([0x4a, 0x40]); /// assert_eq!(value, 12.5); @@ -1094,7 +1094,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let value = f16::from_le_bytes([0x40, 0x4a]); /// assert_eq!(value, 12.5); @@ -1124,7 +1124,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let value = f16::from_ne_bytes(if cfg!(target_endian = "big") { /// [0x4a, 0x40] @@ -1257,7 +1257,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// assert!((-3.0f16).clamp(-2.0, 1.0) == -2.0); /// assert!((0.0f16).clamp(-2.0, 1.0) == 0.0); diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 7f23681ee45fc..dca42a3e98ec1 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.118" } +compiler_builtins = { version = "0.1.120" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = [ diff --git a/library/std/build.rs b/library/std/build.rs index 35a5977b6ebaf..3b77afcc3fc61 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -103,9 +103,6 @@ fn main() { ("arm64ec", _) => false, // MinGW ABI bugs ("x86_64", "windows") => false, - // x86 has ABI bugs that show up with optimizations. This should be partially fixed with - // the compiler-builtins update. - ("x86" | "x86_64", _) => false, // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` ("powerpc" | "powerpc64", _) => false, // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 8d20b95621384..4957de2e1b791 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -269,34 +269,45 @@ fn make_win_dist( let target_libs = find_files(&target_libs, &lib_path); // Copy runtime dlls next to rustc.exe - let dist_bin_dir = rust_root.join("bin/"); - fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed"); - for src in rustc_dlls { - builder.copy_link_to_folder(&src, &dist_bin_dir); + let rust_bin_dir = rust_root.join("bin/"); + fs::create_dir_all(&rust_bin_dir).expect("creating rust_bin_dir failed"); + for src in &rustc_dlls { + builder.copy_link_to_folder(src, &rust_bin_dir); + } + + if builder.config.lld_enabled { + // rust-lld.exe also needs runtime dlls + let rust_target_bin_dir = rust_root.join("lib/rustlib").join(target).join("bin"); + fs::create_dir_all(&rust_target_bin_dir).expect("creating rust_target_bin_dir failed"); + for src in &rustc_dlls { + builder.copy_link_to_folder(src, &rust_target_bin_dir); + } } //Copy platform tools to platform-specific bin directory - let target_bin_dir = - plat_root.join("lib").join("rustlib").join(target).join("bin").join("self-contained"); - fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed"); + let plat_target_bin_self_contained_dir = + plat_root.join("lib/rustlib").join(target).join("bin/self-contained"); + fs::create_dir_all(&plat_target_bin_self_contained_dir) + .expect("creating plat_target_bin_self_contained_dir failed"); for src in target_tools { - builder.copy_link_to_folder(&src, &target_bin_dir); + builder.copy_link_to_folder(&src, &plat_target_bin_self_contained_dir); } // Warn windows-gnu users that the bundled GCC cannot compile C files builder.create( - &target_bin_dir.join("GCC-WARNING.txt"), + &plat_target_bin_self_contained_dir.join("GCC-WARNING.txt"), "gcc.exe contained in this folder cannot be used for compiling C files - it is only \ used as a linker. In order to be able to compile projects containing C code use \ the GCC provided by MinGW or Cygwin.", ); //Copy platform libs to platform-specific lib directory - let target_lib_dir = - plat_root.join("lib").join("rustlib").join(target).join("lib").join("self-contained"); - fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed"); + let plat_target_lib_self_contained_dir = + plat_root.join("lib/rustlib").join(target).join("lib/self-contained"); + fs::create_dir_all(&plat_target_lib_self_contained_dir) + .expect("creating plat_target_lib_self_contained_dir failed"); for src in target_libs { - builder.copy_link_to_folder(&src, &target_lib_dir); + builder.copy_link_to_folder(&src, &plat_target_lib_self_contained_dir); } } diff --git a/src/doc/unstable-book/src/compiler-flags/embed-source.md b/src/doc/unstable-book/src/compiler-flags/embed-source.md new file mode 100644 index 0000000000000..01a11e3779712 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/embed-source.md @@ -0,0 +1,12 @@ +# `embed-source` + +This flag controls whether the compiler embeds the program source code text into +the object debug information section. It takes one of the following values: + +* `y`, `yes`, `on` or `true`: put source code in debug info. +* `n`, `no`, `off`, `false` or no value: omit source code from debug info (the default). + +This flag is ignored in configurations that don't emit DWARF debug information +and is ignored on non-LLVM backends. `-Z embed-source` requires DWARFv5. Use +`-Z dwarf-version=5` to control the compiler's DWARF target version and `-g` to +enable debug info generation. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index db81b4c4282a1..5260e363dd68c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -272,7 +272,7 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> | rbv::ResolvedArg::LateBound(_, _, did) | rbv::ResolvedArg::Free(_, did), ) = cx.tcx.named_bound_var(lifetime.hir_id) - && let Some(lt) = cx.args.get(&did).and_then(|arg| arg.as_lt()) + && let Some(lt) = cx.args.get(&did.to_def_id()).and_then(|arg| arg.as_lt()) { return lt.clone(); } diff --git a/tests/run-make/embed-source-dwarf/main.rs b/tests/run-make/embed-source-dwarf/main.rs new file mode 100644 index 0000000000000..c80af84f41415 --- /dev/null +++ b/tests/run-make/embed-source-dwarf/main.rs @@ -0,0 +1,2 @@ +// hello +fn main() {} diff --git a/tests/run-make/embed-source-dwarf/rmake.rs b/tests/run-make/embed-source-dwarf/rmake.rs new file mode 100644 index 0000000000000..06d550121b0de --- /dev/null +++ b/tests/run-make/embed-source-dwarf/rmake.rs @@ -0,0 +1,70 @@ +//@ ignore-windows +//@ ignore-apple + +// LLVM 17's embed-source implementation requires that source code is attached +// for all files in the output DWARF debug info. This restriction was lifted in +// LLVM 18 (87e22bdd2bd6d77d782f9d64b3e3ae5bdcd5080d). +//@ min-llvm-version: 18 + +// This test should be replaced with one in tests/debuginfo once we can easily +// tell via GDB or LLDB if debuginfo contains source code. Cheap tricks in LLDB +// like setting an invalid source map path don't appear to work, maybe this'll +// become easier once GDB supports DWARFv6? + +use std::collections::HashMap; +use std::path::PathBuf; +use std::rc::Rc; + +use gimli::{AttributeValue, EndianRcSlice, Reader, RunTimeEndian}; +use object::{Object, ObjectSection}; +use run_make_support::{gimli, object, rfs, rustc}; + +fn main() { + let output = PathBuf::from("embed-source-main"); + rustc() + .input("main.rs") + .output(&output) + .arg("-g") + .arg("-Zembed-source=yes") + .arg("-Zdwarf-version=5") + .run(); + let output = rfs::read(output); + let obj = object::File::parse(output.as_slice()).unwrap(); + let endian = if obj.is_little_endian() { RunTimeEndian::Little } else { RunTimeEndian::Big }; + let dwarf = gimli::Dwarf::load(|section| -> Result<_, ()> { + let data = obj.section_by_name(section.name()).map(|s| s.uncompressed_data().unwrap()); + Ok(EndianRcSlice::new(Rc::from(data.unwrap_or_default().as_ref()), endian)) + }) + .unwrap(); + + let mut sources = HashMap::new(); + + let mut iter = dwarf.units(); + while let Some(header) = iter.next().unwrap() { + let unit = dwarf.unit(header).unwrap(); + let unit = unit.unit_ref(&dwarf); + + if let Some(program) = &unit.line_program { + let header = program.header(); + for file in header.file_names() { + if let Some(source) = file.source() { + let path = unit + .attr_string(file.path_name()) + .unwrap() + .to_string_lossy() + .unwrap() + .to_string(); + let source = + unit.attr_string(source).unwrap().to_string_lossy().unwrap().to_string(); + if !source.is_empty() { + sources.insert(path, source); + } + } + } + } + } + + dbg!(&sources); + assert_eq!(sources.len(), 1); + assert_eq!(sources.get("main.rs").unwrap(), "// hello\nfn main() {}\n"); +} diff --git a/tests/run-make/msvc-wholearchive/c.c b/tests/run-make/msvc-wholearchive/c.c new file mode 100644 index 0000000000000..d6847845c6846 --- /dev/null +++ b/tests/run-make/msvc-wholearchive/c.c @@ -0,0 +1 @@ +// This page is intentionally left blank diff --git a/tests/run-make/msvc-wholearchive/dll.def b/tests/run-make/msvc-wholearchive/dll.def new file mode 100644 index 0000000000000..d55819e0d5e9f --- /dev/null +++ b/tests/run-make/msvc-wholearchive/dll.def @@ -0,0 +1,4 @@ +LIBRARY dll +EXPORTS + hello + number diff --git a/tests/run-make/msvc-wholearchive/rmake.rs b/tests/run-make/msvc-wholearchive/rmake.rs new file mode 100644 index 0000000000000..98586fd8cc8bd --- /dev/null +++ b/tests/run-make/msvc-wholearchive/rmake.rs @@ -0,0 +1,52 @@ +//! This is a regression test for #129020 +//! It ensures we can use `/WHOLEARCHIVE` to link a rust staticlib into DLL +//! using the MSVC linker + +//@ only-msvc +// Reason: this is testing the MSVC linker + +use std::path::PathBuf; + +use run_make_support::{cc, cmd, env_var, extra_c_flags, rustc}; + +fn main() { + // Build the staticlib + rustc().crate_type("staticlib").input("static.rs").output("static.lib").run(); + // Build an empty object to pass to the linker. + cc().input("c.c").output("c.obj").args(["-c"]).run(); + + // Find the C toolchain's linker. + let mut linker = PathBuf::from(env_var("CC")); + let linker_flavour = if linker.file_stem().is_some_and(|s| s == "cl") { + linker.set_file_name("link.exe"); + "msvc" + } else if linker.file_stem().is_some_and(|s| s == "clang-cl") { + linker.set_file_name("lld-link.exe"); + "llvm" + } else { + panic!("unknown C toolchain"); + }; + + // As a sanity check, make sure this works without /WHOLEARCHIVE. + // Otherwise the actual test failure may be caused by something else. + cmd(&linker) + .args(["c.obj", "./static.lib", "-dll", "-def:dll.def", "-out:dll.dll"]) + .args(extra_c_flags()) + .run(); + + // FIXME(@ChrisDenton): this doesn't currently work with llvm's lld-link for other reasons. + // May need LLVM patches. + if linker_flavour == "msvc" { + // Link in the staticlib using `/WHOLEARCHIVE` and produce a DLL. + cmd(&linker) + .args([ + "c.obj", + "-WHOLEARCHIVE:./static.lib", + "-dll", + "-def:dll.def", + "-out:dll_whole_archive.dll", + ]) + .args(extra_c_flags()) + .run(); + } +} diff --git a/tests/run-make/msvc-wholearchive/static.rs b/tests/run-make/msvc-wholearchive/static.rs new file mode 100644 index 0000000000000..881c88565737a --- /dev/null +++ b/tests/run-make/msvc-wholearchive/static.rs @@ -0,0 +1,9 @@ +#[no_mangle] +pub extern "C" fn hello() { + println!("Hello world!"); +} + +#[no_mangle] +pub extern "C" fn number() -> u32 { + 42 +} diff --git a/tests/ui/consts/const-float-bits-conv.rs b/tests/ui/consts/const-float-bits-conv.rs index 45e8ea570ed73..3a526c54dc376 100644 --- a/tests/ui/consts/const-float-bits-conv.rs +++ b/tests/ui/consts/const-float-bits-conv.rs @@ -3,8 +3,9 @@ #![feature(const_float_bits_conv)] #![feature(const_float_classify)] +#![feature(f16)] +#![feature(f128)] #![allow(unused_macro_rules)] - // Don't promote const fn nop(x: T) -> T { x } @@ -28,6 +29,37 @@ fn has_broken_floats() -> bool { std::env::var("TARGET").is_ok_and(|v| v.contains("i586")) } +#[cfg(target_arch = "x86_64")] +fn f16(){ + const_assert!((1f16).to_bits(), 0x3c00); + const_assert!(u16::from_be_bytes(1f16.to_be_bytes()), 0x3c00); + const_assert!((12.5f16).to_bits(), 0x4a40); + const_assert!(u16::from_le_bytes(12.5f16.to_le_bytes()), 0x4a40); + const_assert!((1337f16).to_bits(), 0x6539); + const_assert!(u16::from_ne_bytes(1337f16.to_ne_bytes()), 0x6539); + const_assert!((-14.25f16).to_bits(), 0xcb20); + const_assert!(f16::from_bits(0x3c00), 1.0); + const_assert!(f16::from_be_bytes(0x3c00u16.to_be_bytes()), 1.0); + const_assert!(f16::from_bits(0x4a40), 12.5); + const_assert!(f16::from_le_bytes(0x4a40u16.to_le_bytes()), 12.5); + const_assert!(f16::from_bits(0x5be0), 252.0); + const_assert!(f16::from_ne_bytes(0x5be0u16.to_ne_bytes()), 252.0); + const_assert!(f16::from_bits(0xcb20), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u16 = f16::NAN.to_bits() ^ 0x0155; + const SIGNALING_NAN: u16 = f16::NAN.to_bits() ^ 0x02AA; + + const_assert!(f16::from_bits(QUIET_NAN).is_nan()); + const_assert!(f16::from_bits(SIGNALING_NAN).is_nan()); + const_assert!(f16::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + const_assert!(f16::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + fn f32() { const_assert!((1f32).to_bits(), 0x3f800000); const_assert!(u32::from_be_bytes(1f32.to_be_bytes()), 0x3f800000); @@ -88,7 +120,43 @@ fn f64() { } } +#[cfg(target_arch = "x86_64")] +fn f128() { + const_assert!((1f128).to_bits(), 0x3fff0000000000000000000000000000); + const_assert!(u128::from_be_bytes(1f128.to_be_bytes()), 0x3fff0000000000000000000000000000); + const_assert!((12.5f128).to_bits(), 0x40029000000000000000000000000000); + const_assert!(u128::from_le_bytes(12.5f128.to_le_bytes()), 0x40029000000000000000000000000000); + const_assert!((1337f128).to_bits(), 0x40094e40000000000000000000000000); + const_assert!(u128::from_ne_bytes(1337f128.to_ne_bytes()), 0x40094e40000000000000000000000000); + const_assert!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000); + const_assert!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0); + const_assert!(f128::from_be_bytes(0x3fff0000000000000000000000000000u128.to_be_bytes()), 1.0); + const_assert!(f128::from_bits(0x40029000000000000000000000000000), 12.5); + const_assert!(f128::from_le_bytes(0x40029000000000000000000000000000u128.to_le_bytes()), 12.5); + const_assert!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0); + assert_eq!(f128::from_ne_bytes(0x40094e40000000000000000000000000u128.to_ne_bytes()), 1337.0); + const_assert!(f128::from_bits(0xc002c800000000000000000000000000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u128 = f128::NAN.to_bits() | 0x0000_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA; + const SIGNALING_NAN: u128 = f128::NAN.to_bits() ^ 0x0000_5555_5555_5555_5555_5555_5555_5555; + + const_assert!(f128::from_bits(QUIET_NAN).is_nan()); + const_assert!(f128::from_bits(SIGNALING_NAN).is_nan()); + const_assert!(f128::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + const_assert!(f128::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + fn main() { + #[cfg(target_arch = "x86_64")] + { + f16(); + f128(); + } f32(); f64(); }