diff options
| author | bors <bors@rust-lang.org> | 2024-03-14 16:36:02 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-03-14 16:36:02 +0000 |
| commit | 30f74ff0dc4d66debc8b50724c446f817e5f75f4 (patch) | |
| tree | 349f7ff26a76c5f4e827022d1f21ca6f1046d336 /compiler | |
| parent | fe6157522848604562f83084154274c545fe3a27 (diff) | |
| parent | 02b1a91ee8fe485ab3b77100d4252094fca9b7b2 (diff) | |
Auto merge of #122497 - matthiaskrgr:rollup-pg9ux4r, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - #119029 (Avoid closing invalid handles) - #122238 (Document some builtin impls in the next solver) - #122247 (rustdoc-search: depth limit `T<U>` -> `U` unboxing) - #122287 (add test ensuring simd codegen checks don't run when a static assertion failed) - #122368 (chore: remove repetitive words) - #122397 (Various cleanups around the const eval query providers) - #122406 (Fix WF for `AsyncFnKindHelper` in new trait solver) - #122477 (Change some attribute to only_local) - #122482 (Ungate the `UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES` lint) - #122490 (Update build instructions for OpenHarmony) Failed merges: - #122471 (preserve span when evaluating mir::ConstOperand) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
20 files changed, 224 insertions, 175 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 18c5960ffc6..cec479218b7 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -71,7 +71,7 @@ pub(crate) fn eval_mir_constant<'tcx>( // This cannot fail because we checked all required_consts in advance. let val = cv .eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span)) - .expect("erroneous constant not captured by required_consts"); + .expect("erroneous constant missed by mono item collection"); (val, cv.ty()) } diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index d532bd90426..ff899c50b3d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -21,11 +21,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } pub fn eval_mir_constant(&self, constant: &mir::ConstOperand<'tcx>) -> mir::ConstValue<'tcx> { - // `MirUsedCollector` visited all constants before codegen began, so if we got here there - // can be no more constants that fail to evaluate. + // `MirUsedCollector` visited all required_consts before codegen began, so if we got here + // there can be no more constants that fail to evaluate. self.monomorphize(constant.const_) .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span)) - .expect("erroneous constant not captured by required_consts") + .expect("erroneous constant missed by mono item collection") } /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index bac10f31336..cd6afd2dbbf 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -211,7 +211,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // It may seem like we should iterate over `required_consts` to ensure they all successfully // evaluate; however, the `MirUsedCollector` already did that during the collection phase of - // monomorphization so we don't have to do it again. + // monomorphization, and if there is an error during collection then codegen never starts -- so + // we don't have to do it again. fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx); diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index f3af633b4e5..0046190d20c 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -374,12 +374,6 @@ const_eval_unallowed_op_in_const_context = const_eval_unavailable_target_features_for_fn = calling a function that requires unavailable target features: {$unavailable_feats} -const_eval_undefined_behavior = - it is undefined behavior to use this value - -const_eval_undefined_behavior_note = - The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - const_eval_uninhabited_enum_variant_read = read discriminant of an uninhabited enum variant const_eval_uninhabited_enum_variant_written = @@ -434,6 +428,12 @@ const_eval_validation_expected_raw_ptr = expected a raw pointer const_eval_validation_expected_ref = expected a reference const_eval_validation_expected_str = expected a string +const_eval_validation_failure = + it is undefined behavior to use this value + +const_eval_validation_failure_note = + The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + const_eval_validation_front_matter_invalid_value = constructing invalid value const_eval_validation_front_matter_invalid_value_with_path = constructing invalid value at {$path} diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index b6adee435ba..763344207c4 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -2,15 +2,16 @@ use std::mem; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg}; use rustc_hir::CRATE_HIR_ID; +use rustc_middle::mir::interpret::Provenance; use rustc_middle::mir::AssertKind; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{layout::LayoutError, ConstInt}; use rustc_span::{Span, Symbol, DUMMY_SP}; -use super::{CompileTimeInterpreter, InterpCx}; +use super::CompileTimeInterpreter; use crate::errors::{self, FrameNote, ReportErrorExt}; -use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, MachineStopType}; +use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType}; /// The CTFE machine has some custom error kinds. #[derive(Clone, Debug)] @@ -58,15 +59,12 @@ impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind { pub fn get_span_and_frames<'tcx, 'mir>( tcx: TyCtxtAt<'tcx>, - machine: &CompileTimeInterpreter<'mir, 'tcx>, + stack: &[Frame<'mir, 'tcx, impl Provenance, impl Sized>], ) -> (Span, Vec<errors::FrameNote>) where 'tcx: 'mir, { - let mut stacktrace = - InterpCx::<CompileTimeInterpreter<'mir, 'tcx>>::generate_stacktrace_from_stack( - &machine.stack, - ); + let mut stacktrace = Frame::generate_stacktrace_from_stack(stack); // Filter out `requires_caller_location` frames. stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx)); let span = stacktrace.first().map(|f| f.span).unwrap_or(tcx.span); @@ -170,7 +168,7 @@ pub(super) fn lint<'tcx, 'mir, L>( ) where L: for<'a> rustc_errors::LintDiagnostic<'a, ()>, { - let (span, frames) = get_span_and_frames(tcx, machine); + let (span, frames) = get_span_and_frames(tcx, &machine.stack); tcx.emit_node_span_lint( lint, diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 5f4408ebbc6..5a1c7cc4209 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -18,18 +18,18 @@ use crate::errors; use crate::errors::ConstEvalError; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ - create_static_alloc, intern_const_alloc_recursive, take_static_root_alloc, CtfeValidationMode, - GlobalId, Immediate, InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, - OpTy, RefTracking, StackPopCleanup, + create_static_alloc, intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate, + InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, + StackPopCleanup, }; // Returns a pointer to where the result lives -#[instrument(level = "trace", skip(ecx, body), ret)] -fn eval_body_using_ecx<'mir, 'tcx>( +#[instrument(level = "trace", skip(ecx, body))] +fn eval_body_using_ecx<'mir, 'tcx, R: InterpretationResult<'tcx>>( ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, cid: GlobalId<'tcx>, body: &'mir mir::Body<'tcx>, -) -> InterpResult<'tcx, MPlaceTy<'tcx>> { +) -> InterpResult<'tcx, R> { trace!(?ecx.param_env); let tcx = *ecx.tcx; assert!( @@ -84,7 +84,10 @@ fn eval_body_using_ecx<'mir, 'tcx>( // Intern the result intern_const_alloc_recursive(ecx, intern_kind, &ret)?; - Ok(ret) + // Since evaluation had no errors, validate the resulting constant. + const_validate_mplace(&ecx, &ret, cid)?; + + Ok(R::make_result(ret, ecx)) } /// The `InterpCx` is only meant to be used to do field and index projections into constants for @@ -282,18 +285,26 @@ pub fn eval_static_initializer_provider<'tcx>( let instance = ty::Instance::mono(tcx, def_id.to_def_id()); let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None }; - let mut ecx = InterpCx::new( - tcx, - tcx.def_span(def_id), - ty::ParamEnv::reveal_all(), - // Statics (and promoteds inside statics) may access other statics, because unlike consts - // they do not have to behave "as if" they were evaluated at runtime. - CompileTimeInterpreter::new(CanAccessMutGlobal::Yes, CheckAlignment::Error), - ); - let alloc_id = eval_in_interpreter(&mut ecx, cid, true)?.alloc_id; - let alloc = take_static_root_alloc(&mut ecx, alloc_id); - let alloc = tcx.mk_const_alloc(alloc); - Ok(alloc) + eval_in_interpreter(tcx, cid, ty::ParamEnv::reveal_all()) +} + +pub trait InterpretationResult<'tcx> { + /// This function takes the place where the result of the evaluation is stored + /// and prepares it for returning it in the appropriate format needed by the specific + /// evaluation query. + fn make_result<'mir>( + mplace: MPlaceTy<'tcx>, + ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, + ) -> Self; +} + +impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> { + fn make_result<'mir>( + mplace: MPlaceTy<'tcx>, + _ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, + ) -> Self { + ConstAlloc { alloc_id: mplace.ptr().provenance.unwrap().alloc_id(), ty: mplace.layout.ty } + } } #[instrument(skip(tcx), level = "debug")] @@ -319,92 +330,64 @@ pub fn eval_to_allocation_raw_provider<'tcx>( trace!("const eval: {:?} ({})", key, instance); } - let cid = key.value; + eval_in_interpreter(tcx, key.value, key.param_env) +} + +fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( + tcx: TyCtxt<'tcx>, + cid: GlobalId<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> Result<R, ErrorHandled> { let def = cid.instance.def.def_id(); let is_static = tcx.is_static(def); let mut ecx = InterpCx::new( tcx, tcx.def_span(def), - key.param_env, + param_env, // Statics (and promoteds inside statics) may access mutable global memory, because unlike consts // they do not have to behave "as if" they were evaluated at runtime. // For consts however we want to ensure they behave "as if" they were evaluated at runtime, // so we have to reject reading mutable global memory. CompileTimeInterpreter::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), ); - eval_in_interpreter(&mut ecx, cid, is_static) -} - -pub fn eval_in_interpreter<'mir, 'tcx>( - ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, - cid: GlobalId<'tcx>, - is_static: bool, -) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { - // `is_static` just means "in static", it could still be a promoted! - debug_assert_eq!(is_static, ecx.tcx.static_mutability(cid.instance.def_id()).is_some()); - let res = ecx.load_mir(cid.instance.def, cid.promoted); - match res.and_then(|body| eval_body_using_ecx(ecx, cid, body)) { - Err(error) => { - let (error, backtrace) = error.into_parts(); - backtrace.print_backtrace(); - - let (kind, instance) = if is_static { - ("static", String::new()) - } else { - // If the current item has generics, we'd like to enrich the message with the - // instance and its args: to show the actual compile-time values, in addition to - // the expression, leading to the const eval error. - let instance = &cid.instance; - if !instance.args.is_empty() { - let instance = with_no_trimmed_paths!(instance.to_string()); - ("const_with_path", instance) - } else { - ("const", String::new()) - } - }; - - Err(super::report( - *ecx.tcx, - error, - None, - || super::get_span_and_frames(ecx.tcx, &ecx.machine), - |span, frames| ConstEvalError { - span, - error_kind: kind, - instance, - frame_notes: frames, - }, - )) - } - Ok(mplace) => { - // Since evaluation had no errors, validate the resulting constant. - - // Temporarily allow access to the static_root_ids for the purpose of validation. - let static_root_ids = ecx.machine.static_root_ids.take(); - let res = const_validate_mplace(&ecx, &mplace, cid); - ecx.machine.static_root_ids = static_root_ids; - - let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); - - // Validation failed, report an error. - if let Err(error) = res { - Err(const_report_error(&ecx, error, alloc_id)) + res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)).map_err(|error| { + let (error, backtrace) = error.into_parts(); + backtrace.print_backtrace(); + + let (kind, instance) = if ecx.tcx.is_static(cid.instance.def_id()) { + ("static", String::new()) + } else { + // If the current item has generics, we'd like to enrich the message with the + // instance and its args: to show the actual compile-time values, in addition to + // the expression, leading to the const eval error. + let instance = &cid.instance; + if !instance.args.is_empty() { + let instance = with_no_trimmed_paths!(instance.to_string()); + ("const_with_path", instance) } else { - // Convert to raw constant - Ok(ConstAlloc { alloc_id, ty: mplace.layout.ty }) + ("const", String::new()) } - } - } + }; + + super::report( + *ecx.tcx, + error, + None, + || super::get_span_and_frames(ecx.tcx, ecx.stack()), + |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames }, + ) + }) } #[inline(always)] -pub fn const_validate_mplace<'mir, 'tcx>( +fn const_validate_mplace<'mir, 'tcx>( ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, mplace: &MPlaceTy<'tcx>, cid: GlobalId<'tcx>, -) -> InterpResult<'tcx> { +) -> Result<(), ErrorHandled> { + let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); let mut ref_tracking = RefTracking::new(mplace.clone()); let mut inner = false; while let Some((mplace, path)) = ref_tracking.todo.pop() { @@ -418,7 +401,10 @@ pub fn const_validate_mplace<'mir, 'tcx>( CtfeValidationMode::Const { allow_immutable_unsafe_cell: !inner } } }; - ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?; + ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode) + // Instead of just reporting the `InterpError` via the usual machinery, we give a more targetted + // error about the validation failure. + .map_err(|error| report_validation_error(&ecx, error, alloc_id))?; inner = true; } @@ -426,7 +412,7 @@ pub fn const_validate_mplace<'mir, 'tcx>( } #[inline(always)] -pub fn const_report_error<'mir, 'tcx>( +fn report_validation_error<'mir, 'tcx>( ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, error: InterpErrorInfo<'tcx>, alloc_id: AllocId, @@ -444,7 +430,7 @@ pub fn const_report_error<'mir, 'tcx>( *ecx.tcx, error, None, - || crate::const_eval::get_span_and_frames(ecx.tcx, &ecx.machine), - move |span, frames| errors::UndefinedBehavior { span, ub_note, frames, raw_bytes }, + || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()), + move |span, frames| errors::ValidationFailure { span, ub_note, frames, raw_bytes }, ) } diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 289dcb7d01d..d0d6adbfad0 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::interpret::InterpErrorInfo; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::{self, Ty}; -use crate::interpret::{format_interp_error, InterpCx}; +use crate::interpret::format_interp_error; mod error; mod eval_queries; diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 46790264359..cc32640408b 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -412,11 +412,11 @@ pub struct NullaryIntrinsicError { } #[derive(Diagnostic)] -#[diag(const_eval_undefined_behavior, code = E0080)] -pub struct UndefinedBehavior { +#[diag(const_eval_validation_failure, code = E0080)] +pub struct ValidationFailure { #[primary_span] pub span: Span, - #[note(const_eval_undefined_behavior_note)] + #[note(const_eval_validation_failure_note)] pub ub_note: Option<()>, #[subdiagnostic] pub frames: Vec<FrameNote>, diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 7526acf1454..09e9cc4b35d 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -283,6 +283,32 @@ impl<'mir, 'tcx, Prov: Provenance, Extra> Frame<'mir, 'tcx, Prov, Extra> { pub(super) fn locals_addr(&self) -> usize { self.locals.raw.as_ptr().addr() } + + #[must_use] + pub fn generate_stacktrace_from_stack(stack: &[Self]) -> Vec<FrameInfo<'tcx>> { + let mut frames = Vec::new(); + // This deliberately does *not* honor `requires_caller_location` since it is used for much + // more than just panics. + for frame in stack.iter().rev() { + let span = match frame.loc { + Left(loc) => { + // If the stacktrace passes through MIR-inlined source scopes, add them. + let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc); + let mut scope_data = &frame.body.source_scopes[scope]; + while let Some((instance, call_span)) = scope_data.inlined { + frames.push(FrameInfo { span, instance }); + span = call_span; + scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()]; + } + span + } + Right(span) => span, + }; + frames.push(FrameInfo { span, instance: frame.instance }); + } + trace!("generate stacktrace: {:#?}", frames); + frames + } } // FIXME: only used by miri, should be removed once translatable. @@ -1171,36 +1197,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[must_use] - pub fn generate_stacktrace_from_stack( - stack: &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>], - ) -> Vec<FrameInfo<'tcx>> { - let mut frames = Vec::new(); - // This deliberately does *not* honor `requires_caller_location` since it is used for much - // more than just panics. - for frame in stack.iter().rev() { - let span = match frame.loc { - Left(loc) => { - // If the stacktrace passes through MIR-inlined source scopes, add them. - let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc); - let mut scope_data = &frame.body.source_scopes[scope]; - while let Some((instance, call_span)) = scope_data.inlined { - frames.push(FrameInfo { span, instance }); - span = call_span; - scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()]; - } - span - } - Right(span) => span, - }; - frames.push(FrameInfo { span, instance: frame.instance }); - } - trace!("generate stacktrace: {:#?}", frames); - frames - } - - #[must_use] pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> { - Self::generate_stacktrace_from_stack(self.stack()) + Frame::generate_stacktrace_from_stack(self.stack()) } } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index c30a1362417..17bb59aae8f 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -176,7 +176,7 @@ pub fn intern_const_alloc_recursive< // This gives us the initial set of nested allocations, which will then all be processed // recursively in the loop below. let mut todo: Vec<_> = if is_static { - // Do not steal the root allocation, we need it later for `take_static_root_alloc` + // Do not steal the root allocation, we need it later to create the return value of `eval_static_initializer`. // But still change its mutability to match the requested one. let alloc = ecx.memory.alloc_map.get_mut(&base_alloc_id).unwrap(); alloc.1.mutability = base_mutability; diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 2ed879ca72b..474d35b2aa3 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -39,5 +39,5 @@ use self::{ }; pub(crate) use self::intrinsics::eval_nullary_intrinsic; -pub(crate) use self::util::{create_static_alloc, take_static_root_alloc}; +pub(crate) use self::util::create_static_alloc; use eval_context::{from_known_layout, mir_assign_valid_types}; diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 086475f72c5..c83ef14c03f 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,14 +1,15 @@ -use crate::const_eval::CompileTimeEvalContext; +use crate::const_eval::{CompileTimeEvalContext, CompileTimeInterpreter, InterpretationResult}; use crate::interpret::{MemPlaceMeta, MemoryKind}; use rustc_hir::def_id::LocalDefId; -use rustc_middle::mir::interpret::{AllocId, Allocation, InterpResult, Pointer}; +use rustc_middle::mir; +use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use std::ops::ControlFlow; -use super::MPlaceTy; +use super::{InterpCx, MPlaceTy}; /// Checks whether a type contains generic parameters which must be instantiated. /// @@ -80,11 +81,15 @@ where } } -pub(crate) fn take_static_root_alloc<'mir, 'tcx: 'mir>( - ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, - alloc_id: AllocId, -) -> Allocation { - ecx.memory.alloc_map.swap_remove(&alloc_id).unwrap().1 +impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> { + fn make_result<'mir>( + mplace: MPlaceTy<'tcx>, + ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, + ) -> Self { + let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); + let alloc = ecx.memory.alloc_map.swap_remove(&alloc_id).unwrap().1; + ecx.tcx.mk_const_alloc(alloc) + } } pub(crate) fn create_static_alloc<'mir, 'tcx: 'mir>( diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 38848b22cb2..1f77484d65c 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -894,56 +894,93 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing), - rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing), - rustc_attr!(TEST, rustc_variance_of_opaques, Normal, template!(Word), WarnFollowing), - rustc_attr!(TEST, rustc_hidden_type_of_opaques, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing, @only_local: true), + rustc_attr!( + TEST, rustc_variance_of_opaques, Normal, template!(Word), + WarnFollowing, @only_local: true + ), + rustc_attr!( + TEST, rustc_hidden_type_of_opaques, Normal, template!(Word), + WarnFollowing, @only_local: true), rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing), - rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing), - rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), + rustc_attr!( + TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), + WarnFollowing, @only_local: true + ), + rustc_attr!( + TEST, rustc_regions, Normal, template!(Word), + WarnFollowing, @only_local: true + ), rustc_attr!( TEST, rustc_error, Normal, template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly ), - rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing), + rustc_attr!( + TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing, + @only_local: true + ), rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing), rustc_attr!( - TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), DuplicatesOk + TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), + DuplicatesOk, @only_local: true ), rustc_attr!( - TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"), DuplicatesOk + TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"), + DuplicatesOk, @only_local: true ), rustc_attr!( TEST, rustc_clean, Normal, template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), - DuplicatesOk, + DuplicatesOk, @only_local: true ), rustc_attr!( TEST, rustc_partition_reused, Normal, - template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, + template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, @only_local: true ), rustc_attr!( TEST, rustc_partition_codegened, Normal, - template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, + template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, @only_local: true ), rustc_attr!( TEST, rustc_expected_cgu_reuse, Normal, template!(List: r#"cfg = "...", module = "...", kind = "...""#), DuplicatesOk, + @only_local: true + ), + rustc_attr!( + TEST, rustc_symbol_name, Normal, template!(Word), WarnFollowing, + @only_local: true ), - rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word), WarnFollowing), - rustc_attr!(TEST, rustc_def_path, Normal, template!(Word), WarnFollowing), + rustc_attr!( + TEST, rustc_def_path, Normal, template!(Word), WarnFollowing, + @only_local: true + ), rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), DuplicatesOk), gated!( custom_mir, Normal, template!(List: r#"dialect = "...", phase = "...""#), - ErrorFollowing, "the `#[custom_mir]` attribute is just used for the Rust test suite", + ErrorFollowing, @only_local: true, + "the `#[custom_mir]` attribute is just used for the Rust test suite", + ), + rustc_attr!( + TEST, rustc_dump_program_clauses, Normal, template!(Word), WarnFollowing, + @only_local: true + ), + rustc_attr!( + TEST, rustc_dump_env_program_clauses, Normal, template!(Word), WarnFollowing, + @only_local: true + ), + rustc_attr!( + TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing, + @only_local: true ), - rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word), WarnFollowing), - rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word), WarnFollowing), - rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_dump_vtable, Normal, template!(Word), WarnFollowing), - rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/), DuplicatesOk), + rustc_attr!( + TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/), DuplicatesOk, + @only_local: true + ), gated!( omit_gdb_pretty_printer_section, Normal, template!(Word), WarnFollowing, + @only_local: true, "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite", ), rustc_attr!( diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f384f66a2c3..4acdd8fef52 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4355,7 +4355,6 @@ declare_lint! { pub UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, Warn, "unrecognized or malformed diagnostic attribute", - @feature_gate = sym::diagnostic_namespace; } declare_lint! { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index cac12e5ee0b..11065b2a382 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2436,8 +2436,9 @@ impl<'tcx> Ty<'tcx> { }, // "Bound" types appear in canonical queries when the - // closure type is not yet known - Bound(..) | Param(_) | Infer(_) => None, + // closure type is not yet known, and `Placeholder` and `Param` + // may be encountered in generic `AsyncFnKindHelper` goals. + Bound(..) | Placeholder(_) | Param(_) | Infer(_) => None, Error(_) => Some(ty::ClosureKind::Fn), diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index d9387ecd14c..0970c4de19f 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -11,7 +11,7 @@ use rustc_target::spec::PanicStrategy; use crate::errors; /// Some of the functions declared as "may unwind" by `fn_can_unwind` can't actually unwind. In -/// particular, `extern "C"` is still considered as can-unwind on stable, but we need to to consider +/// particular, `extern "C"` is still considered as can-unwind on stable, but we need to consider /// it cannot-unwind here. So below we check `fn_can_unwind() && abi_can_unwind()` before concluding /// that a function call can unwind. fn abi_can_unwind(abi: Abi) -> bool { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 33a446eb55a..2465f9fbfa8 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -818,13 +818,16 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { self.super_rvalue(rvalue, location); } - /// This does not walk the constant, as it has been handled entirely here and trying - /// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily - /// work, as some constants cannot be represented in the type system. + /// This does not walk the MIR of the constant as that is not needed for codegen, all we need is + /// to ensure that the constant evaluates successfully and walk the result. #[instrument(skip(self), level = "debug")] fn visit_constant(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) { let const_ = self.monomorphize(constant.const_); let param_env = ty::ParamEnv::reveal_all(); + // Evaluate the constant. This makes const eval failure a collection-time error (rather than + // a codegen-time error). rustc stops after collection if there was an error, so this + // ensures codegen never has to worry about failing consts. + // (codegen relies on this and ICEs will happen if this is violated.) let val = match const_.eval(self.tcx, param_env, None) { Ok(v) => v, Err(ErrorHandled::Reported(..)) => return, diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 296eb3120ee..15041b9cd41 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -1112,6 +1112,9 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co let (items, usage_map) = collector::collect_crate_mono_items(tcx, collection_mode); + // If there was an error during collection (e.g. from one of the constants we evaluated), + // then we stop here. This way codegen does not have to worry about failing constants. + // (codegen relies on this and ICEs will happen if this is violated.) tcx.dcx().abort_if_errors(); let (codegen_units, _) = tcx.sess.time("partition_and_assert_distinct_symbols", || { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index af533d8db71..2bfb86b592b 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -120,6 +120,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( ty: Ty<'tcx>, ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> { match *ty.kind() { + // impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, ! + // impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) | ty::Int(_) @@ -152,8 +154,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( bug!("unexpected type `{ty}`") } + // impl Sized for (T1, T2, .., Tn) where T1: Sized, T2: Sized, .. Tn: Sized ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()), + // impl Sized for Adt where T: Sized forall T in field types ty::Adt(def, args) => { let sized_crit = def.sized_constraint(ecx.tcx()); Ok(sized_crit.iter_instantiated(ecx.tcx(), args).map(ty::Binder::dummy).collect()) @@ -167,6 +171,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty: Ty<'tcx>, ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> { match *ty.kind() { + // impl Copy/Clone for FnDef, FnPtr ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]), // Implementations are provided in core @@ -196,12 +201,16 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( bug!("unexpected type `{ty}`") } + // impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()), + // impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), ty::CoroutineClosure(..) => Err(NoSolution), + // only when `coroutine_clone` is enabled and the coroutine is movable + // impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses) ty::Coroutine(def_id, args) => match ecx.tcx().coroutine_movability(def_id) { Movability::Static => Err(NoSolution), Movability::Movable => { @@ -217,6 +226,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( } }, + // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types ty::CoroutineWitness(def_id, args) => Ok(ecx .tcx() .coroutine_hidden_types(def_id) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 281f5cc5685..c252ad76dfe 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -250,6 +250,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ) -> QueryResult<'tcx> { let self_ty = goal.predicate.self_ty(); match goal.predicate.polarity { + // impl FnPtr for FnPtr {} ty::ImplPolarity::Positive => { if self_ty.is_fn_ptr() { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) @@ -257,6 +258,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { Err(NoSolution) } } + // impl !FnPtr for T where T != FnPtr && T is rigid {} ty::ImplPolarity::Negative => { // If a type is rigid and not a fn ptr, then we know for certain // that it does *not* implement `FnPtr`. @@ -374,6 +376,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } } + /// ```rust, ignore (not valid rust syntax) + /// impl Tuple for () {} + /// impl Tuple for (T1,) {} + /// impl Tuple for (T1, T2) {} + /// impl Tuple for (T1, .., Tn) {} + /// ``` fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, |
