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:
bors 2024-03-14 16:36:02 +00:00
commit 30f74ff0dc
33 changed files with 728 additions and 253 deletions

View File

@ -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())
}

View File

@ -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

View File

@ -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);

View File

@ -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}

View File

@ -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,

View File

@ -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 },
)
}

View File

@ -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;

View File

@ -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>,

View File

@ -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())
}
}

View File

@ -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;

View File

@ -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};

View File

@ -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>(

View File

@ -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!(

View File

@ -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! {

View File

@ -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),

View File

@ -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 {

View File

@ -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,

View File

@ -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", || {

View File

@ -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)

View File

@ -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>,

View File

@ -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
}
}

View File

@ -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

View File

@ -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:

View File

@ -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;
}

View File

@ -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 {

View 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;

View 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' },
],
};

View 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::*;

View File

@ -0,0 +1,7 @@
#![deny(unknown_or_malformed_diagnostic_attributes)]
#[diagnostic::unknown_attribute]
//~^ERROR unknown diagnostic attribute
struct Foo;
fn main() {}

View File

@ -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

View 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));
}

View 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`.

View File

@ -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;