diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 1476fe285ef5c..cd269810741e7 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -89,6 +89,8 @@ const_eval_exact_div_has_remainder = const_eval_extern_static = cannot access extern static ({$did}) +const_eval_extern_type_field = `extern type` field does not have a known offset + const_eval_fn_ptr_call = function pointers need an RFC before allowed to be called in {const_eval_const_context}s const_eval_for_loop_into_iter_non_const = 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 c60df06bb0efc..d8efaa66415fb 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -386,33 +386,8 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), ); let res = ecx.load_mir(cid.instance.def, cid.promoted); - 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 { - ("const", String::new()) - } - }; - - super::report( - *ecx.tcx, - error, - DUMMY_SP, - || super::get_span_and_frames(ecx.tcx, ecx.stack()), - |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames }, - ) - }) + res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) + .map_err(|error| report_eval_error(&ecx, cid, error)) } #[inline(always)] @@ -438,24 +413,61 @@ fn const_validate_mplace<'tcx>( 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 targeted // error about the validation failure. - .map_err(|error| report_validation_error(&ecx, error, alloc_id))?; + .map_err(|error| report_validation_error(&ecx, cid, error, alloc_id))?; inner = true; } Ok(()) } -#[inline(always)] +#[inline(never)] +fn report_eval_error<'tcx>( + ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, + cid: GlobalId<'tcx>, + error: InterpErrorInfo<'tcx>, +) -> ErrorHandled { + 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 { + ("const", String::new()) + } + }; + + super::report( + *ecx.tcx, + error, + DUMMY_SP, + || super::get_span_and_frames(ecx.tcx, ecx.stack()), + |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames }, + ) +} + +#[inline(never)] fn report_validation_error<'tcx>( ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, + cid: GlobalId<'tcx>, error: InterpErrorInfo<'tcx>, alloc_id: AllocId, ) -> ErrorHandled { + if !matches!(error.kind(), InterpError::UndefinedBehavior(_)) { + // Some other error happened during validation, e.g. an unsupported operation. + return report_eval_error(ecx, cid, error); + } + let (error, backtrace) = error.into_parts(); backtrace.print_backtrace(); - let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {}); - let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id); let (size, align, _) = ecx.get_alloc_info(alloc_id); let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes }; @@ -465,6 +477,6 @@ fn report_validation_error<'tcx>( error, DUMMY_SP, || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()), - move |span, frames| errors::ValidationFailure { span, ub_note, frames, raw_bytes }, + move |span, frames| errors::ValidationFailure { span, ub_note: (), frames, raw_bytes }, ) } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 5fa48a59794be..292d6ba9d08a4 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -425,7 +425,7 @@ pub struct ValidationFailure { #[primary_span] pub span: Span, #[note(const_eval_validation_failure_note)] - pub ub_note: Option<()>, + pub ub_note: (), #[subdiagnostic] pub frames: Vec, #[subdiagnostic] @@ -825,6 +825,7 @@ impl ReportErrorExt for UnsupportedOpInfo { use crate::fluent_generated::*; match self { UnsupportedOpInfo::Unsupported(s) => s.clone().into(), + UnsupportedOpInfo::ExternTypeField => const_eval_extern_type_field, UnsupportedOpInfo::UnsizedLocal => const_eval_unsized_local, UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite, UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy, @@ -845,7 +846,10 @@ impl ReportErrorExt for UnsupportedOpInfo { // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to // be further processed by validity checking which then turns it into something nice to // print. So it's not worth the effort of having diagnostics that can print the `info`. - UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {} + UnsizedLocal + | UnsupportedOpInfo::ExternTypeField + | Unsupported(_) + | ReadPointerAsInt(_) => {} OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => { diag.arg("ptr", ptr); } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index efa01b5434260..cfa814c810aff 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -21,7 +21,7 @@ use rustc_target::abi::{self, VariantIdx}; use tracing::{debug, instrument}; use super::{ - throw_ub, throw_unsup_format, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, + throw_ub, throw_unsup, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar, }; @@ -186,8 +186,8 @@ where (base_meta, offset) } None => { - // We don't know the alignment of this field, so we cannot adjust. - throw_unsup_format!("`extern type` does not have a known offset") + // We cannot know the alignment of this field, so we cannot adjust. + throw_unsup!(ExternTypeField) } } } else { diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index ca8b98849338b..add48e1b186cb 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -5,6 +5,7 @@ //! to be const-safe. use std::fmt::Write; +use std::hash::Hash; use std::num::NonZero; use either::{Left, Right}; @@ -17,7 +18,8 @@ use rustc_hir as hir; use rustc_middle::bug; use rustc_middle::mir::interpret::{ ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance, - ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*, + UnsupportedOpInfo, ValidationErrorInfo, + ValidationErrorKind::{self, *}, }; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; @@ -26,8 +28,6 @@ use rustc_target::abi::{ Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, }; -use std::hash::Hash; - use super::{ err_ub, format_interp_error, machine::AllocMap, throw_ub, AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, @@ -1028,7 +1028,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Err(err) if matches!( err.kind(), - err_ub!(ValidationError { .. }) | InterpError::InvalidProgram(_) + err_ub!(ValidationError { .. }) + | InterpError::InvalidProgram(_) + | InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField) ) => { Err(err) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 23680f143970d..6a8498abaf933 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -520,6 +520,8 @@ pub enum UnsupportedOpInfo { Unsupported(String), /// Unsized local variables. UnsizedLocal, + /// Extern type field with an indeterminate offset. + ExternTypeField, // // The variants below are only reachable from CTFE/const prop, miri will never emit them. // diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 12fb76f397241..1b70a1a1cf08f 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -311,7 +311,9 @@ pub fn report_error<'tcx>( ResourceExhaustion(_) => "resource exhaustion", Unsupported( // We list only the ones that can actually happen. - UnsupportedOpInfo::Unsupported(_) | UnsupportedOpInfo::UnsizedLocal, + UnsupportedOpInfo::Unsupported(_) + | UnsupportedOpInfo::UnsizedLocal + | UnsupportedOpInfo::ExternTypeField, ) => "unsupported operation", InvalidProgram( // We list only the ones that can actually happen. diff --git a/src/tools/miri/tests/fail/extern-type-field-offset.stderr b/src/tools/miri/tests/fail/extern-type-field-offset.stderr index e0d6e9ebf1de7..3ed5732b4eb06 100644 --- a/src/tools/miri/tests/fail/extern-type-field-offset.stderr +++ b/src/tools/miri/tests/fail/extern-type-field-offset.stderr @@ -1,8 +1,8 @@ -error: unsupported operation: `extern type` does not have a known offset +error: unsupported operation: `extern type` field does not have a known offset --> $DIR/extern-type-field-offset.rs:LL:CC | LL | let _field = &x.a; - | ^^^^ `extern type` does not have a known offset + | ^^^^ `extern type` field does not have a known offset | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: diff --git a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr index 99f37fedd3dd3..54d45ee8ffb24 100644 --- a/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr +++ b/tests/ui/consts/const-eval/issue-91827-extern-types-field-offset.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/issue-91827-extern-types-field-offset.rs:38:17 | LL | let field = &x.a; - | ^^^^ `extern type` does not have a known offset + | ^^^^ `extern type` field does not have a known offset error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/validation-ice-extern-type-field.rs b/tests/ui/consts/const-eval/validation-ice-extern-type-field.rs new file mode 100644 index 0000000000000..3502409d576c2 --- /dev/null +++ b/tests/ui/consts/const-eval/validation-ice-extern-type-field.rs @@ -0,0 +1,15 @@ +#![feature(extern_types)] + +extern { + type Opaque; +} + +struct ThinDst { + x: u8, + tail: Opaque, +} + +const C1: &ThinDst = unsafe { std::mem::transmute(b"d".as_ptr()) }; +//~^ERROR: evaluation of constant value failed + +fn main() {} diff --git a/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr b/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr new file mode 100644 index 0000000000000..1ec36abc2eccf --- /dev/null +++ b/tests/ui/consts/const-eval/validation-ice-extern-type-field.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/validation-ice-extern-type-field.rs:12:1 + | +LL | const C1: &ThinDst = unsafe { std::mem::transmute(b"d".as_ptr()) }; + | ^^^^^^^^^^^^^^^^^^ `extern type` field does not have a known offset + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr index 3f8011d961ae7..6bbd81ae3e163 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr @@ -9,15 +9,11 @@ LL | const _: *const Foo = 0 as _; | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0080]: it is undefined behavior to use this value +error[E0080]: evaluation of constant value failed --> $DIR/stack-overflow-trait-infer-98842.rs:15:1 | LL | const _: *const Foo = 0 as _; | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation - | - = note: the raw bytes of the constant (size: 4, align: 4) { - 00 00 00 00 │ .... - } error: aborting due to 2 previous errors diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr index 04e2c4483bf64..6bbd81ae3e163 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr @@ -9,15 +9,11 @@ LL | const _: *const Foo = 0 as _; | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0080]: it is undefined behavior to use this value +error[E0080]: evaluation of constant value failed --> $DIR/stack-overflow-trait-infer-98842.rs:15:1 | LL | const _: *const Foo = 0 as _; | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation - | - = note: the raw bytes of the constant (size: 8, align: 8) { - 00 00 00 00 00 00 00 00 │ ........ - } error: aborting due to 2 previous errors diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.rs b/tests/ui/sized/stack-overflow-trait-infer-98842.rs index 54d50346cc831..be4807b2e4aa7 100644 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.rs +++ b/tests/ui/sized/stack-overflow-trait-infer-98842.rs @@ -13,6 +13,6 @@ struct Foo(<&'static Foo as ::core::ops::Deref>::Target); // and it will infinitely recurse somewhere trying to figure out the // size of this pointer (is my guess): const _: *const Foo = 0 as _; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed pub fn main() {} diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.stderr deleted file mode 100644 index 8ddddeb5bf2d1..0000000000000 --- a/tests/ui/sized/stack-overflow-trait-infer-98842.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0391]: cycle detected when computing layout of `Foo` - | - = note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`... - = note: ...which again requires computing layout of `Foo`, completing the cycle -note: cycle used when const-evaluating + checking `_` - --> $DIR/stack-overflow-trait-infer-98842.rs:13:1 - | -LL | const _: *const Foo = 0 as _; - | ^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error[E0080]: it is undefined behavior to use this value - --> $DIR/stack-overflow-trait-infer-98842.rs:13:1 - | -LL | const _: *const Foo = 0 as _; - | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation - | - = note: the raw bytes of the constant (size: 8, align: 8) { - 00 00 00 00 00 00 00 00 │ ........ - } - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0080, E0391. -For more information about an error, try `rustc --explain E0080`.