Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 10 pull requests #122497

Merged
merged 34 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4b76fac
Document some builtin impls in the next solver
fee1-dead Mar 9, 2024
a82587c
Avoid closing invalid handles
dylni Mar 9, 2024
bcc3f19
rustdoc-search: depth limit `T<U>` -> `U` unboxing
notriddle Mar 9, 2024
39db6a0
add test ensuring simd codegen checks don't run when a static asserti…
RalfJung Mar 10, 2024
d765fb8
add comments explaining where post-mono const eval errors abort compi…
RalfJung Mar 10, 2024
fa5b9f0
rustdoc-search: stress test for associated types
notriddle Mar 11, 2024
6b082b5
chore: remove repetitive words
pavedroad Mar 12, 2024
dd0f41f
Fix WF for AsyncFnKindHelper in new trait solver
compiler-errors Mar 12, 2024
5dd44f4
change some attribute to only_local
surechen Mar 14, 2024
2541111
Ungate the `UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES` lint
weiznich Mar 14, 2024
71f1943
Fix accidental re-addition of removed code in a previous PR
oli-obk Mar 13, 2024
d6c9997
Generalize `eval_in_interpreter` with a helper trait
oli-obk Mar 11, 2024
93888cd
Move only usage of `take_static_root_alloc` to its definition and inl…
oli-obk Mar 11, 2024
8b8efd1
Move error handling into const_validate_mplace
oli-obk Mar 11, 2024
6b936b6
Move InterpCx into eval_in_interpreter
oli-obk Mar 11, 2024
69d781a
move impl documentation to their actual locations
fee1-dead Mar 14, 2024
d2d2bd2
Move generate_stacktrace_from_stack away from InterpCx to avoid havin…
oli-obk Mar 11, 2024
d3b7b55
Directly pass in the stack instead of computing it from a machine
oli-obk Mar 11, 2024
02a0ac8
Remove an argument that can be computed cheaply
oli-obk Mar 12, 2024
cc7e0b2
Share the `InterpCx` creation between static and const evaluation
oli-obk Mar 12, 2024
2e6c490
Move validation into eval_body_using_ecx
oli-obk Mar 12, 2024
16046c7
Move the entire success path into `eval_body_using_ecx`
oli-obk Mar 12, 2024
a316c21
Rename some things around validation error reporting to signal that i…
oli-obk Mar 13, 2024
ec0b459
Update build instructions for OpenHarmony
Amanieu Mar 14, 2024
280a1da
Rollup merge of #119029 - dylni:avoid-closing-invalid-handles, r=Chri…
matthiaskrgr Mar 14, 2024
7997ef4
Rollup merge of #122238 - fee1-dead-contrib:builtin-impl-next-solver-…
matthiaskrgr Mar 14, 2024
a95e2f9
Rollup merge of #122247 - notriddle:notriddle/search-unbox-limit, r=G…
matthiaskrgr Mar 14, 2024
6a4dd19
Rollup merge of #122287 - RalfJung:simd-static-assert, r=pnkfelix
matthiaskrgr Mar 14, 2024
1dce191
Rollup merge of #122368 - pavedroad:master, r=oli-obk
matthiaskrgr Mar 14, 2024
b4dffc9
Rollup merge of #122397 - oli-obk:machine-read-hook2, r=RalfJung
matthiaskrgr Mar 14, 2024
54b7300
Rollup merge of #122406 - compiler-errors:next-solver-asynckind-wf, r…
matthiaskrgr Mar 14, 2024
8303c6a
Rollup merge of #122477 - surechen:change_attribute_only_local_202403…
matthiaskrgr Mar 14, 2024
c0fd2db
Rollup merge of #122482 - weiznich:fix/122446, r=compiler-errors
matthiaskrgr Mar 14, 2024
02b1a91
Rollup merge of #122490 - Amanieu:ohos-tier2-instructions, r=Guillaum…
matthiaskrgr Mar 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_ssa/src/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_const_eval/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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}

Expand Down
14 changes: 6 additions & 8 deletions compiler/rustc_const_eval/src/const_eval/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
162 changes: 74 additions & 88 deletions compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")]
Expand All @@ -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() {
Expand All @@ -418,15 +401,18 @@ 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;
}

Ok(())
}

#[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,
Expand All @@ -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 },
)
}
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_const_eval/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
Loading
Loading