diff --git a/compiler/rustc_attr_ir/src/lang_items.rs b/compiler/rustc_attr_ir/src/lang_items.rs index f2ad7abba755d..c1ad05dc8e4a8 100644 --- a/compiler/rustc_attr_ir/src/lang_items.rs +++ b/compiler/rustc_attr_ir/src/lang_items.rs @@ -465,6 +465,9 @@ language_item_table! { // Used to fallback `{float}` to `f32` when `f32: From<{float}>` From, sym::From, from_trait, Target::Trait, GenericRequirement::Exact(1); FromFn, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + + // Experimental lang item for `Reflection and comptime`(https://goals.rust-lang.org/2025h2/reflection-and-comptime.html) + FnPtr, sym::FnPtr, fn_ptr, Target::Struct, GenericRequirement::None; } /// The requirement imposed on the generics of a lang item diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 534cd1327bbe5..2f5793d5b3672 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -589,6 +589,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // result in basically the exact same error being reported to // the user. Avoid that. let mut deduplicate_errors = FxIndexSet::default(); + let mut failed_type_tests = Vec::new(); for type_test in &self.type_tests { debug!("check_type_test: {:?}", type_test); @@ -609,8 +610,40 @@ impl<'tcx> RegionInferenceContext<'tcx> { continue; } - // Type-test failed. Report the error. + // Type-test failed. Collect it so we can suppress redundant errors below. let erased_generic_kind = infcx.tcx.erase_and_anonymize_regions(type_test.generic_kind); + failed_type_tests.push((erased_generic_kind, type_test)); + } + + // An async body can produce both `G: 'static` and `G: 'a` type-test failures at + // the same span, as in `tests/ui/async-await/spurious-static-bound-issue-115376.rs`. + // Reporting the weaker bound adds a redundant diagnostic and suggests a lifetime + // bound that cannot fix the missing `G: 'static` requirement. Keep the `'static` + // error and suppress weaker failures for the same erased generic kind and span. + // This is a diagnostic heuristic, using the same erasure as deduplication below. + // + // Collect all failed `'static` bounds before reporting errors so suppression does + // not depend on the order of the type tests. Compare SCCs because a lower-bound + // region can be equivalent to `'static` without being `fr_static` itself. + let static_scc = self.constraint_sccs.scc(self.universal_regions().fr_static); + let static_bound_errors: FxIndexSet<_> = failed_type_tests + .iter() + .filter_map(|&(erased_generic_kind, type_test)| { + if self.constraint_sccs.scc(type_test.lower_bound) == static_scc { + Some((erased_generic_kind, type_test.span)) + } else { + None + } + }) + .collect(); + + // If `G: 'static` failed at this span, then same-span `G: 'a` failures are weaker. + for (erased_generic_kind, type_test) in failed_type_tests { + if self.constraint_sccs.scc(type_test.lower_bound) != static_scc + && static_bound_errors.contains(&(erased_generic_kind, type_test.span)) + { + continue; + } // Skip duplicate-ish errors. if deduplicate_errors.insert(( diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index d6c25cf524a5c..e06549090226e 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -284,6 +284,7 @@ impl ExtraBackendMethods for AotDriver { &self, tcx: TyCtxt<'_>, cgu_name: Symbol, + _bitcode_needed: bool, ) -> (ModuleCodegen, u64) { let start_time = Instant::now(); diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index cbc7db8e9e23f..2fb5459a20283 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -365,6 +365,7 @@ impl ExtraBackendMethods for GccCodegenBackend { &self, tcx: TyCtxt<'_>, cgu_name: Symbol, + _bitcode_needed: bool, ) -> (ModuleCodegen, u64) { base::compile_codegen_unit( tcx, diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 3d2362be02f27..c22318c0ec8a7 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -10,6 +10,8 @@ use rustc_middle::mir::interpret::{PointerArithmetic, Scalar as ConstScalar}; use rustc_middle::ty::Instance; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, span_bug}; +use rustc_session::Session; +use rustc_session::config::Lto; use rustc_span::{Pos, Span, Symbol, sym}; use rustc_target::asm::*; use rustc_target::spec::HasTargetSpec; @@ -594,30 +596,45 @@ pub(crate) fn inline_asm_call<'ll>( let key = "srcloc"; let kind = bx.get_md_kind_id(key); - // `srcloc` contains one 64-bit integer for each line of assembly code, - // where the lower 32 bits hold the lo byte position and the upper 32 bits - // hold the hi byte position. - let mut srcloc = vec![]; - if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { - // LLVM inserts an extra line to add the ".intel_syntax", so add - // a dummy srcloc entry for it. - // - // Don't do this if we only have 1 line span since that may be - // due to the asm template string coming from a macro. LLVM will - // default to the first srcloc for lines that don't have an - // associated srcloc. - srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); + if allow_raw_span_inline_asm_srcloc(bx.tcx.sess, bx.bitcode_needed) { + // `srcloc` contains one 64-bit integer for each line of assembly code, + // where the lower 32 bits hold the lo byte position and the upper 32 bits + // hold the hi byte position. + let mut srcloc = vec![]; + if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { + // LLVM inserts an extra line to add the ".intel_syntax", so add + // a dummy srcloc entry for it. + // + // Don't do this if we only have 1 line span since that may be + // due to the asm template string coming from a macro. LLVM will + // default to the first srcloc for lines that don't have an + // associated srcloc. + srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); + } + srcloc.extend(line_spans.iter().map(|span| { + llvm::LLVMValueAsMetadata( + bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)), + ) + })); + bx.cx.set_metadata_node(call, kind, &srcloc); } - srcloc.extend(line_spans.iter().map(|span| { - llvm::LLVMValueAsMetadata( - bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)), - ) - })); - bx.cx.set_metadata_node(call, kind, &srcloc); Some(call) } +/// Whenever inline assembly bitcode is built, its `srcloc` contains the raw span numbers +/// as location cookies. This is problematic since that is nondeterministic when using +/// the parallel frontend. Even without parallelism, the cookies are meaningless in another +/// rustc session. +/// +/// Discussion about replacing the cookies with something stable: rust-lang/rust#150451 +fn allow_raw_span_inline_asm_srcloc(sess: &Session, bitcode_needed: bool) -> bool { + // even for Lto::ThinLocal, where the bitcode isn't serialized into files, the changes in + // raw span positions would reflect in the LTO module hashes, which could lead to + // nondeterminism + sess.lto() == Lto::No && !bitcode_needed +} + /// If the register is an xmm/ymm/zmm register then return its index. fn xmm_reg_index(reg: InlineAsmReg) -> Option { use X86InlineAsmReg::*; diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index bbe968e8248ad..5316b7425be47 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -64,6 +64,7 @@ pub(crate) fn iter_global_aliases(llmod: &llvm::Module) -> ValueIter<'_> { pub(crate) fn compile_codegen_unit( tcx: TyCtxt<'_>, cgu_name: Symbol, + bitcode_needed: bool, ) -> (ModuleCodegen, u64) { let start_time = Instant::now(); @@ -71,7 +72,7 @@ pub(crate) fn compile_codegen_unit( let (module, _) = tcx.dep_graph.with_task( dep_node, tcx, - || module_codegen(tcx, cgu_name), + || module_codegen(tcx, cgu_name, bitcode_needed), Some(dep_graph::hash_result), ); let time_to_codegen = start_time.elapsed(); @@ -80,7 +81,11 @@ pub(crate) fn compile_codegen_unit( // the time we needed for codegenning it. let cost = time_to_codegen.as_nanos() as u64; - fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen { + fn module_codegen( + tcx: TyCtxt<'_>, + cgu_name: Symbol, + needs_bitcode: bool, + ) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); let _prof_timer = tcx.prof.generic_activity_with_arg_recorder("codegen_module", |recorder| { @@ -90,7 +95,7 @@ pub(crate) fn compile_codegen_unit( // Instantiate monomorphizations without filling out definitions yet... let llvm_module = ModuleLlvm::new(tcx, cgu_name.as_str()); { - let mut cx = CodegenCx::new(tcx, cgu, &llvm_module); + let mut cx = CodegenCx::new(tcx, cgu, &llvm_module, needs_bitcode); // Declare and store globals shared by all offload kernels // diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index c737fad66e573..08a74774305c6 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -93,6 +93,7 @@ pub(crate) type CodegenCx<'ll, 'tcx> = GenericCx<'ll, FullCx<'ll, 'tcx>>; pub(crate) struct FullCx<'ll, 'tcx> { pub tcx: TyCtxt<'tcx>, + pub bitcode_needed: bool, pub scx: SimpleCx<'ll>, pub use_dll_storage_attrs: bool, pub tls_model: llvm::ThreadLocalMode, @@ -608,6 +609,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { tcx: TyCtxt<'tcx>, codegen_unit: &'tcx CodegenUnit<'tcx>, llvm_module: &'ll crate::ModuleLlvm, + bitcode_needed: bool, ) -> Self { // An interesting part of Windows which MSVC forces our hand on (and // apparently MinGW didn't) is the usage of `dllimport` and `dllexport` @@ -703,6 +705,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { GenericCx( FullCx { tcx, + bitcode_needed, scx: SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size()), use_dll_storage_attrs, tls_model, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 775e1dcf2ffea..ca16d33b90256 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -112,8 +112,9 @@ impl ExtraBackendMethods for LlvmCodegenBackend { &self, tcx: TyCtxt<'_>, cgu_name: Symbol, + bitcode_needed: bool, ) -> (ModuleCodegen, u64) { - base::compile_codegen_unit(tcx, cgu_name) + base::compile_codegen_unit(tcx, cgu_name, bitcode_needed) } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 78cdd3e38f68c..e8b25eb4359d0 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -15,7 +15,6 @@ use rustc_errors::{ Level, MultiSpan, Style, Suggestions, catch_fatal_errors, }; use rustc_fs_util::link_or_copy; -use rustc_hir::find_attr; use rustc_incremental::{copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir_sess}; use rustc_macros::{Decodable, Encodable}; use rustc_metadata::fs::copy_to_stdout; @@ -114,7 +113,7 @@ pub struct ModuleConfig { } impl ModuleConfig { - fn new(kind: ModuleKind, tcx: TyCtxt<'_>, no_builtins: bool) -> ModuleConfig { + pub(crate) fn new(kind: ModuleKind, tcx: TyCtxt<'_>, no_builtins: bool) -> ModuleConfig { // If it's a regular module, use `$regular`, otherwise use `$other`. // `$regular` and `$other` are evaluated lazily. macro_rules! if_regular { @@ -426,15 +425,12 @@ fn need_pre_lto_bitcode_for_incr_comp(sess: &Session) -> bool { pub(crate) fn start_async_codegen( backend: B, tcx: TyCtxt<'_>, + regular_config: Arc, + allocator_config: Arc, allocator_module: Option>, ) -> OngoingCodegen { let (coordinator_send, coordinator_receive) = channel(); - let no_builtins = find_attr!(tcx, crate, NoBuiltins); - - let regular_config = ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins); - let allocator_config = ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins); - let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); let (codegen_worker_send, codegen_worker_receive) = channel(); @@ -444,8 +440,8 @@ pub(crate) fn start_async_codegen( shared_emitter, codegen_worker_send, coordinator_receive, - Arc::new(regular_config), - Arc::new(allocator_config), + regular_config, + allocator_config, allocator_module, coordinator_send.clone(), ); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index c870d1694d068..8dd129f45cc5a 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -42,7 +42,7 @@ use tracing::{debug, info}; use crate::assert_module_sources::CguReuse; use crate::back::link::are_upstream_rust_objects_already_included; use crate::back::write::{ - ComputedLtoType, OngoingCodegen, compute_per_cgu_lto_type, start_async_codegen, + ComputedLtoType, ModuleConfig, OngoingCodegen, compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, }; use crate::common::{self, IntPredicate, RealPredicate, TypeKind}; @@ -52,7 +52,7 @@ use crate::mir::place::PlaceRef; use crate::traits::*; use crate::{ CachedModuleCodegen, CodegenLintLevelSpecs, CrateInfo, EiiLinkageImplInfo, EiiLinkageInfo, - ModuleCodegen, diagnostics, meth, mir, + ModuleCodegen, ModuleKind, diagnostics, meth, mir, }; pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate { @@ -762,7 +762,18 @@ pub fn codegen_crate< None }; - let ongoing_codegen = start_async_codegen(backend.clone(), tcx, allocator_module); + let no_builtins = find_attr!(tcx, crate, NoBuiltins); + let regular_module_config = ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins); + let bitcode_needed = regular_module_config.bitcode_needed(); + let allocator_module_config = ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins); + + let ongoing_codegen = start_async_codegen( + backend.clone(), + tcx, + Arc::new(regular_module_config), + Arc::new(allocator_module_config), + allocator_module, + ); // For better throughput during parallel processing by LLVM, we used to sort // CGUs largest to smallest. This would lead to better thread utilization @@ -822,7 +833,8 @@ pub fn codegen_crate< let start_time = Instant::now(); let pre_compiled_cgus = par_map(cgus, |(i, _)| { - let module = backend.compile_codegen_unit(tcx, codegen_units[i].name()); + let module = + backend.compile_codegen_unit(tcx, codegen_units[i].name(), bitcode_needed); (i, IntoDynSyncSend(module)) }); @@ -846,7 +858,7 @@ pub fn codegen_crate< cgu.0 } else { let start_time = Instant::now(); - let module = backend.compile_codegen_unit(tcx, cgu.name()); + let module = backend.compile_codegen_unit(tcx, cgu.name(), bitcode_needed); total_codegen_time += start_time.elapsed(); module }; diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 11878c1f5165d..2435cca50a0f3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -177,5 +177,6 @@ pub trait ExtraBackendMethods: Send + Sync + DynSend + DynSync { &self, tcx: TyCtxt<'_>, cgu_name: Symbol, + bitcode_needed: bool, ) -> (ModuleCodegen, u64); } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 7c10dd04f39f3..ce4c8497463c8 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -612,6 +612,15 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.write_scalar(Scalar::from_bool(ty.is_signed()), dest)?; } + sym::type_id_points_mutably => { + let ty = ecx.read_type_id(&args[0])?; + let is_mutable = matches!( + ty.kind(), + ty::RawPtr(_, Mutability::Mut) | &ty::Ref(_, _, Mutability::Mut) + ); + ecx.write_scalar(Scalar::from_bool(is_mutable), dest)?; + } + sym::size_of_type_id => { let ty = ecx.read_type_id(&args[0])?; let layout = ecx.layout_of(ty)?; @@ -691,6 +700,33 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ); ecx.write_type_id(frt, dest)?; } + sym::type_id_function_ptr => { + let ty = ecx.read_type_id(&args[0])?; + let variant_index = if let ty::FnPtr(sig, fn_header) = ty.kind() { + let (variant, variant_place) = ecx.project_downcast_named(dest, sym::Some)?; + let field_place = ecx.project_field(&variant_place, FieldIdx::ZERO)?; + let sig = sig.skip_binder(); // FIXME: handle lifetime bounds + ecx.write_fn_ptr_type_info(field_place, &sig, fn_header)?; + variant + } else { + ecx.project_downcast_named(dest, sym::None)?.0 + }; + ecx.write_discriminant(variant_index, dest)?; + } + sym::type_id_points_to => { + let ty = ecx.read_type_id(&args[0])?; + let variant_index = if let ty::RawPtr(pointee_ty, _) | ty::Ref(_, pointee_ty, _) = + ty.kind() + { + let (variant, variant_place) = ecx.project_downcast_named(dest, sym::Some)?; + let field_place = ecx.project_field(&variant_place, FieldIdx::ZERO)?; + ecx.write_type_id(*pointee_ty, &field_place)?; + variant + } else { + ecx.project_downcast_named(dest, sym::None)?.0 + }; + ecx.write_discriminant(variant_index, dest)?; + } sym::type_id_variants => { let ty = ecx.read_type_id(&args[0])?; diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index f6e0208d98835..8d93aee57a518 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -3,7 +3,6 @@ mod adt; use std::borrow::Cow; use rustc_abi::{ExternAbi, FieldIdx}; -use rustc_ast::Mutability; use rustc_hir::attrs::lang_items::LangItem; use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; @@ -134,23 +133,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { self.project_downcast_named(&field_dest, sym::Str)?; variant } - ty::Ref(_, ty, mutability) => { - let (variant, variant_place) = + ty::Ref(_, _, _) => { + let (variant, _) = self.project_downcast_named(&field_dest, sym::Reference)?; - let reference_place = - self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_reference_type_info(reference_place, *ty, *mutability)?; - variant } - ty::RawPtr(ty, mutability) => { - let (variant, variant_place) = + ty::RawPtr(_, _) => { + let (variant, _variant_place) = self.project_downcast_named(&field_dest, sym::Pointer)?; - let pointer_place = - self.project_field(&variant_place, FieldIdx::ZERO)?; - - self.write_pointer_type_info(pointer_place, *ty, *mutability)?; - variant } ty::Dynamic(predicates, region) => { @@ -160,16 +150,9 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?; variant } - ty::FnPtr(sig, fn_header) => { - let (variant, variant_place) = + ty::FnPtr(_, _) => { + let (variant, _) = self.project_downcast_named(&field_dest, sym::FnPtr)?; - let fn_ptr_place = - self.project_field(&variant_place, FieldIdx::ZERO)?; - - // FIXME: handle lifetime bounds - let sig = sig.skip_binder(); - - self.write_fn_ptr_type_info(fn_ptr_place, &sig, fn_header)?; variant } ty::Foreign(_) @@ -301,31 +284,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } - pub(crate) fn write_reference_type_info( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - ty: Ty<'tcx>, - mutability: Mutability, - ) -> InterpResult<'tcx> { - // Iterate over all fields of `type_info::Reference`. - for (field_idx, field) in - place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() - { - let field_place = self.project_field(&place, field_idx)?; - - match field.name { - // Write the `TypeId` of the reference's inner type to the `ty` field. - sym::pointee => self.write_type_id(ty, &field_place)?, - // Write the boolean representing the reference's mutability to the `mutable` field. - sym::mutable => { - self.write_scalar(Scalar::from_bool(mutability.is_mut()), &field_place)? - } - other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), - } - } - interp_ok(()) - } - pub(crate) fn write_type_id_generics( &mut self, place: &impl Writeable<'tcx, CtfeProvenance>, @@ -383,7 +341,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { let field_place = self.project_field(&place, field_idx)?; match field.name { - sym::unsafety => { + sym::is_unsafe => { self.write_scalar(Scalar::from_bool(!fn_sig_kind.is_safe()), &field_place)?; } sym::abi => match fn_sig_kind.abi() { @@ -444,30 +402,4 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } - - pub(crate) fn write_pointer_type_info( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - ty: Ty<'tcx>, - mutability: Mutability, - ) -> InterpResult<'tcx> { - // Iterate over all fields of `type_info::Pointer`. - for (field_idx, field) in - place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() - { - let field_place = self.project_field(&place, field_idx)?; - - match field.name { - // Write the `TypeId` of the pointer's inner type to the `ty` field. - sym::pointee => self.write_type_id(ty, &field_place)?, - // Write the boolean representing the pointer's mutability to the `mutable` field. - sym::mutable => { - self.write_scalar(Scalar::from_bool(mutability.is_mut()), &field_place)? - } - other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), - } - } - - interp_ok(()) - } } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 30d7127ccd8fa..61f72ee4b5de1 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -202,8 +202,11 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::type_id_eq | sym::type_id_field_representing_type | sym::type_id_fields + | sym::type_id_function_ptr | sym::type_id_generics | sym::type_id_is_signed + | sym::type_id_points_mutably + | sym::type_id_points_to | sym::type_id_variants | sym::type_id_vtable | sym::type_name @@ -317,7 +320,20 @@ pub(crate) fn check_intrinsic_type( (0, 0, vec![type_id_ty(), tcx.types.usize, tcx.types.usize], type_id_ty()) } sym::type_id_fields => (0, 0, vec![type_id_ty(), tcx.types.usize], tcx.types.usize), + sym::type_id_function_ptr => { + let fn_ptr = tcx.require_lang_item(LangItem::FnPtr, span); + let fn_ptr_adt_ref = tcx.adt_def(fn_ptr); + let fn_ptr_ty = Ty::new_adt(tcx, fn_ptr_adt_ref, ty::List::empty()); + + let option = tcx.require_lang_item(LangItem::Option, span); + let option_adt_ref = tcx.adt_def(option); + let option_args = tcx.mk_args(&[fn_ptr_ty.into()]); + let option_fn_ptr_ty = Ty::new_adt(tcx, option_adt_ref, option_args); + (0, 0, vec![type_id_ty()], option_fn_ptr_ty) + } sym::type_id_is_signed => (0, 0, vec![type_id_ty()], tcx.types.bool), + sym::type_id_points_mutably => (0, 0, vec![type_id_ty()], tcx.types.bool), + sym::type_id_points_to => (0, 0, vec![type_id_ty()], Ty::new_option(tcx, type_id_ty())), sym::type_id_variants => (0, 0, vec![type_id_ty()], tcx.types.usize), sym::variant_name => (0, 0, vec![type_id_ty(), tcx.types.usize], Ty::new_static_str(tcx)), sym::variant_non_exhaustive => (0, 0, vec![type_id_ty(), tcx.types.usize], tcx.types.bool), diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 13fbb3a2c0c3c..db9dbc1c3f482 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -55,14 +55,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Block { block: ast_block } => { this.ast_block(destination, block, ast_block, source_info) } - ExprKind::Match { scrutinee, ref arms, .. } => this.match_expr( - destination, - block, - scrutinee, - arms, - expr_span, - this.thir[scrutinee].span, - ), + ExprKind::Match { scrutinee, ref arms, .. } => { + this.match_expr(destination, block, scrutinee, arms, expr_span) + } ExprKind::If { cond, then, else_opt, if_then_scope } => { let then_span = this.thir[then].span; let then_source_info = this.source_info(then_span); @@ -303,9 +298,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Logic for `match`. let scrutinee_span = this.thir.exprs[scrutinee].span; - let scrutinee_place_builder = unpack!( - body_block = this.lower_scrutinee(body_block, scrutinee, scrutinee_span) - ); + let scrutinee_place_builder = + unpack!(body_block = this.lower_scrutinee(body_block, scrutinee)); let match_start_span = match_span.shrink_to_lo().to(scrutinee_span); diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index a520acda5e6c8..01505fb9ec8ae 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -339,10 +339,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_id: ExprId, arms: &[ArmId], span: Span, - scrutinee_span: Span, ) -> BlockAnd<()> { - let scrutinee_place = - unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span)); + let scrutinee_span = self.thir[scrutinee_id].span; + let scrutinee_place = unpack!(block = self.lower_scrutinee(block, scrutinee_id)); let match_start_span = span.shrink_to_lo().to(scrutinee_span); let patterns = arms @@ -378,11 +377,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, scrutinee_id: ExprId, - scrutinee_span: Span, ) -> BlockAnd> { let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee_id)); if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { - let source_info = self.source_info(scrutinee_span); + let source_info = self.source_info(self.thir[scrutinee_id].span); self.cfg.push_place_mention(block, source_info, scrutinee_place); } @@ -612,9 +610,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } _ => { - let initializer = &self.thir[initializer_id]; - let place_builder = - unpack!(block = self.lower_scrutinee(block, initializer_id, initializer.span)); + let place_builder = unpack!(block = self.lower_scrutinee(block, initializer_id)); self.place_into_pattern(block, irrefutable_pat, place_builder, true) } } @@ -2334,7 +2330,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { declare_let_bindings: DeclareLetBindings, ) -> BlockAnd<()> { let expr_span = self.thir[expr_id].span; - let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); + let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id)); let built_tree = self.lower_match_tree( block, expr_span, diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 6ffb85d7b90a8..a4d39f09b724d 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -1,5 +1,6 @@ use rustc_hir::attrs::CoverageAttrKind; -use rustc_hir::find_attr; +use rustc_hir::def::DefKind; +use rustc_hir::{self as hir, find_attr}; use rustc_index::bit_set::DenseBitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::{ @@ -30,11 +31,23 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might // be tricky if const expressions have no corresponding statements in the enclosing MIR. // Closures are carved out by their initial `Assign` statement.) - if !tcx.def_kind(def_id).is_fn_like() { + let def_kind = tcx.def_kind(def_id); + if !def_kind.is_fn_like() { trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)"); return false; } + // Comptime functions can't exist at runtime, so instrumenting them is useless. + // This also avoids an ICE when getting the symbol name for an unused-function record + // (due to ). + // We check `def_kind` first to avoid any unexpected panics from merely asking for constness. + if matches!(def_kind, DefKind::Fn | DefKind::AssocFn) + && matches!(tcx.constness(def_id), hir::Constness::Const { always: true }) + { + trace!("InstrumentCoverage skipped for {def_id:?} (comptime)"); + return false; + } + if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NAKED) { trace!("InstrumentCoverage skipped for {def_id:?} (`#[naked]`)"); return false; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7665df4a4e5ae..68d28f9227dbe 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1153,6 +1153,7 @@ symbols! { is, is_auto, is_splatted, + is_unsafe, is_val_statically_known, isa_attribute, isize, @@ -2170,8 +2171,11 @@ symbols! { type_id_eq, type_id_field_representing_type, type_id_fields, + type_id_function_ptr, type_id_generics, type_id_is_signed, + type_id_points_mutably, + type_id_points_to, type_id_variants, type_id_vtable, type_info, @@ -2263,7 +2267,6 @@ symbols! { unsafe_no_drop_flag, unsafe_pinned, unsafe_unpin, - unsafety, unsize, unsized_const_param_ty, unsized_const_params, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index a99633456de0b..f8cc81228b27b 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3101,6 +3101,15 @@ pub fn field_representing_type_name(_frt_type_id: crate::any::TypeId) -> &'stati #[rustc_comptime] pub fn field_representing_type_offset(_frt_type_id: crate::any::TypeId) -> usize; +/// Given a `TypeId` that represents a function pointer returns an [`core::mem::type_info::FnPtr`]. +/// When called on something else this returns `None`. +/// +/// The more user-friendly version of this intrinsic is [`core::any::TypeId::function_ptr`]. +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_comptime] +pub fn type_id_function_ptr(_type_id: crate::any::TypeId) -> Option; + /// Checks whether this type is non-exhaustive. #[rustc_intrinsic] #[unstable(feature = "core_intrinsics", issue = "none")] @@ -3114,6 +3123,26 @@ pub fn non_exhaustive(_id: crate::any::TypeId) -> bool; #[rustc_comptime] pub fn type_id_generics(_id: crate::any::TypeId) -> &'static [crate::mem::type_info::Generic]; +// FIXME(reflection): Pick a consistent naming scheme for the intrinsics. Right now we got +// type_id_, _type_id and intrinsics not mentioning type_id at all. +/// Given a `TypeId` that represents a pointer this returns the `TypeId` which that pointer +/// points to. When called on anything else this returns None. +/// +/// The more user-friendly version of this intrinsic is [`core::any::TypeId::points_to`]. +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_comptime] +pub fn type_id_points_to(_id: crate::any::TypeId) -> Option; + +/// Given a `TypeId` that represents a pointer returns whether that pointer is mutable. +/// When called on anything else this returns `false`. +/// +/// The more user-friendly version of this intrinsic is [`core::any::TypeId::points_mutably`]. +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_comptime] +pub fn type_id_points_mutably(_id: crate::any::TypeId) -> bool; + /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// /// This is used to implement functions like `slice::from_raw_parts_mut` and diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 111664775ca8d..1f38339a7421b 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -100,12 +100,14 @@ pub enum TypeKind { /// String slice type. Str(Str), /// References. - Reference(Reference), + Reference, /// Pointers. - Pointer(Pointer), + Pointer, /// Function pointers. - FnPtr(FnPtr), + FnPtr, /// FIXME(#146922): add all the common types + /// non exhaustive list: + /// - Never Other, } @@ -207,65 +209,55 @@ pub struct Str { // No additional information to provide for now. } -/// Compile-time type information about references. -#[derive(Debug)] -#[non_exhaustive] -#[unstable(feature = "type_info", issue = "146922")] -pub struct Reference { - /// The type of the value being referred to. - pub pointee: TypeId, - /// Whether this reference is mutable or not. - pub mutable: bool, -} - -/// Compile-time type information about pointers. -#[derive(Debug)] -#[non_exhaustive] -#[unstable(feature = "type_info", issue = "146922")] -pub struct Pointer { - /// The type of the value being pointed to. - pub pointee: TypeId, - /// Whether this pointer is mutable or not. - pub mutable: bool, -} - #[derive(Debug)] +#[lang = "FnPtr"] #[unstable(feature = "type_info", issue = "146922")] /// Function pointer, e.g. fn(u8), pub struct FnPtr { - /// Unsafety, true is unsafe - pub unsafety: bool, - - /// Abi, e.g. extern "C" - pub abi: Abi, - - /// Function inputs - pub inputs: &'static [TypeId], - - /// Function return type, default is TypeId::of::<()> - pub output: TypeId, - - /// Vardiadic function, e.g. extern "C" fn add(n: usize, mut args: ...); - pub variadic: bool, - + is_unsafe: bool, + abi: Abi, + inputs: &'static [TypeId], + output: TypeId, + variadic: bool, // FIXME(splat): should these fields be private, or merged into an Option? /// Is any function argument splatted? - pub is_splatted: bool, + is_splatted: bool, - /// The index of the splatted function argument in `inputs`, only valid if `is_splatted` is true. - /// e.g. in `fn overload(a: u8, #[rustc_splat] b: (f32, usize))` the index is 1, and it can be called - /// as `overload(a, 1.0, 2)`. - pub splatted_index: u8, + splatted_index: u8, } impl FnPtr { /// Returns the splatted function argument index, or `None` if no argument is splatted. + /// + /// e.g. in `fn overload(a: u8, #[rustc_splat] b: (f32, usize))` the index is 1, + /// and it can be called as `overload(a, 1.0, 2)`. pub const fn splatted(&self) -> Option { if self.is_splatted { Some(self.splatted_index) } else { None } } + /// Whether this function is variadic, e.g. extern "C" fn add(n: usize, mut args: ...); + pub const fn is_variadic(&self) -> bool { + self.variadic + } + /// whether this refers to an unsafe function. + pub const fn is_unsafe(&self) -> bool { + self.is_unsafe + } + /// Returns the application binary interface. For example extern "C". + pub const fn abi(&self) -> Abi { + self.abi + } + /// The types of the functions parameters + pub const fn inputs(&self) -> &'static [TypeId] { + self.inputs + } + /// List of the types returned by the function. For a function with no output + /// specified this returns `TypeId::of<()>`. + pub const fn output(&self) -> TypeId { + self.output + } } -#[derive(Debug, Default)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] #[non_exhaustive] #[unstable(feature = "type_info", issue = "146922")] /// Abi of [FnPtr] @@ -567,6 +559,86 @@ impl TypeId { pub fn generics(self) -> &'static [Generic] { intrinsics::type_id_generics(self) } + + /// Given a `TypeId` that represents a pointer this returns the `TypeId` + /// which that pointer points to. When called on anything else this returns + /// None. + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::TypeId; + /// + /// assert_eq!( + /// const { TypeId::of::<&i32>().points_to() }, + /// const { Some(TypeId::of::()) }, + /// ); + /// + /// assert_eq!( + /// const { TypeId::of::<*const i32>().points_to() }, + /// const { Some(TypeId::of::()) }, + /// ); + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + #[rustc_comptime] + pub fn points_to(self) -> Option { + intrinsics::type_id_points_to(self) + } + + /// Given a `TypeId` that represents a pointer returns whether that pointer is mutable. + /// When called on anything else this returns `false`. + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::TypeId; + /// + /// assert!(const { TypeId::of::<&mut i32>().points_mutably() }); + /// assert!(const { !TypeId::of::<&i32>().points_mutably() }); + /// + /// assert!(!const { TypeId::of::<*const i32>().points_mutably() }); + /// assert!(const { TypeId::of::<*mut i32>().points_mutably() }); + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + #[rustc_comptime] + pub fn points_mutably(self) -> bool { + intrinsics::type_id_points_mutably(self) + } + + /// Given a `TypeId` that represents a function pointer returns an + /// [`FnPtr`]. When called on something else this returns `None`. + /// ``` + /// #![feature(type_info)] + /// use std::any::TypeId; + /// use std::mem::type_info::{Abi, FnPtr}; + /// + /// const F: FnPtr = TypeId::of:: usize>() + /// .function_ptr() + /// .expect("TypeId of a function ptr"); + /// + /// assert!(F.inputs() == [TypeId::of::(), TypeId::of::()]); + /// assert!(F.output() == TypeId::of::()); + /// assert!(F.abi() == Abi::default()); + /// ``` + /// ``` + /// #![feature(type_info)] + /// # use std::any::TypeId; + /// # use std::mem::type_info::{Abi, FnPtr}; + /// # + /// const F: FnPtr = TypeId::of::() + /// .function_ptr() + /// .expect("TypeId of a function ptr"); + /// + /// assert!(F.inputs() == []); + /// assert!(F.output() == TypeId::of::<()>()); + /// assert!(F.abi() == Abi::default()); + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + #[rustc_comptime] + pub fn function_ptr(self) -> Option { + intrinsics::type_id_function_ptr(self) + } } /// Variant representing type ID. Representing a variant of an enum. diff --git a/library/coretests/tests/mem/fn_ptr.rs b/library/coretests/tests/mem/fn_ptr.rs index 192054bcaf66b..862048e4090d4 100644 --- a/library/coretests/tests/mem/fn_ptr.rs +++ b/library/coretests/tests/mem/fn_ptr.rs @@ -3,233 +3,101 @@ use std::mem::type_info::{Abi, FnPtr, Type, TypeKind}; const STRING_TY: TypeId = const { TypeId::of::() }; const U8_TY: TypeId = const { TypeId::of::() }; -const _U8_REF_TY: TypeId = const { TypeId::of::<&u8>() }; const UNIT_TY: TypeId = const { TypeId::of::<()>() }; const TUPLE_STRING_U8_TY: TypeId = const { TypeId::of::<(String, u8)>() }; #[test] fn test_fn_ptrs() { - let TypeKind::FnPtr(FnPtr { - unsafety: false, - abi: Abi::ExternRust, - inputs: &[], - output, - variadic: false, - is_splatted: false, - splatted_index: _, - }) = (const { Type::of::().kind }) - else { - panic!(); - }; - assert_eq!(output, UNIT_TY); + let f = const { TypeId::of::().function_ptr().unwrap() }; + assert_eq!(f.is_unsafe(), false); + assert_eq!(f.abi(), Abi::ExternRust); + assert_eq!(f.inputs(), &[]); + assert_eq!(f.output(), UNIT_TY); + assert_eq!(f.is_variadic(), false); + assert_eq!(f.splatted(), None); } + +#[test] +fn test_typekind() { + assert!(matches!(const { Type::of::().kind }, TypeKind::FnPtr)); + assert!(matches!(const { Type::of::().kind }, TypeKind::FnPtr)); + assert!(matches!(const { Type::of::().kind }, TypeKind::FnPtr)); + assert!(matches!(const { Type::of::().kind }, TypeKind::FnPtr)); + assert!(matches!( + const { Type::of::().kind }, + TypeKind::FnPtr + )); +} + #[test] fn test_ref() { - const { - // references are tricky because the lifetimes give the references different type ids - // so we check the pointees instead - let TypeKind::FnPtr(FnPtr { - unsafety: false, - abi: Abi::ExternRust, - inputs: &[ty1, ty2], - output, - variadic: false, - is_splatted: false, - splatted_index: _, - }) = (const { Type::of::().kind }) - else { - panic!(); - }; - if output != UNIT_TY { - panic!(); - } - let TypeKind::Reference(reference) = ty1.info().kind else { - panic!(); - }; - if reference.pointee != U8_TY { - panic!(); - } - let TypeKind::Reference(reference) = ty2.info().kind else { - panic!(); - }; - if reference.pointee != U8_TY { - panic!(); - } - } + // references are tricky because the lifetimes give the references different type ids + // so we check the pointees instead + const F: FnPtr = TypeId::of::().function_ptr().unwrap(); + assert_eq!(const { F.inputs()[0].points_to() }, Some(U8_TY)); + assert_eq!(const { F.inputs()[1].points_to() }, Some(U8_TY)); } #[test] fn test_unsafe() { - let TypeKind::FnPtr(FnPtr { - unsafety: true, - abi: Abi::ExternRust, - inputs: &[], - output, - variadic: false, - is_splatted: false, - splatted_index: _, - }) = (const { Type::of::().kind }) - else { - panic!(); - }; - assert_eq!(output, UNIT_TY); + assert_eq!(const { TypeId::of::().function_ptr() }.unwrap().is_unsafe(), true); } + #[test] fn test_abi() { - let TypeKind::FnPtr(FnPtr { - unsafety: false, - abi: Abi::ExternRust, - inputs: &[], - output, - variadic: false, - is_splatted: false, - splatted_index: _, - }) = (const { Type::of::().kind }) - else { - panic!(); - }; - assert_eq!(output, UNIT_TY); + assert_eq!( + const { TypeId::of::().function_ptr() }.unwrap().abi(), + Abi::ExternRust + ); - let TypeKind::FnPtr(FnPtr { - unsafety: false, - abi: Abi::ExternC, - inputs: &[], - output, - variadic: false, - is_splatted: false, - splatted_index: _, - }) = (const { Type::of::().kind }) - else { - panic!(); - }; - assert_eq!(output, UNIT_TY); + assert_eq!( + const { TypeId::of::().function_ptr() }.unwrap().abi(), + Abi::ExternC + ); - let TypeKind::FnPtr(FnPtr { - unsafety: true, - abi: Abi::Named("system"), - inputs: &[], - output, - variadic: false, - is_splatted: false, - splatted_index: _, - }) = (const { Type::of::().kind }) - else { - panic!(); - }; - assert_eq!(output, UNIT_TY); + assert_eq!( + const { TypeId::of::().function_ptr() }.unwrap().abi(), + Abi::Named("system") + ); } #[test] fn test_inputs() { - let TypeKind::FnPtr(FnPtr { - unsafety: false, - abi: Abi::ExternRust, - inputs: &[ty1, ty2], - output, - variadic: false, - is_splatted: false, - splatted_index: _, - }) = (const { Type::of::().kind }) - else { - panic!(); - }; - assert_eq!(output, UNIT_TY); - assert_eq!(ty1, STRING_TY); - assert_eq!(ty2, U8_TY); + assert_eq!( + const { TypeId::of::().function_ptr() }.unwrap().inputs(), + [STRING_TY, U8_TY] + ); - let TypeKind::FnPtr(FnPtr { - unsafety: false, - abi: Abi::ExternRust, - inputs: &[ty1, ty2], - output, - variadic: false, - is_splatted: false, - splatted_index: _, - }) = (const { Type::of::().kind }) - else { - panic!(); - }; - assert_eq!(output, UNIT_TY); - assert_eq!(ty1, STRING_TY); - assert_eq!(ty2, U8_TY); + assert_eq!( + const { TypeId::of::().function_ptr() }.unwrap().inputs(), + [STRING_TY, U8_TY] + ); } #[test] fn test_output() { - let TypeKind::FnPtr(FnPtr { - unsafety: false, - abi: Abi::ExternRust, - inputs: &[], - output, - variadic: false, - is_splatted: false, - splatted_index: _, - }) = (const { Type::of:: u8>().kind }) - else { - panic!(); - }; - assert_eq!(output, U8_TY); + let f = const { TypeId::of:: u8>().function_ptr() }.unwrap(); + assert_eq!(f.output(), U8_TY); } #[test] fn test_variadic() { - let TypeKind::FnPtr(FnPtr { - unsafety: false, - abi: Abi::ExternC, - inputs: [ty1], - output, - variadic: true, - is_splatted: false, - splatted_index: _, - }) = &(const { Type::of::().kind }) - else { - panic!(); - }; - assert_eq!(output, &UNIT_TY); - assert_eq!(*ty1, U8_TY); + let f = const { TypeId::of::().function_ptr() }.unwrap(); + assert_eq!(f.abi(), Abi::ExternC); + assert_eq!(f.inputs(), [U8_TY]); + assert_eq!(f.is_variadic(), true); } #[test] fn test_splat() { - #[rustfmt::skip] - let TypeKind::FnPtr(fn_ptr_ty) = &(const { Type::of::().kind }) else { - panic!(); - }; - let FnPtr { - unsafety: false, - abi: Abi::ExternRust, - inputs: [ty1], - output, - variadic: false, - is_splatted: true, - splatted_index: 0, - } = fn_ptr_ty - else { - panic!(); - }; - assert_eq!(output, &UNIT_TY); - assert_eq!(*ty1, TUPLE_STRING_U8_TY); - assert_eq!(fn_ptr_ty.splatted(), Some(0)); + let f = const { TypeId::of::().function_ptr() }.unwrap(); + assert_eq!(f.inputs(), [TUPLE_STRING_U8_TY]); + assert_eq!(f.splatted(), Some(0)); } #[test] fn test_not_splat() { - let TypeKind::FnPtr(fn_ptr_ty) = &(const { Type::of::().kind }) else { - panic!(); - }; - let FnPtr { - unsafety: false, - abi: Abi::ExternRust, - inputs: [ty1], - output, - variadic: false, - is_splatted: false, - splatted_index: _, - } = fn_ptr_ty - else { - panic!(); - }; - assert_eq!(output, &UNIT_TY); - assert_eq!(*ty1, TUPLE_STRING_U8_TY); - assert_eq!(fn_ptr_ty.splatted(), None); + let f = const { TypeId::of::().function_ptr() }.unwrap(); + assert_eq!(f.inputs(), [TUPLE_STRING_U8_TY]); + assert_eq!(f.splatted(), None); } diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index f3a69dd857aba..7fe592496f1a7 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -271,61 +271,59 @@ fn test_primitives() { #[test] fn test_references() { + use TypeKind::Reference; + // Immutable reference. - match const { Type::of::<&u8>() }.kind { - TypeKind::Reference(reference) => { - assert_eq!(reference.pointee, TypeId::of::()); - assert!(!reference.mutable); - } - _ => unreachable!(), + let Type { kind: Reference, .. } = Type::of::<&u8>() else { panic!() }; + const { + let ty = TypeId::of::<&u8>(); + assert!(ty.points_to() == Some(TypeId::of::())); + assert!(!ty.points_mutably()); } // Mutable references. - match const { Type::of::<&mut u64>() }.kind { - TypeKind::Reference(reference) => { - assert_eq!(reference.pointee, TypeId::of::()); - assert!(reference.mutable); - } - _ => unreachable!(), + let Type { kind: Reference, .. } = Type::of::<&mut u64>() else { panic!() }; + const { + let ty = TypeId::of::<&mut u64>(); + assert!(ty.points_to() == Some(TypeId::of::())); + assert!(ty.points_mutably()); } // Wide references. - match const { Type::of::<&dyn Any>() }.kind { - TypeKind::Reference(reference) => { - assert_eq!(reference.pointee, TypeId::of::()); - assert!(!reference.mutable); - } - _ => unreachable!(), + let Type { kind: Reference, .. } = Type::of::<&dyn Any>() else { panic!() }; + const { + let ty = TypeId::of::<&dyn Any>(); + assert!(ty.points_to() == Some(TypeId::of::())); + assert!(!ty.points_mutably()); } } #[test] fn test_pointers() { + use TypeKind::Pointer; + // Immutable pointer. - match const { Type::of::<*const u8>() }.kind { - TypeKind::Pointer(pointer) => { - assert_eq!(pointer.pointee, TypeId::of::()); - assert!(!pointer.mutable); - } - _ => unreachable!(), + let Type { kind: Pointer, .. } = Type::of::<*const u8>() else { panic!() }; + const { + let ty = TypeId::of::<*const u8>(); + assert!(ty.points_to() == Some(TypeId::of::())); + assert!(!ty.points_mutably()); } // Mutable pointer. - match const { Type::of::<*mut u64>() }.kind { - TypeKind::Pointer(pointer) => { - assert_eq!(pointer.pointee, TypeId::of::()); - assert!(pointer.mutable); - } - _ => unreachable!(), + let Type { kind: Pointer, .. } = Type::of::<*mut u64>() else { panic!() }; + const { + let ty = TypeId::of::<*mut u64>(); + assert!(ty.points_to() == Some(TypeId::of::())); + assert!(ty.points_mutably()); } // Wide pointer. - match const { Type::of::<*const dyn Any>() }.kind { - TypeKind::Pointer(pointer) => { - assert_eq!(pointer.pointee, TypeId::of::()); - assert!(!pointer.mutable); - } - _ => unreachable!(), + let Type { kind: Pointer, .. } = Type::of::<*const dyn Any>() else { panic!() }; + const { + let ty = TypeId::of::<*const dyn Any>(); + assert!(ty.points_to() == Some(TypeId::of::())); + assert!(!ty.points_mutably()); } } diff --git a/library/std/src/thread/join_handle.rs b/library/std/src/thread/join_handle.rs index 93dcc634d2dfa..955fd524e736b 100644 --- a/library/std/src/thread/join_handle.rs +++ b/library/std/src/thread/join_handle.rs @@ -104,7 +104,7 @@ impl JoinHandle { /// Otherwise, it fully waits for the thread to finish, including all destructors /// for thread-local variables that might be running after the main function of the thread. /// - /// In terms of [atomic memory orderings], the completion of the associated + /// In terms of [atomic memory orderings], the completion of the associated /// thread synchronizes with this function returning. In other words, all /// operations performed by that thread [happen /// before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses) all diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 288e147a26615..754f4a547bd74 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -1018,9 +1018,9 @@ impl Builder<'_> { // Avoid doing this during dry run as that usually means the relevant // compiler is not yet linked/copied properly. // - // Only clear out the directory if we're compiling std; otherwise, we + // Only clear out the directory if we're running Cargo on std; otherwise, we // should let Cargo take care of things for us (via depdep info) - if !self.config.dry_run() && mode == Mode::Std && cmd_kind == Kind::Build { + if !self.config.dry_run() && mode == Mode::Std { build_stamp::clear_if_dirty(self, &out_dir, &self.rustc(compiler)); } diff --git a/src/bootstrap/src/utils/build_stamp.rs b/src/bootstrap/src/utils/build_stamp.rs index 36a3d0772e5ad..f70c92667a5cf 100644 --- a/src/bootstrap/src/utils/build_stamp.rs +++ b/src/bootstrap/src/utils/build_stamp.rs @@ -114,7 +114,13 @@ pub fn clear_if_dirty(builder: &Builder<'_>, dir: &Path, input: &Path) -> bool { let stamp = BuildStamp::new(dir); let mut cleared = false; if mtime(stamp.path()) < mtime(input) { - builder.do_if_verbose(|| println!("Dirty - {}", dir.display())); + builder.do_if_verbose(|| { + println!( + "Removing dirty directory `{}` because `{}` changed", + dir.display(), + input.display(), + ) + }); let _ = fs::remove_dir_all(dir); cleared = true; } else if stamp.path().exists() { diff --git a/tests/coverage/comptime.cov-map b/tests/coverage/comptime.cov-map new file mode 100644 index 0000000000000..30f91da050f6f --- /dev/null +++ b/tests/coverage/comptime.cov-map @@ -0,0 +1,10 @@ +Function name: comptime::main +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 01, 00, 0a, 01, 00, 0c, 00, 0d] +Number of files: 1 +- file 0 => $DIR/comptime.rs +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) +Highest counter ID seen: c0 + diff --git a/tests/coverage/comptime.coverage b/tests/coverage/comptime.coverage new file mode 100644 index 0000000000000..1ff44169babb2 --- /dev/null +++ b/tests/coverage/comptime.coverage @@ -0,0 +1,12 @@ + LL| |#![feature(rustc_attrs)] + LL| |//@ edition: 2024 + LL| | + LL| |// Check that instrumenting a crate with a comptime function doesn't ICE. + LL| |// (The function itself doesn't need to be instrumented, and probably shouldn't be.) + LL| |// Regression test for . + LL| | + LL| |#[rustc_comptime] + LL| |fn comptime_fn() {} + LL| | + LL| 1|fn main() {} + diff --git a/tests/coverage/comptime.rs b/tests/coverage/comptime.rs new file mode 100644 index 0000000000000..4891051b0076d --- /dev/null +++ b/tests/coverage/comptime.rs @@ -0,0 +1,11 @@ +#![feature(rustc_attrs)] +//@ edition: 2024 + +// Check that instrumenting a crate with a comptime function doesn't ICE. +// (The function itself doesn't need to be instrumented, and probably shouldn't be.) +// Regression test for . + +#[rustc_comptime] +fn comptime_fn() {} + +fn main() {} diff --git a/tests/run-make/parallel-reproducible-inline-asm-cookie/inline-asm-cookie-issue-150451.rs b/tests/run-make/parallel-reproducible-inline-asm-cookie/inline-asm-cookie-issue-150451.rs new file mode 100644 index 0000000000000..be49be470091e --- /dev/null +++ b/tests/run-make/parallel-reproducible-inline-asm-cookie/inline-asm-cookie-issue-150451.rs @@ -0,0 +1,9 @@ +use std::thread; + +fn _main() { + let _t1 = thread::spawn(|| { + for _ in 0..100 { + println!("test"); + } + }); +} diff --git a/tests/run-make/parallel-reproducible-inline-asm-cookie/rmake.rs b/tests/run-make/parallel-reproducible-inline-asm-cookie/rmake.rs new file mode 100644 index 0000000000000..62ad5a46af860 --- /dev/null +++ b/tests/run-make/parallel-reproducible-inline-asm-cookie/rmake.rs @@ -0,0 +1,42 @@ +//@ needs-target-std +//@ ignore-cross-compile +//@ ignore-windows-gnu +// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) + +use std::rc::Rc; + +use run_make_support::{bin_name, is_windows_msvc, rfs, run_in_tmpdir, rustc}; + +/// Test that parallel compiler produces identical binaries. +fn main() { + const FILE_NAME: &str = "inline-asm-cookie-issue-150451"; + let bin_name = bin_name(FILE_NAME); + + let mut reference = None; + + for _ in 0..10 { + // Tmp dir as previous runs affect output binary on windows. + run_in_tmpdir(|| { + let mut rustc = rustc(); + rustc + .input(format!("{FILE_NAME}.rs")) + .arg("--crate-type=lib") + .arg("-Zthreads=3") + .arg("-Clink-dead-code=true") + .arg("-Copt-level=0") + .arg("-Cembed-bitcode=true") + .output(&bin_name); + + if is_windows_msvc() { + rustc.arg("-Clink-arg=/Brepro"); + } + + rustc.run(); + + let current = Rc::new(rfs::read(&bin_name)); + reference.get_or_insert(Rc::clone(¤t)); + + assert_eq!(Some(current), reference); + }); + } +} diff --git a/tests/ui/asm/aarch64/srcloc.rs b/tests/ui/asm/aarch64/srcloc.rs index 91a2ef3514aee..b5e77c4023970 100644 --- a/tests/ui/asm/aarch64/srcloc.rs +++ b/tests/ui/asm/aarch64/srcloc.rs @@ -1,7 +1,7 @@ //@ add-minicore //@ build-fail //@ needs-asm-support -//@ compile-flags: --target aarch64-unknown-linux-gnu -Ccodegen-units=1 +//@ compile-flags: --target aarch64-unknown-linux-gnu -Ccodegen-units=1 -Cembed-bitcode=false -Clto=no //@ needs-llvm-components: aarch64 //@ ignore-backends: gcc #![crate_type = "lib"] diff --git a/tests/ui/asm/inline-syntax.arm.stderr b/tests/ui/asm/inline-syntax.arm.stderr index 5b193d26c8776..315f97bb09de9 100644 --- a/tests/ui/asm/inline-syntax.arm.stderr +++ b/tests/ui/asm/inline-syntax.arm.stderr @@ -6,15 +6,6 @@ note: instantiated into assembly here LL | .intel_syntax noprefix | ^ -error: unknown directive - | -note: instantiated into assembly here - --> :1:1 - | -LL | .intel_syntax noprefix - | ^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: unknown directive --> $DIR/inline-syntax.rs:21:15 | @@ -87,5 +78,5 @@ note: instantiated into assembly here LL | .intel_syntax noprefix | ^ -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs index 63395c1096c09..d7c9fc8972cb7 100644 --- a/tests/ui/asm/inline-syntax.rs +++ b/tests/ui/asm/inline-syntax.rs @@ -1,9 +1,9 @@ //@ add-minicore //@ revisions: x86_64 arm -//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -Cembed-bitcode=false -Clto=no //@[x86_64] check-pass //@[x86_64] needs-llvm-components: x86 -//@[arm] compile-flags: --target armv7-unknown-linux-gnueabihf +//@[arm] compile-flags: --target armv7-unknown-linux-gnueabihf -Cembed-bitcode=false -Clto=no //@[arm] build-fail //@[arm] needs-llvm-components: arm //@[arm] min-llvm-version: 23 @@ -49,4 +49,3 @@ global_asm!(".intel_syntax noprefix", "nop"); // Global assembly errors don't have line numbers, so no error on ARM. //[arm]~? ERROR unknown directive -//[arm]~? ERROR unknown directive diff --git a/tests/ui/asm/riscv/riscv32e-registers.rs b/tests/ui/asm/riscv/riscv32e-registers.rs index a5f4151b2c80a..77a2d92c3736b 100644 --- a/tests/ui/asm/riscv/riscv32e-registers.rs +++ b/tests/ui/asm/riscv/riscv32e-registers.rs @@ -4,7 +4,7 @@ //@ build-fail //@ revisions: riscv32e_llvm23 riscv32em_llvm23 riscv32emc_llvm23 //@ revisions: riscv32e_llvm24 riscv32em_llvm24 riscv32emc_llvm24 -//@ compile-flags: --crate-type=rlib +//@ compile-flags: --crate-type=rlib -Cembed-bitcode=false -Clto=no //@ [riscv32e_llvm23] needs-llvm-components: riscv //@ [riscv32e_llvm23] compile-flags: --target=riscv32e-unknown-none-elf //@ [riscv32e_llvm23] max-llvm-major-version: 23 diff --git a/tests/ui/asm/x86_64/srcloc.rs b/tests/ui/asm/x86_64/srcloc.rs index e73854acf1522..9bbd20340e3ab 100644 --- a/tests/ui/asm/x86_64/srcloc.rs +++ b/tests/ui/asm/x86_64/srcloc.rs @@ -1,6 +1,6 @@ //@ add-minicore //@ build-fail -//@ compile-flags: --target x86_64-unknown-linux-gnu -Ccodegen-units=1 +//@ compile-flags: --target x86_64-unknown-linux-gnu -Ccodegen-units=1 -Cembed-bitcode=false -Clto=no //@ needs-llvm-components: x86 //@ ignore-backends: gcc #![crate_type = "lib"] diff --git a/tests/ui/async-await/spurious-static-bound-issue-115376.rs b/tests/ui/async-await/spurious-static-bound-issue-115376.rs new file mode 100644 index 0000000000000..42cd388ab7eec --- /dev/null +++ b/tests/ui/async-await/spurious-static-bound-issue-115376.rs @@ -0,0 +1,8 @@ +//@ edition: 2021 + +async fn test(_: &u8) { + let _: &'static T; + //~^ ERROR the parameter type `T` may not live long enough +} + +fn main() {} diff --git a/tests/ui/async-await/spurious-static-bound-issue-115376.stderr b/tests/ui/async-await/spurious-static-bound-issue-115376.stderr new file mode 100644 index 0000000000000..6292823029de1 --- /dev/null +++ b/tests/ui/async-await/spurious-static-bound-issue-115376.stderr @@ -0,0 +1,17 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/spurious-static-bound-issue-115376.rs:4:12 + | +LL | let _: &'static T; + | ^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | async fn test(_: &u8) { + | +++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs index 4fdf5470feac6..0edabe009acdb 100644 --- a/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs +++ b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs @@ -14,7 +14,6 @@ impl Foo { //~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box` may not live long enough //~| ERROR the parameter type `I` may not live long enough //~| ERROR the parameter type `I` may not live long enough - //~| ERROR the parameter type `I` may not live long enough //~| ERROR `f` does not live long enough } } diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr index df86ce79f09c7..cbeb8fba8d226 100644 --- a/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr +++ b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr @@ -84,19 +84,6 @@ help: consider adding an explicit lifetime bound LL | pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box) { | +++++++++ -error[E0311]: the parameter type `I` may not live long enough - --> $DIR/unconstrained-closure-lifetime-generic.rs:10:35 - | -LL | pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box) { - | --------- the parameter type `I` must be valid for the anonymous lifetime defined here... -LL | self.bar = Box::new(|baz| Box::new(f(baz))); - | ^^^^^^^^^^^^^^^^ ...so that the type `I` will meet its required lifetime bounds - | -help: consider adding an explicit lifetime bound - | -LL | pub fn ack<'a, I: 'a>(&'a mut self, f: impl for<'a> Fn(&'a usize) -> Box) { - | +++ ++++ ++ - error[E0597]: `f` does not live long enough --> $DIR/unconstrained-closure-lifetime-generic.rs:10:44 | @@ -113,7 +100,7 @@ LL | } | = note: due to object lifetime defaults, `Box Fn(&'a usize) -> Box<(dyn Any + 'a)>>` actually means `Box<(dyn for<'a> Fn(&'a usize) -> Box<(dyn Any + 'a)> + 'static)>` -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0310, E0311, E0597. +Some errors have detailed explanations: E0310, E0597. For more information about an error, try `rustc --explain E0310`. diff --git a/tests/ui/consts/const-eval/do_not_const_check.rs b/tests/ui/consts/const-eval/do_not_const_check.rs new file mode 100644 index 0000000000000..ced2557bffd19 --- /dev/null +++ b/tests/ui/consts/const-eval/do_not_const_check.rs @@ -0,0 +1,25 @@ +//! Ensure that we refuse to run a do_not_const_check function, even if the body *would* const-check +//! at the moment. +#![feature(rustc_attrs, intrinsics)] + +#[rustc_do_not_const_check] +const fn mostly_harmless() {} + +const _: () = { + mostly_harmless(); //~ERROR: calling non-const function +}; + +// Also ensure the same happens with intrinsics. +// Here we need some intrinsic that the interpreter does *not* have a native implementation for. +// Let's hope nobody adds one... +#[rustc_intrinsic] +#[rustc_do_not_const_check] +pub const fn integer_min(a: T, b: T) -> T { + a +} + +const _: () = { + integer_min(0, 1); //~ERROR: calling non-const function +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/do_not_const_check.stderr b/tests/ui/consts/const-eval/do_not_const_check.stderr new file mode 100644 index 0000000000000..507999df218d1 --- /dev/null +++ b/tests/ui/consts/const-eval/do_not_const_check.stderr @@ -0,0 +1,15 @@ +error[E0080]: calling non-const function `mostly_harmless` + --> $DIR/do_not_const_check.rs:9:5 + | +LL | mostly_harmless(); + | ^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + +error[E0080]: calling non-const function `integer_min::` + --> $DIR/do_not_const_check.rs:22:5 + | +LL | integer_min(0, 1); + | ^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`.