mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
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
This commit is contained in:
commit
30f74ff0dc
@ -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())
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
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 is_static {
|
||||
("static", String::new())
|
||||
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 {
|
||||
// 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))
|
||||
} 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 },
|
||||
)
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>,
|
||||
|
@ -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.
|
||||
@ -1170,37 +1196,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
PlacePrinter { ecx: self, place: *place.place() }
|
||||
}
|
||||
|
||||
#[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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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>(
|
||||
|
@ -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!(
|
||||
|
@ -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! {
|
||||
|
@ -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),
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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", || {
|
||||
|
@ -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)
|
||||
|
@ -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>,
|
||||
|
@ -7,7 +7,7 @@ use crate::fmt;
|
||||
use crate::fs;
|
||||
use crate::io;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::forget;
|
||||
use crate::mem::{forget, ManuallyDrop};
|
||||
use crate::ptr;
|
||||
use crate::sys;
|
||||
use crate::sys::cvt;
|
||||
@ -91,7 +91,7 @@ pub struct OwnedHandle {
|
||||
#[repr(transparent)]
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
#[derive(Debug)]
|
||||
pub struct HandleOrNull(OwnedHandle);
|
||||
pub struct HandleOrNull(RawHandle);
|
||||
|
||||
/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
|
||||
/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
|
||||
@ -110,7 +110,7 @@ pub struct HandleOrNull(OwnedHandle);
|
||||
#[repr(transparent)]
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
#[derive(Debug)]
|
||||
pub struct HandleOrInvalid(OwnedHandle);
|
||||
pub struct HandleOrInvalid(RawHandle);
|
||||
|
||||
// The Windows [`HANDLE`] type may be transferred across and shared between
|
||||
// thread boundaries (despite containing a `*mut void`, which in general isn't
|
||||
@ -163,15 +163,24 @@ impl TryFrom<HandleOrNull> for OwnedHandle {
|
||||
|
||||
#[inline]
|
||||
fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NullHandleError> {
|
||||
let owned_handle = handle_or_null.0;
|
||||
if owned_handle.handle.is_null() {
|
||||
// Don't call `CloseHandle`; it'd be harmless, except that it could
|
||||
// overwrite the `GetLastError` error.
|
||||
forget(owned_handle);
|
||||
|
||||
Err(NullHandleError(()))
|
||||
let handle_or_null = ManuallyDrop::new(handle_or_null);
|
||||
if handle_or_null.is_valid() {
|
||||
// SAFETY: The handle is not null.
|
||||
Ok(unsafe { OwnedHandle::from_raw_handle(handle_or_null.0) })
|
||||
} else {
|
||||
Ok(owned_handle)
|
||||
Err(NullHandleError(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl Drop for HandleOrNull {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
if self.is_valid() {
|
||||
unsafe {
|
||||
let _ = sys::c::CloseHandle(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -232,15 +241,24 @@ impl TryFrom<HandleOrInvalid> for OwnedHandle {
|
||||
|
||||
#[inline]
|
||||
fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, InvalidHandleError> {
|
||||
let owned_handle = handle_or_invalid.0;
|
||||
if owned_handle.handle == sys::c::INVALID_HANDLE_VALUE {
|
||||
// Don't call `CloseHandle`; it'd be harmless, except that it could
|
||||
// overwrite the `GetLastError` error.
|
||||
forget(owned_handle);
|
||||
|
||||
Err(InvalidHandleError(()))
|
||||
let handle_or_invalid = ManuallyDrop::new(handle_or_invalid);
|
||||
if handle_or_invalid.is_valid() {
|
||||
// SAFETY: The handle is not invalid.
|
||||
Ok(unsafe { OwnedHandle::from_raw_handle(handle_or_invalid.0) })
|
||||
} else {
|
||||
Ok(owned_handle)
|
||||
Err(InvalidHandleError(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl Drop for HandleOrInvalid {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
if self.is_valid() {
|
||||
unsafe {
|
||||
let _ = sys::c::CloseHandle(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -333,7 +351,11 @@ impl HandleOrNull {
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
#[inline]
|
||||
pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
|
||||
Self(OwnedHandle::from_raw_handle(handle))
|
||||
Self(handle)
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> bool {
|
||||
!self.0.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,7 +378,11 @@ impl HandleOrInvalid {
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
#[inline]
|
||||
pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
|
||||
Self(OwnedHandle::from_raw_handle(handle))
|
||||
Self(handle)
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> bool {
|
||||
self.0 != sys::c::INVALID_HANDLE_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,9 +96,34 @@ exec /path/to/ohos-sdk/linux/native/llvm/bin/clang++ \
|
||||
|
||||
Future versions of the OpenHarmony SDK will avoid the need for this process.
|
||||
|
||||
## Building the target
|
||||
## Building Rust programs
|
||||
|
||||
To build a rust toolchain, create a `config.toml` with the following contents:
|
||||
Rustup ships pre-compiled artifacts for this target, which you can install with:
|
||||
```sh
|
||||
rustup target add aarch64-unknown-linux-ohos
|
||||
rustup target add armv7-unknown-linux-ohos
|
||||
rustup target add x86_64-unknown-linux-ohos
|
||||
```
|
||||
|
||||
You will need to configure the linker to use in `~/.cargo/config.toml`:
|
||||
```toml
|
||||
[target.aarch64-unknown-linux-ohos]
|
||||
ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
|
||||
linker = "/path/to/aarch64-unknown-linux-ohos-clang.sh"
|
||||
|
||||
[target.armv7-unknown-linux-ohos]
|
||||
ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
|
||||
linker = "/path/to/armv7-unknown-linux-ohos-clang.sh"
|
||||
|
||||
[target.x86_64-unknown-linux-ohos]
|
||||
ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
|
||||
linker = "/path/to/x86_64-unknown-linux-ohos-clang.sh"
|
||||
```
|
||||
|
||||
## Building the target from source
|
||||
|
||||
Instead of using `rustup`, you can instead build a rust toolchain from source.
|
||||
Create a `config.toml` with the following contents:
|
||||
|
||||
```toml
|
||||
profile = "compiler"
|
||||
@ -130,28 +155,6 @@ ranlib = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ranlib"
|
||||
linker = "/path/to/x86_64-unknown-linux-ohos-clang.sh"
|
||||
```
|
||||
|
||||
## Building Rust programs
|
||||
|
||||
Rust does not yet ship pre-compiled artifacts for this target. To compile for
|
||||
this target, you will either need to build Rust with the target enabled (see
|
||||
"Building the target" above), or build your own copy of `core` by using
|
||||
`build-std` or similar.
|
||||
|
||||
You will need to configure the linker to use in `~/.cargo/config`:
|
||||
```toml
|
||||
[target.aarch64-unknown-linux-ohos]
|
||||
ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
|
||||
linker = "/path/to/aarch64-unknown-linux-ohos-clang.sh"
|
||||
|
||||
[target.armv7-unknown-linux-ohos]
|
||||
ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
|
||||
linker = "/path/to/armv7-unknown-linux-ohos-clang.sh"
|
||||
|
||||
[target.x86_64-unknown-linux-ohos]
|
||||
ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
|
||||
linker = "/path/to/x86_64-unknown-linux-ohos-clang.sh"
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Running the Rust testsuite is possible, but currently difficult due to the way
|
||||
|
@ -51,7 +51,7 @@ single stack.
|
||||
By default, the UEFI targets use the `link`-flavor of the LLVM linker `lld` to
|
||||
link binaries into the final PE32+ file suffixed with `*.efi`. The PE subsystem
|
||||
is set to `EFI_APPLICATION`, but can be modified by passing `/subsystem:<...>`
|
||||
to the linker. Similarly, the entry-point is to to `efi_main` but can be
|
||||
to the linker. Similarly, the entry-point is set to `efi_main` but can be
|
||||
changed via `/entry:<...>`. The panic-strategy is set to `abort`,
|
||||
|
||||
The UEFI specification is available online for free:
|
||||
|
@ -81,6 +81,13 @@ const longItemTypes = [
|
||||
const TY_GENERIC = itemTypes.indexOf("generic");
|
||||
const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../";
|
||||
|
||||
// Hard limit on how deep to recurse into generics when doing type-driven search.
|
||||
// This needs limited, partially because
|
||||
// a search for `Ty` shouldn't match `WithInfcx<ParamEnvAnd<Vec<ConstTy<Interner<Ty=Ty>>>>>`,
|
||||
// but mostly because this is the simplest and most principled way to limit the number
|
||||
// of permutations we need to check.
|
||||
const UNBOXING_LIMIT = 5;
|
||||
|
||||
// In the search display, allows to switch between tabs.
|
||||
function printTab(nb) {
|
||||
let iter = 0;
|
||||
@ -1458,10 +1465,23 @@ function initSearch(rawSearchIndex) {
|
||||
* @param {Map<number,number>|null} mgensIn
|
||||
* - Map functions generics to query generics (never modified).
|
||||
* @param {null|Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
|
||||
* @param {number} unboxingDepth
|
||||
* - Limit checks that Ty matches Vec<Ty>,
|
||||
* but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
|
||||
*
|
||||
* @return {boolean} - Returns true if a match, false otherwise.
|
||||
*/
|
||||
function unifyFunctionTypes(fnTypesIn, queryElems, whereClause, mgensIn, solutionCb) {
|
||||
function unifyFunctionTypes(
|
||||
fnTypesIn,
|
||||
queryElems,
|
||||
whereClause,
|
||||
mgensIn,
|
||||
solutionCb,
|
||||
unboxingDepth
|
||||
) {
|
||||
if (unboxingDepth >= UNBOXING_LIMIT) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @type Map<integer, integer>|null
|
||||
*/
|
||||
@ -1480,7 +1500,7 @@ function initSearch(rawSearchIndex) {
|
||||
&& queryElems[0].bindings.size === 0) {
|
||||
const queryElem = queryElems[0];
|
||||
for (const fnType of fnTypesIn) {
|
||||
if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, whereClause, mgens)) {
|
||||
if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
|
||||
continue;
|
||||
}
|
||||
if (fnType.id < 0 && queryElem.id < 0) {
|
||||
@ -1499,7 +1519,13 @@ function initSearch(rawSearchIndex) {
|
||||
}
|
||||
}
|
||||
for (const fnType of fnTypesIn) {
|
||||
if (!unifyFunctionTypeIsUnboxCandidate(fnType, queryElem, whereClause, mgens)) {
|
||||
if (!unifyFunctionTypeIsUnboxCandidate(
|
||||
fnType,
|
||||
queryElem,
|
||||
whereClause,
|
||||
mgens,
|
||||
unboxingDepth + 1
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
if (fnType.id < 0) {
|
||||
@ -1514,7 +1540,8 @@ function initSearch(rawSearchIndex) {
|
||||
queryElems,
|
||||
whereClause,
|
||||
mgensScratch,
|
||||
solutionCb
|
||||
solutionCb,
|
||||
unboxingDepth + 1
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
@ -1523,7 +1550,8 @@ function initSearch(rawSearchIndex) {
|
||||
queryElems,
|
||||
whereClause,
|
||||
mgens ? new Map(mgens) : null,
|
||||
solutionCb
|
||||
solutionCb,
|
||||
unboxingDepth + 1
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
@ -1559,7 +1587,7 @@ function initSearch(rawSearchIndex) {
|
||||
let queryElemsTmp = null;
|
||||
for (let i = flast; i >= 0; i -= 1) {
|
||||
const fnType = fnTypes[i];
|
||||
if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, whereClause, mgens)) {
|
||||
if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
|
||||
continue;
|
||||
}
|
||||
let mgensScratch;
|
||||
@ -1596,7 +1624,8 @@ function initSearch(rawSearchIndex) {
|
||||
fnType,
|
||||
queryElem,
|
||||
whereClause,
|
||||
mgensScratch
|
||||
mgensScratch,
|
||||
unboxingDepth
|
||||
);
|
||||
if (!solution) {
|
||||
return false;
|
||||
@ -1608,14 +1637,16 @@ function initSearch(rawSearchIndex) {
|
||||
queryElem.generics,
|
||||
whereClause,
|
||||
simplifiedMgens,
|
||||
solutionCb
|
||||
solutionCb,
|
||||
unboxingDepth
|
||||
);
|
||||
if (passesUnification) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
unboxingDepth
|
||||
);
|
||||
if (passesUnification) {
|
||||
return true;
|
||||
@ -1627,7 +1658,13 @@ function initSearch(rawSearchIndex) {
|
||||
}
|
||||
for (let i = flast; i >= 0; i -= 1) {
|
||||
const fnType = fnTypes[i];
|
||||
if (!unifyFunctionTypeIsUnboxCandidate(fnType, queryElem, whereClause, mgens)) {
|
||||
if (!unifyFunctionTypeIsUnboxCandidate(
|
||||
fnType,
|
||||
queryElem,
|
||||
whereClause,
|
||||
mgens,
|
||||
unboxingDepth + 1
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
let mgensScratch;
|
||||
@ -1651,7 +1688,8 @@ function initSearch(rawSearchIndex) {
|
||||
queryElems,
|
||||
whereClause,
|
||||
mgensScratch,
|
||||
solutionCb
|
||||
solutionCb,
|
||||
unboxingDepth + 1
|
||||
);
|
||||
if (passesUnification) {
|
||||
return true;
|
||||
@ -1670,11 +1708,10 @@ function initSearch(rawSearchIndex) {
|
||||
*
|
||||
* @param {FunctionType} fnType
|
||||
* @param {QueryElement} queryElem
|
||||
* @param {[FunctionSearchType]} whereClause - Trait bounds for generic items.
|
||||
* @param {Map<number,number>|null} mgensIn - Map functions generics to query generics.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function unifyFunctionTypeIsMatchCandidate(fnType, queryElem, whereClause, mgensIn) {
|
||||
function unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgensIn) {
|
||||
// type filters look like `trait:Read` or `enum:Result`
|
||||
if (!typePassesFilter(queryElem.typeFilter, fnType.ty)) {
|
||||
return false;
|
||||
@ -1775,9 +1812,16 @@ function initSearch(rawSearchIndex) {
|
||||
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
|
||||
* @param {Map<number,number>} mgensIn - Map functions generics to query generics.
|
||||
* Never modified.
|
||||
* @param {number} unboxingDepth
|
||||
* @returns {false|{mgens: [Map<number,number>], simplifiedGenerics: [FunctionType]}}
|
||||
*/
|
||||
function unifyFunctionTypeCheckBindings(fnType, queryElem, whereClause, mgensIn) {
|
||||
function unifyFunctionTypeCheckBindings(
|
||||
fnType,
|
||||
queryElem,
|
||||
whereClause,
|
||||
mgensIn,
|
||||
unboxingDepth
|
||||
) {
|
||||
if (fnType.bindings.size < queryElem.bindings.size) {
|
||||
return false;
|
||||
}
|
||||
@ -1804,7 +1848,8 @@ function initSearch(rawSearchIndex) {
|
||||
// return `false` makes unifyFunctionTypes return the full set of
|
||||
// possible solutions
|
||||
return false;
|
||||
}
|
||||
},
|
||||
unboxingDepth
|
||||
);
|
||||
return newSolutions;
|
||||
});
|
||||
@ -1834,9 +1879,19 @@ function initSearch(rawSearchIndex) {
|
||||
* @param {QueryElement} queryElem
|
||||
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
|
||||
* @param {Map<number,number>|null} mgens - Map functions generics to query generics.
|
||||
* @param {number} unboxingDepth
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function unifyFunctionTypeIsUnboxCandidate(fnType, queryElem, whereClause, mgens) {
|
||||
function unifyFunctionTypeIsUnboxCandidate(
|
||||
fnType,
|
||||
queryElem,
|
||||
whereClause,
|
||||
mgens,
|
||||
unboxingDepth
|
||||
) {
|
||||
if (unboxingDepth >= UNBOXING_LIMIT) {
|
||||
return false;
|
||||
}
|
||||
if (fnType.id < 0 && queryElem.id >= 0) {
|
||||
if (!whereClause) {
|
||||
return false;
|
||||
@ -1858,14 +1913,21 @@ function initSearch(rawSearchIndex) {
|
||||
whereClause[(-fnType.id) - 1],
|
||||
queryElem,
|
||||
whereClause,
|
||||
mgensTmp
|
||||
mgensTmp,
|
||||
unboxingDepth
|
||||
);
|
||||
} else if (fnType.generics.length > 0 || fnType.bindings.size > 0) {
|
||||
const simplifiedGenerics = [
|
||||
...fnType.generics,
|
||||
...Array.from(fnType.bindings.values()).flat(),
|
||||
];
|
||||
return checkIfInList(simplifiedGenerics, queryElem, whereClause, mgens);
|
||||
return checkIfInList(
|
||||
simplifiedGenerics,
|
||||
queryElem,
|
||||
whereClause,
|
||||
mgens,
|
||||
unboxingDepth
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1877,13 +1939,14 @@ function initSearch(rawSearchIndex) {
|
||||
* @param {Array<FunctionType>} list
|
||||
* @param {QueryElement} elem - The element from the parsed query.
|
||||
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
|
||||
* @param {Map<number,number>|null} mgens - Map functions generics to query generics.
|
||||
* @param {Map<number,number>|null} mgens - Map functions generics to query generics.
|
||||
* @param {number} unboxingDepth
|
||||
*
|
||||
* @return {boolean} - Returns true if found, false otherwise.
|
||||
*/
|
||||
function checkIfInList(list, elem, whereClause, mgens) {
|
||||
function checkIfInList(list, elem, whereClause, mgens, unboxingDepth) {
|
||||
for (const entry of list) {
|
||||
if (checkType(entry, elem, whereClause, mgens)) {
|
||||
if (checkType(entry, elem, whereClause, mgens, unboxingDepth)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1897,14 +1960,23 @@ function initSearch(rawSearchIndex) {
|
||||
* @param {Row} row
|
||||
* @param {QueryElement} elem - The element from the parsed query.
|
||||
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
|
||||
* @param {Map<number,number>|null} mgens - Map functions generics to query generics.
|
||||
* @param {Map<number,number>|null} mgens - Map functions generics to query generics.
|
||||
*
|
||||
* @return {boolean} - Returns true if the type matches, false otherwise.
|
||||
*/
|
||||
function checkType(row, elem, whereClause, mgens) {
|
||||
function checkType(row, elem, whereClause, mgens, unboxingDepth) {
|
||||
if (unboxingDepth >= UNBOXING_LIMIT) {
|
||||
return false;
|
||||
}
|
||||
if (row.bindings.size === 0 && elem.bindings.size === 0) {
|
||||
if (elem.id < 0) {
|
||||
return row.id < 0 || checkIfInList(row.generics, elem, whereClause, mgens);
|
||||
if (elem.id < 0 && mgens === null) {
|
||||
return row.id < 0 || checkIfInList(
|
||||
row.generics,
|
||||
elem,
|
||||
whereClause,
|
||||
mgens,
|
||||
unboxingDepth + 1
|
||||
);
|
||||
}
|
||||
if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
|
||||
typePassesFilter(elem.typeFilter, row.ty) && elem.generics.length === 0 &&
|
||||
@ -1916,11 +1988,12 @@ function initSearch(rawSearchIndex) {
|
||||
row.generics,
|
||||
elem,
|
||||
whereClause,
|
||||
mgens
|
||||
mgens,
|
||||
unboxingDepth
|
||||
);
|
||||
}
|
||||
}
|
||||
return unifyFunctionTypes([row], [elem], whereClause, mgens);
|
||||
return unifyFunctionTypes([row], [elem], whereClause, mgens, null, unboxingDepth);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2135,9 +2208,9 @@ function initSearch(rawSearchIndex) {
|
||||
);
|
||||
if (tfpDist !== null) {
|
||||
const in_args = row.type && row.type.inputs
|
||||
&& checkIfInList(row.type.inputs, elem, row.type.where_clause);
|
||||
&& checkIfInList(row.type.inputs, elem, row.type.where_clause, null, 0);
|
||||
const returned = row.type && row.type.output
|
||||
&& checkIfInList(row.type.output, elem, row.type.where_clause);
|
||||
&& checkIfInList(row.type.output, elem, row.type.where_clause, null, 0);
|
||||
if (in_args) {
|
||||
results_in_args.max_dist = Math.max(results_in_args.max_dist || 0, tfpDist);
|
||||
const maxDist = results_in_args.size < MAX_RESULTS ?
|
||||
@ -2223,9 +2296,12 @@ function initSearch(rawSearchIndex) {
|
||||
row.type.output,
|
||||
parsedQuery.returned,
|
||||
row.type.where_clause,
|
||||
mgens
|
||||
mgens,
|
||||
null,
|
||||
0 // unboxing depth
|
||||
);
|
||||
}
|
||||
},
|
||||
0 // unboxing depth
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
|
@ -528,7 +528,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
|
||||
use NonHaltingDiagnostic::*;
|
||||
|
||||
let stacktrace =
|
||||
MiriInterpCx::generate_stacktrace_from_stack(self.threads.active_thread_stack());
|
||||
Frame::generate_stacktrace_from_stack(self.threads.active_thread_stack());
|
||||
let (stacktrace, _was_pruned) = prune_stacktrace(stacktrace, self);
|
||||
|
||||
let (title, diag_level) = match &e {
|
||||
|
245
tests/rustdoc-js/auxiliary/interner.rs
Normal file
245
tests/rustdoc-js/auxiliary/interner.rs
Normal file
@ -0,0 +1,245 @@
|
||||
#![feature(associated_type_defaults)]
|
||||
|
||||
use std::cmp::Ord;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::hash::Hash;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
pub trait Interner: Sized {
|
||||
type DefId: Copy + Debug + Hash + Ord;
|
||||
type AdtDef: Copy + Debug + Hash + Ord;
|
||||
type GenericArgs: Copy
|
||||
+ DebugWithInfcx<Self>
|
||||
+ Hash
|
||||
+ Ord
|
||||
+ IntoIterator<Item = Self::GenericArg>;
|
||||
type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Ord;
|
||||
type Term: Copy + Debug + Hash + Ord;
|
||||
type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>;
|
||||
type BoundVars: IntoIterator<Item = Self::BoundVar>;
|
||||
type BoundVar;
|
||||
type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
|
||||
type Ty: Copy
|
||||
+ DebugWithInfcx<Self>
|
||||
+ Hash
|
||||
+ Ord
|
||||
+ Into<Self::GenericArg>
|
||||
+ IntoKind<Kind = TyKind<Self>>
|
||||
+ TypeSuperVisitable<Self>
|
||||
+ Flags
|
||||
+ Ty<Self>;
|
||||
type Tys: Copy + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>;
|
||||
type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Ord;
|
||||
type ParamTy: Copy + Debug + Hash + Ord;
|
||||
type BoundTy: Copy + Debug + Hash + Ord;
|
||||
type PlaceholderTy: Copy + Debug + Hash + Ord + PlaceholderLike;
|
||||
type ErrorGuaranteed: Copy + Debug + Hash + Ord;
|
||||
type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Ord;
|
||||
type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Ord;
|
||||
type AllocId: Copy + Debug + Hash + Ord;
|
||||
type Const: Copy
|
||||
+ DebugWithInfcx<Self>
|
||||
+ Hash
|
||||
+ Ord
|
||||
+ Into<Self::GenericArg>
|
||||
+ IntoKind<Kind = ConstKind<Self>>
|
||||
+ ConstTy<Self>
|
||||
+ TypeSuperVisitable<Self>
|
||||
+ Flags
|
||||
+ Const<Self>;
|
||||
type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Ord;
|
||||
type PlaceholderConst: Copy + Debug + Hash + Ord + PlaceholderLike;
|
||||
type ParamConst: Copy + Debug + Hash + Ord;
|
||||
type BoundConst: Copy + Debug + Hash + Ord;
|
||||
type ValueConst: Copy + Debug + Hash + Ord;
|
||||
type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Ord;
|
||||
type Region: Copy
|
||||
+ DebugWithInfcx<Self>
|
||||
+ Hash
|
||||
+ Ord
|
||||
+ Into<Self::GenericArg>
|
||||
+ IntoKind<Kind = RegionKind<Self>>
|
||||
+ Flags
|
||||
+ Region<Self>;
|
||||
type EarlyParamRegion: Copy + Debug + Hash + Ord;
|
||||
type LateParamRegion: Copy + Debug + Hash + Ord;
|
||||
type BoundRegion: Copy + Debug + Hash + Ord;
|
||||
type InferRegion: Copy + DebugWithInfcx<Self> + Hash + Ord;
|
||||
type PlaceholderRegion: Copy + Debug + Hash + Ord + PlaceholderLike;
|
||||
type Predicate: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
|
||||
type TraitPredicate: Copy + Debug + Hash + Eq;
|
||||
type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
|
||||
type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
|
||||
type ProjectionPredicate: Copy + Debug + Hash + Eq;
|
||||
type NormalizesTo: Copy + Debug + Hash + Eq;
|
||||
type SubtypePredicate: Copy + Debug + Hash + Eq;
|
||||
type CoercePredicate: Copy + Debug + Hash + Eq;
|
||||
type ClosureKind: Copy + Debug + Hash + Eq;
|
||||
|
||||
// Required method
|
||||
fn mk_canonical_var_infos(
|
||||
self,
|
||||
infos: &[CanonicalVarInfo<Self>]
|
||||
) -> Self::CanonicalVars;
|
||||
}
|
||||
|
||||
pub trait DebugWithInfcx<I: Interner>: Debug {
|
||||
// Required method
|
||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
||||
this: WithInfcx<'_, Infcx, &Self>,
|
||||
f: &mut Formatter<'_>
|
||||
) -> std::fmt::Result;
|
||||
}
|
||||
|
||||
pub trait TypeVisitable<I: Interner>: Debug + Clone {
|
||||
// Required method
|
||||
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result;
|
||||
}
|
||||
|
||||
pub trait BoundVars<I: Interner> {
|
||||
// Required methods
|
||||
fn bound_vars(&self) -> I::BoundVars;
|
||||
fn has_no_bound_vars(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> {
|
||||
// Required method
|
||||
fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result;
|
||||
}
|
||||
|
||||
pub struct CanonicalVarInfo<I: Interner> {
|
||||
pub kind: CanonicalVarKind<I>,
|
||||
}
|
||||
|
||||
pub struct CanonicalVarKind<I>(std::marker::PhantomData<I>);
|
||||
|
||||
pub struct TyKind<I>(std::marker::PhantomData<I>);
|
||||
|
||||
pub trait IntoKind {
|
||||
type Kind;
|
||||
|
||||
// Required method
|
||||
fn kind(self) -> Self::Kind;
|
||||
}
|
||||
pub trait Flags {
|
||||
// Required methods
|
||||
fn flags(&self) -> TypeFlags;
|
||||
fn outer_exclusive_binder(&self) -> DebruijnIndex;
|
||||
}
|
||||
pub struct TypeFlags;
|
||||
|
||||
pub trait Ty<I: Interner<Ty = Self>> {
|
||||
// Required method
|
||||
fn new_anon_bound(
|
||||
interner: I,
|
||||
debruijn: DebruijnIndex,
|
||||
var: BoundVar
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
pub trait PlaceholderLike {
|
||||
// Required methods
|
||||
fn universe(self) -> UniverseIndex;
|
||||
fn var(self) -> BoundVar;
|
||||
fn with_updated_universe(self, ui: UniverseIndex) -> Self;
|
||||
fn new(ui: UniverseIndex, var: BoundVar) -> Self;
|
||||
}
|
||||
|
||||
pub struct UniverseIndex;
|
||||
|
||||
pub struct BoundVar;
|
||||
|
||||
pub struct ConstKind<I>(std::marker::PhantomData<I>);
|
||||
pub trait Const<I: Interner<Const = Self>> {
|
||||
// Required method
|
||||
fn new_anon_bound(
|
||||
interner: I,
|
||||
debruijn: DebruijnIndex,
|
||||
var: BoundVar,
|
||||
ty: I::Ty
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
pub trait ConstTy<I: Interner> {
|
||||
// Required method
|
||||
fn ty(self) -> I::Ty;
|
||||
}
|
||||
|
||||
pub struct DebruijnIndex;
|
||||
|
||||
pub struct RegionKind<I>(std::marker::PhantomData<I>);
|
||||
pub trait Region<I: Interner<Region = Self>> {
|
||||
// Required method
|
||||
fn new_anon_bound(
|
||||
interner: I,
|
||||
debruijn: DebruijnIndex,
|
||||
var: BoundVar
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
pub trait TypeVisitor<I: Interner>: Sized {
|
||||
type Result: VisitorResult = ();
|
||||
|
||||
// Provided methods
|
||||
fn visit_binder<T: TypeVisitable<I>>(
|
||||
&mut self,
|
||||
t: &I::Binder<T>
|
||||
) -> Self::Result { unimplemented!() }
|
||||
fn visit_ty(&mut self, t: I::Ty) -> Self::Result { unimplemented!() }
|
||||
fn visit_region(&mut self, _r: I::Region) -> Self::Result { unimplemented!() }
|
||||
fn visit_const(&mut self, c: I::Const) -> Self::Result { unimplemented!() }
|
||||
fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { unimplemented!() }
|
||||
}
|
||||
|
||||
pub trait VisitorResult {
|
||||
type Residual;
|
||||
|
||||
// Required methods
|
||||
fn output() -> Self;
|
||||
fn from_residual(residual: Self::Residual) -> Self;
|
||||
fn from_branch(b: ControlFlow<Self::Residual>) -> Self;
|
||||
fn branch(self) -> ControlFlow<Self::Residual>;
|
||||
}
|
||||
|
||||
impl VisitorResult for () {
|
||||
type Residual = ();
|
||||
fn output() -> Self {}
|
||||
fn from_residual(_: Self::Residual) -> Self {}
|
||||
fn from_branch(_: ControlFlow<Self::Residual>) -> Self {}
|
||||
fn branch(self) -> ControlFlow<Self::Residual> { ControlFlow::Continue(()) }
|
||||
}
|
||||
|
||||
pub struct WithInfcx<'a, Infcx: InferCtxtLike, T> {
|
||||
pub data: T,
|
||||
pub infcx: &'a Infcx,
|
||||
}
|
||||
|
||||
pub trait InferCtxtLike {
|
||||
type Interner: Interner;
|
||||
|
||||
// Required methods
|
||||
fn interner(&self) -> Self::Interner;
|
||||
fn universe_of_ty(&self, ty: TyVid) -> Option<UniverseIndex>;
|
||||
fn root_ty_var(&self, vid: TyVid) -> TyVid;
|
||||
fn probe_ty_var(
|
||||
&self,
|
||||
vid: TyVid
|
||||
) -> Option<<Self::Interner as Interner>::Ty>;
|
||||
fn universe_of_lt(
|
||||
&self,
|
||||
lt: <Self::Interner as Interner>::InferRegion
|
||||
) -> Option<UniverseIndex>;
|
||||
fn opportunistic_resolve_lt_var(
|
||||
&self,
|
||||
vid: <Self::Interner as Interner>::InferRegion
|
||||
) -> Option<<Self::Interner as Interner>::Region>;
|
||||
fn universe_of_ct(&self, ct: ConstVid) -> Option<UniverseIndex>;
|
||||
fn root_ct_var(&self, vid: ConstVid) -> ConstVid;
|
||||
fn probe_ct_var(
|
||||
&self,
|
||||
vid: ConstVid
|
||||
) -> Option<<Self::Interner as Interner>::Const>;
|
||||
}
|
||||
|
||||
pub struct TyVid;
|
||||
pub struct ConstVid;
|
9
tests/rustdoc-js/looks-like-rustc-interner.js
Normal file
9
tests/rustdoc-js/looks-like-rustc-interner.js
Normal file
@ -0,0 +1,9 @@
|
||||
// https://github.com/rust-lang/rust/pull/122247
|
||||
// exact-check
|
||||
|
||||
const EXPECTED = {
|
||||
'query': 'canonicalvarinfo, intoiterator -> intoiterator',
|
||||
'others': [
|
||||
{ 'path': 'looks_like_rustc_interner::Interner', 'name': 'mk_canonical_var_infos' },
|
||||
],
|
||||
};
|
5
tests/rustdoc-js/looks-like-rustc-interner.rs
Normal file
5
tests/rustdoc-js/looks-like-rustc-interner.rs
Normal file
@ -0,0 +1,5 @@
|
||||
//@ aux-crate:interner=interner.rs
|
||||
// https://github.com/rust-lang/rust/pull/122247
|
||||
extern crate interner;
|
||||
#[doc(inline)]
|
||||
pub use interner::*;
|
@ -0,0 +1,7 @@
|
||||
#![deny(unknown_or_malformed_diagnostic_attributes)]
|
||||
|
||||
#[diagnostic::unknown_attribute]
|
||||
//~^ERROR unknown diagnostic attribute
|
||||
struct Foo;
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,14 @@
|
||||
error: unknown diagnostic attribute
|
||||
--> $DIR/deny_malformed_attribute.rs:3:15
|
||||
|
|
||||
LL | #[diagnostic::unknown_attribute]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/deny_malformed_attribute.rs:1:9
|
||||
|
|
||||
LL | #![deny(unknown_or_malformed_diagnostic_attributes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
24
tests/ui/simd/const-err-trumps-simd-err.rs
Normal file
24
tests/ui/simd/const-err-trumps-simd-err.rs
Normal file
@ -0,0 +1,24 @@
|
||||
//@build-fail
|
||||
//! Make sure that monomorphization-time const errors from `static_assert` take priority over the
|
||||
//! error from simd_extract. Basically this checks that if a const fails to evaluate in some
|
||||
//! function, we don't bother codegen'ing the function.
|
||||
#![feature(generic_arg_infer)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(repr_simd)]
|
||||
#![feature(inline_const)]
|
||||
use std::intrinsics::simd::*;
|
||||
|
||||
#[repr(simd)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct int8x4_t(u8,u8,u8,u8);
|
||||
|
||||
fn get_elem<const LANE: u32>(a: int8x4_t) -> u8 {
|
||||
const { assert!(LANE < 4); } // the error should be here...
|
||||
//~^ ERROR failed
|
||||
//~| assertion failed
|
||||
unsafe { simd_extract(a, LANE) } // ...not here
|
||||
}
|
||||
|
||||
fn main() {
|
||||
get_elem::<4>(int8x4_t(0,0,0,0));
|
||||
}
|
17
tests/ui/simd/const-err-trumps-simd-err.stderr
Normal file
17
tests/ui/simd/const-err-trumps-simd-err.stderr
Normal file
@ -0,0 +1,17 @@
|
||||
error[E0080]: evaluation of `get_elem::<4>::{constant#0}` failed
|
||||
--> $DIR/const-err-trumps-simd-err.rs:16:13
|
||||
|
|
||||
LL | const { assert!(LANE < 4); } // the error should be here...
|
||||
| ^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: LANE < 4', $DIR/const-err-trumps-simd-err.rs:16:13
|
||||
|
|
||||
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
note: the above error was encountered while instantiating `fn get_elem::<4>`
|
||||
--> $DIR/const-err-trumps-simd-err.rs:23:5
|
||||
|
|
||||
LL | get_elem::<4>(int8x4_t(0,0,0,0));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
@ -1,5 +1,5 @@
|
||||
//! We evaluate `1 + 2` with `Reveal::All` during typeck, causing
|
||||
//! us to to get the concrete type of `Bar` while computing it.
|
||||
//! us to get the concrete type of `Bar` while computing it.
|
||||
//! This again requires type checking `foo`.
|
||||
#![feature(type_alias_impl_trait)]
|
||||
type Bar = impl Sized;
|
||||
|
Loading…
Reference in New Issue
Block a user