mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 15:01:51 +00:00
Auto merge of #108521 - matthiaskrgr:rollup-exkviev, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #108319 (Don't project specializable RPITIT projection) - #108364 (Unify validity checks into a single query) - #108463 (bootstrap: Update the output of the `check` descriptions) - #108477 (Make `match` arm comma suggestion more clear) - #108486 (Merge diagnostic_items duplicate diagnostics) - #108494 (Clean up JS files code a bit) - #108500 (update Miri) - #108502 (Don't trigger error for ReError when other region is empty.) - #108513 (Remove `@nagisa` from review rotation) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
49b9cc5139
10
Cargo.lock
10
Cargo.lock
@ -444,7 +444,7 @@ dependencies = [
|
||||
"directories",
|
||||
"rustc-build-sysroot",
|
||||
"rustc-workspace-hack",
|
||||
"rustc_tools_util 0.2.1",
|
||||
"rustc_tools_util",
|
||||
"rustc_version",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -738,7 +738,7 @@ dependencies = [
|
||||
"regex",
|
||||
"rustc-semver",
|
||||
"rustc-workspace-hack",
|
||||
"rustc_tools_util 0.3.0",
|
||||
"rustc_tools_util",
|
||||
"semver",
|
||||
"serde",
|
||||
"syn",
|
||||
@ -4725,12 +4725,6 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_tools_util"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "598f48ce2a421542b3e64828aa742b687cc1b91d2f96591cfdb7ac5988cd6366"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_tools_util"
|
||||
version = "0.3.0"
|
||||
|
@ -1505,14 +1505,6 @@ pub struct PointeeInfo {
|
||||
pub safe: Option<PointerKind>,
|
||||
}
|
||||
|
||||
/// Used in `might_permit_raw_init` to indicate the kind of initialisation
|
||||
/// that is checked to be valid
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum InitKind {
|
||||
Zero,
|
||||
UninitMitigated0x01Fill,
|
||||
}
|
||||
|
||||
impl LayoutS {
|
||||
/// Returns `true` if the layout corresponds to an unsized type.
|
||||
pub fn is_unsized(&self) -> bool {
|
||||
|
@ -21,7 +21,8 @@ mod simd;
|
||||
pub(crate) use cpuid::codegen_cpuid_call;
|
||||
pub(crate) use llvm::codegen_llvm_intrinsic_call;
|
||||
|
||||
use rustc_middle::ty::layout::HasParamEnv;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::{HasParamEnv, InitKind};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
@ -642,7 +643,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
||||
if intrinsic == sym::assert_zero_valid
|
||||
&& !fx
|
||||
.tcx
|
||||
.permits_zero_init(fx.param_env().and(ty))
|
||||
.check_validity_of_init((InitKind::Zero, fx.param_env().and(ty)))
|
||||
.expect("expected to have layout during codegen")
|
||||
{
|
||||
with_no_trimmed_paths!({
|
||||
@ -661,7 +662,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
||||
if intrinsic == sym::assert_mem_uninitialized_valid
|
||||
&& !fx
|
||||
.tcx
|
||||
.permits_uninit_init(fx.param_env().and(ty))
|
||||
.check_validity_of_init((
|
||||
InitKind::UninitMitigated0x01Fill,
|
||||
fx.param_env().and(ty),
|
||||
))
|
||||
.expect("expected to have layout during codegen")
|
||||
{
|
||||
with_no_trimmed_paths!({
|
||||
|
@ -14,7 +14,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, InitKind, LayoutOf};
|
||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt};
|
||||
use rustc_session::config::OptLevel;
|
||||
@ -676,11 +676,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
Inhabited => layout.abi.is_uninhabited(),
|
||||
ZeroValid => !bx
|
||||
.tcx()
|
||||
.permits_zero_init(bx.param_env().and(ty))
|
||||
.check_validity_of_init((InitKind::Zero, bx.param_env().and(ty)))
|
||||
.expect("expected to have layout during codegen"),
|
||||
MemUninitializedValid => !bx
|
||||
.tcx()
|
||||
.permits_uninit_init(bx.param_env().and(ty))
|
||||
.check_validity_of_init((
|
||||
InitKind::UninitMitigated0x01Fill,
|
||||
bx.param_env().and(ty),
|
||||
))
|
||||
.expect("expected to have layout during codegen"),
|
||||
};
|
||||
Some(if do_panic {
|
||||
|
@ -11,7 +11,7 @@ use rustc_middle::mir::{
|
||||
BinOp, NonDivergingIntrinsic,
|
||||
};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::LayoutOf as _;
|
||||
use rustc_middle::ty::layout::{InitKind, LayoutOf as _};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
@ -437,7 +437,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
if intrinsic_name == sym::assert_zero_valid {
|
||||
let should_panic = !self
|
||||
.tcx
|
||||
.permits_zero_init(self.param_env.and(ty))
|
||||
.check_validity_of_init((InitKind::Zero, self.param_env.and(ty)))
|
||||
.map_err(|_| err_inval!(TooGeneric))?;
|
||||
|
||||
if should_panic {
|
||||
@ -454,7 +454,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
if intrinsic_name == sym::assert_mem_uninitialized_valid {
|
||||
let should_panic = !self
|
||||
.tcx
|
||||
.permits_uninit_init(self.param_env.and(ty))
|
||||
.check_validity_of_init((
|
||||
InitKind::UninitMitigated0x01Fill,
|
||||
self.param_env.and(ty),
|
||||
))
|
||||
.map_err(|_| err_inval!(TooGeneric))?;
|
||||
|
||||
if should_panic {
|
||||
|
@ -38,7 +38,6 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
|
||||
use rustc_macros::fluent_messages;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_target::abi::InitKind;
|
||||
|
||||
fluent_messages! { "../locales/en-US.ftl" }
|
||||
|
||||
@ -62,9 +61,7 @@ pub fn provide(providers: &mut Providers) {
|
||||
let (param_env, value) = param_env_and_value.into_parts();
|
||||
const_eval::deref_mir_constant(tcx, param_env, value)
|
||||
};
|
||||
providers.permits_uninit_init = |tcx, param_env_and_ty| {
|
||||
util::might_permit_raw_init(tcx, param_env_and_ty, InitKind::UninitMitigated0x01Fill)
|
||||
providers.check_validity_of_init = |tcx, (init_kind, param_env_and_ty)| {
|
||||
util::might_permit_raw_init(tcx, init_kind, param_env_and_ty)
|
||||
};
|
||||
providers.permits_zero_init =
|
||||
|tcx, param_env_and_ty| util::might_permit_raw_init(tcx, param_env_and_ty, InitKind::Zero);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::layout::{InitKind, LayoutCx, LayoutError, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_session::Limit;
|
||||
use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
|
||||
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
|
||||
|
||||
use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
|
||||
use crate::interpret::{InterpCx, MemoryKind, OpTy};
|
||||
@ -20,8 +20,8 @@ use crate::interpret::{InterpCx, MemoryKind, OpTy};
|
||||
/// to the full uninit check).
|
||||
pub fn might_permit_raw_init<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
kind: InitKind,
|
||||
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
if tcx.sess.opts.unstable_opts.strict_init_checks {
|
||||
might_permit_raw_init_strict(tcx.layout_of(param_env_and_ty)?, tcx, kind)
|
||||
|
@ -648,6 +648,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||
tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
|
||||
)
|
||||
.fold_with(&mut collector);
|
||||
|
||||
debug_assert_ne!(
|
||||
collector.types.len(),
|
||||
0,
|
||||
"expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`"
|
||||
);
|
||||
|
||||
let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
|
||||
trait_sig.error_reported()?;
|
||||
let trait_return_ty = trait_sig.output();
|
||||
|
@ -438,7 +438,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
||||
}
|
||||
(VarValue::Value(a), VarValue::Empty(_)) => {
|
||||
match *a {
|
||||
ReLateBound(..) | ReErased | ReError(_) => {
|
||||
// this is always on an error path,
|
||||
// so it doesn't really matter if it's shorter or longer than an empty region
|
||||
ReError(_) => false,
|
||||
|
||||
ReLateBound(..) | ReErased => {
|
||||
bug!("cannot relate region: {:?}", a);
|
||||
}
|
||||
|
||||
@ -467,7 +471,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
||||
}
|
||||
(VarValue::Empty(a_ui), VarValue::Value(b)) => {
|
||||
match *b {
|
||||
ReLateBound(..) | ReErased | ReError(_) => {
|
||||
// this is always on an error path,
|
||||
// so it doesn't really matter if it's shorter or longer than an empty region
|
||||
ReError(_) => false,
|
||||
|
||||
ReLateBound(..) | ReErased => {
|
||||
bug!("cannot relate region: {:?}", b);
|
||||
}
|
||||
|
||||
|
@ -64,13 +64,17 @@ impl ModuleItems {
|
||||
self.foreign_items.iter().copied()
|
||||
}
|
||||
|
||||
pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
|
||||
pub fn owners(&self) -> impl Iterator<Item = OwnerId> + '_ {
|
||||
self.items
|
||||
.iter()
|
||||
.map(|id| id.owner_id.def_id)
|
||||
.chain(self.trait_items.iter().map(|id| id.owner_id.def_id))
|
||||
.chain(self.impl_items.iter().map(|id| id.owner_id.def_id))
|
||||
.chain(self.foreign_items.iter().map(|id| id.owner_id.def_id))
|
||||
.map(|id| id.owner_id)
|
||||
.chain(self.trait_items.iter().map(|id| id.owner_id))
|
||||
.chain(self.impl_items.iter().map(|id| id.owner_id))
|
||||
.chain(self.foreign_items.iter().map(|id| id.owner_id))
|
||||
}
|
||||
|
||||
pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
|
||||
self.owners().map(|id| id.def_id)
|
||||
}
|
||||
|
||||
pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) {
|
||||
|
@ -4,8 +4,9 @@ use crate::infer::canonical::Canonical;
|
||||
use crate::mir;
|
||||
use crate::traits;
|
||||
use crate::ty::fast_reject::SimplifiedType;
|
||||
use crate::ty::layout::{InitKind, TyAndLayout};
|
||||
use crate::ty::subst::{GenericArg, SubstsRef};
|
||||
use crate::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_hir::hir_id::{HirId, OwnerId};
|
||||
use rustc_query_system::query::{DefaultCacheSelector, SingleCacheSelector, VecCacheSelector};
|
||||
@ -696,3 +697,24 @@ impl Key for HirId {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (InitKind, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) {
|
||||
type CacheSelector = DefaultCacheSelector<Self>;
|
||||
|
||||
// Just forward to `Ty<'tcx>`
|
||||
#[inline(always)]
|
||||
fn query_crate_is_local(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
|
||||
fn ty_adt_id(&self) -> Option<DefId> {
|
||||
match self.1.value.kind() {
|
||||
ty::Adt(adt, _) => Some(adt.did()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2173,12 +2173,8 @@ rustc_queries! {
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
query permits_uninit_init(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<bool, ty::layout::LayoutError<'tcx>> {
|
||||
desc { "checking to see if `{}` permits being left uninit", key.value }
|
||||
}
|
||||
|
||||
query permits_zero_init(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<bool, ty::layout::LayoutError<'tcx>> {
|
||||
desc { "checking to see if `{}` permits being left zeroed", key.value }
|
||||
query check_validity_of_init(key: (InitKind, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, ty::layout::LayoutError<'tcx>> {
|
||||
desc { "checking to see if `{}` permits being left {}", key.1.value, key.0 }
|
||||
}
|
||||
|
||||
query compare_impl_const(
|
||||
|
@ -169,6 +169,23 @@ pub const FAT_PTR_EXTRA: usize = 1;
|
||||
/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
|
||||
pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
|
||||
|
||||
/// Used in `might_permit_raw_init` to indicate the kind of initialisation
|
||||
/// that is checked to be valid
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
|
||||
pub enum InitKind {
|
||||
Zero,
|
||||
UninitMitigated0x01Fill,
|
||||
}
|
||||
|
||||
impl fmt::Display for InitKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Zero => f.write_str("zeroed"),
|
||||
Self::UninitMitigated0x01Fill => f.write_str("filled with 0x01"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
|
||||
pub enum LayoutError<'tcx> {
|
||||
Unknown(Ty<'tcx>),
|
||||
|
@ -32,6 +32,7 @@ use crate::traits::specialization_graph;
|
||||
use crate::traits::{self, ImplSource};
|
||||
use crate::ty::context::TyCtxtFeed;
|
||||
use crate::ty::fast_reject::SimplifiedType;
|
||||
use crate::ty::layout::InitKind;
|
||||
use crate::ty::subst::{GenericArg, SubstsRef};
|
||||
use crate::ty::util::AlwaysRequiresDrop;
|
||||
use crate::ty::GeneratorDiagnosticData;
|
||||
|
@ -6,8 +6,8 @@ use rustc_middle::mir::{
|
||||
BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue,
|
||||
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp,
|
||||
};
|
||||
use rustc_middle::ty::layout::LayoutError;
|
||||
use rustc_middle::ty::{self, ParamEnv, ParamEnvAnd, SubstsRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::layout::InitKind;
|
||||
use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
pub struct InstCombine;
|
||||
@ -234,16 +234,15 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
|
||||
}
|
||||
let ty = substs.type_at(0);
|
||||
|
||||
// Check this is a foldable intrinsic before we query the layout of our generic parameter
|
||||
let Some(assert_panics) = intrinsic_assert_panics(intrinsic_name) else { return; };
|
||||
match assert_panics(self.tcx, self.param_env.and(ty)) {
|
||||
// We don't know the layout, don't touch the assertion
|
||||
Err(_) => {}
|
||||
Ok(true) => {
|
||||
let known_is_valid = intrinsic_assert_panics(self.tcx, self.param_env, ty, intrinsic_name);
|
||||
match known_is_valid {
|
||||
// We don't know the layout or it's not validity assertion at all, don't touch it
|
||||
None => {}
|
||||
Some(true) => {
|
||||
// If we know the assert panics, indicate to later opts that the call diverges
|
||||
*target = None;
|
||||
}
|
||||
Ok(false) => {
|
||||
Some(false) => {
|
||||
// If we know the assert does not panic, turn the call into a Goto
|
||||
terminator.kind = TerminatorKind::Goto { target: *target_block };
|
||||
}
|
||||
@ -252,33 +251,21 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
|
||||
}
|
||||
|
||||
fn intrinsic_assert_panics<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
intrinsic_name: Symbol,
|
||||
) -> Option<fn(TyCtxt<'tcx>, ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<bool, LayoutError<'tcx>>> {
|
||||
fn inhabited_predicate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
Ok(tcx.layout_of(param_env_and_ty)?.abi.is_uninhabited())
|
||||
}
|
||||
fn zero_valid_predicate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
Ok(!tcx.permits_zero_init(param_env_and_ty)?)
|
||||
}
|
||||
fn mem_uninitialized_valid_predicate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
Ok(!tcx.permits_uninit_init(param_env_and_ty)?)
|
||||
}
|
||||
|
||||
match intrinsic_name {
|
||||
sym::assert_inhabited => Some(inhabited_predicate),
|
||||
sym::assert_zero_valid => Some(zero_valid_predicate),
|
||||
sym::assert_mem_uninitialized_valid => Some(mem_uninitialized_valid_predicate),
|
||||
_ => None,
|
||||
}
|
||||
) -> Option<bool> {
|
||||
Some(match intrinsic_name {
|
||||
sym::assert_inhabited => tcx.layout_of(param_env.and(ty)).ok()?.abi.is_uninhabited(),
|
||||
sym::assert_zero_valid => {
|
||||
!tcx.check_validity_of_init((InitKind::Zero, param_env.and(ty))).ok()?
|
||||
}
|
||||
sym::assert_mem_uninitialized_valid => !tcx
|
||||
.check_validity_of_init((InitKind::UninitMitigated0x01Fill, param_env.and(ty)))
|
||||
.ok()?,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_rust_intrinsic<'tcx>(
|
||||
|
@ -220,7 +220,7 @@ parse_match_arm_body_without_braces = `match` arm body without braces
|
||||
[one] statement
|
||||
*[other] statements
|
||||
} with a body
|
||||
.suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression
|
||||
.suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression
|
||||
|
||||
parse_inclusive_range_extra_equals = unexpected `=` after inclusive range
|
||||
.suggestion_remove_eq = use `..=` instead
|
||||
|
@ -402,9 +402,6 @@ passes_invalid_attr_at_crate_level =
|
||||
`{$name}` attribute cannot be used at crate level
|
||||
.suggestion = perhaps you meant to use an outer attribute
|
||||
|
||||
passes_duplicate_diagnostic_item =
|
||||
duplicate diagnostic item found: `{$name}`.
|
||||
|
||||
passes_duplicate_diagnostic_item_in_crate =
|
||||
duplicate diagnostic item in crate `{$crate_name}`: `{$name}`.
|
||||
.note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
|
||||
|
@ -11,19 +11,19 @@
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_hir::diagnostic_items::DiagnosticItems;
|
||||
use rustc_hir::OwnerId;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_span::symbol::{kw::Empty, sym, Symbol};
|
||||
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
use crate::errors::{DuplicateDiagnosticItem, DuplicateDiagnosticItemInCrate};
|
||||
use crate::errors::DuplicateDiagnosticItemInCrate;
|
||||
|
||||
fn observe_item(tcx: TyCtxt<'_>, diagnostic_items: &mut DiagnosticItems, def_id: LocalDefId) {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let attrs = tcx.hir().attrs(hir_id);
|
||||
fn observe_item<'tcx>(tcx: TyCtxt<'tcx>, diagnostic_items: &mut DiagnosticItems, owner: OwnerId) {
|
||||
let attrs = tcx.hir().attrs(owner.into());
|
||||
if let Some(name) = extract(attrs) {
|
||||
// insert into our table
|
||||
collect_item(tcx, diagnostic_items, name, def_id.to_def_id());
|
||||
collect_item(tcx, diagnostic_items, name, owner.to_def_id());
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,23 +31,29 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item
|
||||
items.id_to_name.insert(item_def_id, name);
|
||||
if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
|
||||
if original_def_id != item_def_id {
|
||||
let orig_span = tcx.hir().span_if_local(original_def_id);
|
||||
let orig_crate_name =
|
||||
orig_span.is_none().then(|| tcx.crate_name(original_def_id.krate));
|
||||
match tcx.hir().span_if_local(item_def_id) {
|
||||
Some(span) => tcx.sess.emit_err(DuplicateDiagnosticItem { span, name }),
|
||||
None => tcx.sess.emit_err(DuplicateDiagnosticItemInCrate {
|
||||
span: orig_span,
|
||||
orig_crate_name: orig_crate_name.unwrap_or(Empty),
|
||||
have_orig_crate_name: orig_crate_name.map(|_| ()),
|
||||
crate_name: tcx.crate_name(item_def_id.krate),
|
||||
name,
|
||||
}),
|
||||
};
|
||||
report_duplicate_item(tcx, name, original_def_id, item_def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_duplicate_item(
|
||||
tcx: TyCtxt<'_>,
|
||||
name: Symbol,
|
||||
original_def_id: DefId,
|
||||
item_def_id: DefId,
|
||||
) {
|
||||
let orig_span = tcx.hir().span_if_local(original_def_id);
|
||||
let duplicate_span = tcx.hir().span_if_local(item_def_id);
|
||||
tcx.sess.emit_err(DuplicateDiagnosticItemInCrate {
|
||||
duplicate_span,
|
||||
orig_span,
|
||||
crate_name: tcx.crate_name(item_def_id.krate),
|
||||
orig_crate_name: tcx.crate_name(original_def_id.krate),
|
||||
different_crates: (item_def_id.krate != original_def_id.krate).then_some(()),
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
||||
/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.
|
||||
fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
|
||||
attrs.iter().find_map(|attr| {
|
||||
@ -64,21 +70,8 @@ fn diagnostic_items(tcx: TyCtxt<'_>, cnum: CrateNum) -> DiagnosticItems {
|
||||
|
||||
// Collect diagnostic items in this crate.
|
||||
let crate_items = tcx.hir_crate_items(());
|
||||
|
||||
for id in crate_items.items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
|
||||
}
|
||||
|
||||
for id in crate_items.trait_items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
|
||||
}
|
||||
|
||||
for id in crate_items.impl_items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
|
||||
}
|
||||
|
||||
for id in crate_items.foreign_items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
|
||||
for id in crate_items.owners() {
|
||||
observe_item(tcx, &mut diagnostic_items, id);
|
||||
}
|
||||
|
||||
diagnostic_items
|
||||
|
@ -809,23 +809,17 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_duplicate_diagnostic_item)]
|
||||
pub struct DuplicateDiagnosticItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_duplicate_diagnostic_item_in_crate)]
|
||||
pub struct DuplicateDiagnosticItemInCrate {
|
||||
#[primary_span]
|
||||
pub duplicate_span: Option<Span>,
|
||||
#[note(passes_diagnostic_item_first_defined)]
|
||||
pub span: Option<Span>,
|
||||
pub orig_crate_name: Symbol,
|
||||
pub orig_span: Option<Span>,
|
||||
#[note]
|
||||
pub have_orig_crate_name: Option<()>,
|
||||
pub different_crates: Option<()>,
|
||||
pub crate_name: Symbol,
|
||||
pub orig_crate_name: Symbol,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
|
@ -1307,21 +1307,38 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
|
||||
let _ = selcx.infcx.commit_if_ok(|_| {
|
||||
match selcx.select(&obligation.with(tcx, trait_predicate)) {
|
||||
Ok(Some(super::ImplSource::UserDefined(data))) => {
|
||||
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
|
||||
Ok(())
|
||||
let Ok(leaf_def) = specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) else {
|
||||
return Err(());
|
||||
};
|
||||
// Only reveal a specializable default if we're past type-checking
|
||||
// and the obligation is monomorphic, otherwise passes such as
|
||||
// transmute checking and polymorphic MIR optimizations could
|
||||
// get a result which isn't correct for all monomorphizations.
|
||||
if leaf_def.is_final()
|
||||
|| (obligation.param_env.reveal() == Reveal::All
|
||||
&& !selcx
|
||||
.infcx
|
||||
.resolve_vars_if_possible(obligation.predicate.trait_ref(tcx))
|
||||
.still_further_specializable())
|
||||
{
|
||||
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
candidate_set.mark_ambiguous();
|
||||
return Err(());
|
||||
Err(())
|
||||
}
|
||||
Ok(Some(_)) => {
|
||||
// Don't know enough about the impl to provide a useful signature
|
||||
return Err(());
|
||||
Err(())
|
||||
}
|
||||
Err(e) => {
|
||||
debug!(error = ?e, "selection error");
|
||||
candidate_set.mark_error(e);
|
||||
return Err(());
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -105,10 +105,15 @@ impl Step for Std {
|
||||
cargo.arg("--lib");
|
||||
}
|
||||
|
||||
builder.info(&format!(
|
||||
"Checking stage{} library artifacts ({} -> {})",
|
||||
builder.top_stage, &compiler.host, target
|
||||
));
|
||||
let msg = if compiler.host == target {
|
||||
format!("Checking stage{} library artifacts ({target})", builder.top_stage)
|
||||
} else {
|
||||
format!(
|
||||
"Checking stage{} library artifacts ({} -> {})",
|
||||
builder.top_stage, &compiler.host, target
|
||||
)
|
||||
};
|
||||
builder.info(&msg);
|
||||
run_cargo(
|
||||
builder,
|
||||
cargo,
|
||||
@ -162,10 +167,18 @@ impl Step for Std {
|
||||
cargo.arg("-p").arg(krate.name);
|
||||
}
|
||||
|
||||
builder.info(&format!(
|
||||
"Checking stage{} library test/bench/example targets ({} -> {})",
|
||||
builder.top_stage, &compiler.host, target
|
||||
));
|
||||
let msg = if compiler.host == target {
|
||||
format!(
|
||||
"Checking stage{} library test/bench/example targets ({target})",
|
||||
builder.top_stage
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"Checking stage{} library test/bench/example targets ({} -> {})",
|
||||
builder.top_stage, &compiler.host, target
|
||||
)
|
||||
};
|
||||
builder.info(&msg);
|
||||
run_cargo(
|
||||
builder,
|
||||
cargo,
|
||||
@ -239,10 +252,15 @@ impl Step for Rustc {
|
||||
cargo.arg("-p").arg(krate.name);
|
||||
}
|
||||
|
||||
builder.info(&format!(
|
||||
"Checking stage{} compiler artifacts ({} -> {})",
|
||||
builder.top_stage, &compiler.host, target
|
||||
));
|
||||
let msg = if compiler.host == target {
|
||||
format!("Checking stage{} compiler artifacts ({target})", builder.top_stage)
|
||||
} else {
|
||||
format!(
|
||||
"Checking stage{} compiler artifacts ({} -> {})",
|
||||
builder.top_stage, &compiler.host, target
|
||||
)
|
||||
};
|
||||
builder.info(&msg);
|
||||
run_cargo(
|
||||
builder,
|
||||
cargo,
|
||||
@ -299,10 +317,15 @@ impl Step for CodegenBackend {
|
||||
.arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
|
||||
rustc_cargo_env(builder, &mut cargo, target);
|
||||
|
||||
builder.info(&format!(
|
||||
"Checking stage{} {} artifacts ({} -> {})",
|
||||
builder.top_stage, backend, &compiler.host.triple, target.triple
|
||||
));
|
||||
let msg = if compiler.host == target {
|
||||
format!("Checking stage{} {} artifacts ({target})", builder.top_stage, backend)
|
||||
} else {
|
||||
format!(
|
||||
"Checking stage{} {} library ({} -> {})",
|
||||
builder.top_stage, backend, &compiler.host.triple, target.triple
|
||||
)
|
||||
};
|
||||
builder.info(&msg);
|
||||
|
||||
run_cargo(
|
||||
builder,
|
||||
@ -362,10 +385,15 @@ impl Step for RustAnalyzer {
|
||||
cargo.arg("--benches");
|
||||
}
|
||||
|
||||
builder.info(&format!(
|
||||
"Checking stage{} {} artifacts ({} -> {})",
|
||||
compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
|
||||
));
|
||||
let msg = if compiler.host == target {
|
||||
format!("Checking stage{} {} artifacts ({target})", compiler.stage, "rust-analyzer")
|
||||
} else {
|
||||
format!(
|
||||
"Checking stage{} {} artifacts ({} -> {})",
|
||||
compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
|
||||
)
|
||||
};
|
||||
builder.info(&msg);
|
||||
run_cargo(
|
||||
builder,
|
||||
cargo,
|
||||
@ -432,14 +460,18 @@ macro_rules! tool_check_step {
|
||||
// NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
|
||||
// See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
|
||||
cargo.rustflag("-Zunstable-options");
|
||||
|
||||
builder.info(&format!(
|
||||
"Checking stage{} {} artifacts ({} -> {})",
|
||||
builder.top_stage,
|
||||
stringify!($name).to_lowercase(),
|
||||
&compiler.host.triple,
|
||||
target.triple
|
||||
));
|
||||
let msg = if compiler.host == target {
|
||||
format!("Checking stage{} {} artifacts ({target})", builder.top_stage, stringify!($name).to_lowercase())
|
||||
} else {
|
||||
format!(
|
||||
"Checking stage{} {} artifacts ({} -> {})",
|
||||
builder.top_stage,
|
||||
stringify!($name).to_lowercase(),
|
||||
&compiler.host.triple,
|
||||
target.triple
|
||||
)
|
||||
};
|
||||
builder.info(&msg);
|
||||
run_cargo(
|
||||
builder,
|
||||
cargo,
|
||||
|
@ -463,11 +463,10 @@ function initSearch(rawSearchIndex) {
|
||||
* @param {ParserState} parserState
|
||||
*/
|
||||
function parseInput(query, parserState) {
|
||||
let c, before;
|
||||
let foundStopChar = true;
|
||||
|
||||
while (parserState.pos < parserState.length) {
|
||||
c = parserState.userQuery[parserState.pos];
|
||||
const c = parserState.userQuery[parserState.pos];
|
||||
if (isStopCharacter(c)) {
|
||||
foundStopChar = true;
|
||||
if (isSeparatorCharacter(c)) {
|
||||
@ -506,7 +505,7 @@ function initSearch(rawSearchIndex) {
|
||||
}
|
||||
throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``);
|
||||
}
|
||||
before = query.elems.length;
|
||||
const before = query.elems.length;
|
||||
getNextElem(query, parserState, query.elems, false);
|
||||
if (query.elems.length === before) {
|
||||
// Nothing was added, weird... Let's increase the position to not remain stuck.
|
||||
@ -515,7 +514,6 @@ function initSearch(rawSearchIndex) {
|
||||
foundStopChar = false;
|
||||
}
|
||||
while (parserState.pos < parserState.length) {
|
||||
c = parserState.userQuery[parserState.pos];
|
||||
if (isReturnArrow(parserState)) {
|
||||
parserState.pos += 2;
|
||||
// Get returned elements.
|
||||
@ -1940,7 +1938,6 @@ function initSearch(rawSearchIndex) {
|
||||
*/
|
||||
const searchWords = [];
|
||||
const charA = "A".charCodeAt(0);
|
||||
let i, word;
|
||||
let currentIndex = 0;
|
||||
let id = 0;
|
||||
|
||||
@ -2035,7 +2032,7 @@ function initSearch(rawSearchIndex) {
|
||||
// convert `rawPaths` entries into object form
|
||||
// generate normalizedPaths for function search mode
|
||||
let len = paths.length;
|
||||
for (i = 0; i < len; ++i) {
|
||||
for (let i = 0; i < len; ++i) {
|
||||
lowercasePaths.push({ty: paths[i][0], name: paths[i][1].toLowerCase()});
|
||||
paths[i] = {ty: paths[i][0], name: paths[i][1]};
|
||||
}
|
||||
@ -2049,16 +2046,14 @@ function initSearch(rawSearchIndex) {
|
||||
// faster analysis operations
|
||||
len = itemTypes.length;
|
||||
let lastPath = "";
|
||||
for (i = 0; i < len; ++i) {
|
||||
for (let i = 0; i < len; ++i) {
|
||||
let word = "";
|
||||
// This object should have exactly the same set of fields as the "crateRow"
|
||||
// object defined above.
|
||||
if (typeof itemNames[i] === "string") {
|
||||
word = itemNames[i].toLowerCase();
|
||||
searchWords.push(word);
|
||||
} else {
|
||||
word = "";
|
||||
searchWords.push("");
|
||||
}
|
||||
searchWords.push(word);
|
||||
const row = {
|
||||
crate: crate,
|
||||
ty: itemTypes.charCodeAt(i) - charA,
|
||||
|
@ -117,8 +117,7 @@ function createSourceSidebar() {
|
||||
sidebar.appendChild(title);
|
||||
Object.keys(sourcesIndex).forEach(key => {
|
||||
sourcesIndex[key][NAME_OFFSET] = key;
|
||||
hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "",
|
||||
hasFoundFile);
|
||||
hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "", hasFoundFile);
|
||||
});
|
||||
|
||||
container.appendChild(sidebar);
|
||||
|
@ -242,6 +242,13 @@ josh-proxy --local=$HOME/.cache/josh --remote=https://github.com --no-background
|
||||
|
||||
This uses a directory `$HOME/.cache/josh` as a cache, to speed up repeated pulling/pushing.
|
||||
|
||||
To make josh push via ssh instead of https, you can add the following to your `.gitconfig`:
|
||||
|
||||
```toml
|
||||
[url "git@github.com:"]
|
||||
pushInsteadOf = https://github.com/
|
||||
```
|
||||
|
||||
### Importing changes from the rustc repo
|
||||
|
||||
Josh needs to be running, as described above.
|
||||
|
@ -213,7 +213,9 @@ degree documented below):
|
||||
- The best-supported target is `x86_64-unknown-linux-gnu`. Miri releases are
|
||||
blocked on things working with this target. Most other Linux targets should
|
||||
also work well; we do run the test suite on `i686-unknown-linux-gnu` as a
|
||||
32bit target and `mips64-unknown-linux-gnuabi64` as a big-endian target.
|
||||
32bit target and `mips64-unknown-linux-gnuabi64` as a big-endian target, as
|
||||
well as the ARM targets `aarch64-unknown-linux-gnu` and
|
||||
`arm-unknown-linux-gnueabi`.
|
||||
- `x86_64-apple-darwin` should work basically as well as Linux. We also test
|
||||
`aarch64-apple-darwin`. However, we might ship Miri with a nightly even when
|
||||
some features on these targets regress.
|
||||
@ -590,7 +592,7 @@ extern "Rust" {
|
||||
/// `out` must point to at least `out_size` many bytes, and the result will be stored there
|
||||
/// with a null terminator.
|
||||
/// Returns 0 if the `out` buffer was large enough, and the required size otherwise.
|
||||
fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
|
||||
fn miri_host_to_target_path(path: *const std::ffi::c_char, out: *mut std::ffi::c_char, out_size: usize) -> usize;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -193,9 +193,9 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_tools_util"
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "598f48ce2a421542b3e64828aa742b687cc1b91d2f96591cfdb7ac5988cd6366"
|
||||
checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
|
@ -30,4 +30,4 @@ rustc-workspace-hack = "1.0.0"
|
||||
serde = { version = "*", features = ["derive"] }
|
||||
|
||||
[build-dependencies]
|
||||
rustc_tools_util = "0.2"
|
||||
rustc_tools_util = "0.3"
|
||||
|
@ -2,12 +2,5 @@ fn main() {
|
||||
// Don't rebuild miri when nothing changed.
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
// gather version info
|
||||
println!(
|
||||
"cargo:rustc-env=GIT_HASH={}",
|
||||
rustc_tools_util::get_commit_hash().unwrap_or_default()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=COMMIT_DATE={}",
|
||||
rustc_tools_util::get_commit_date().unwrap_or_default()
|
||||
);
|
||||
rustc_tools_util::setup_version_info!();
|
||||
}
|
||||
|
@ -104,6 +104,7 @@ run_tests
|
||||
case $HOST_TARGET in
|
||||
x86_64-unknown-linux-gnu)
|
||||
MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
|
||||
MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
|
||||
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
|
||||
MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
|
||||
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
|
||||
@ -118,6 +119,7 @@ case $HOST_TARGET in
|
||||
MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests
|
||||
;;
|
||||
i686-pc-windows-msvc)
|
||||
MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests
|
||||
MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests
|
||||
MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests
|
||||
;;
|
||||
|
@ -1 +1 @@
|
||||
c54c8cbac882e149e04a9e1f2d146fd548ae30ae
|
||||
c4e0cd966062ca67daed20775f4e8a60c28e57df
|
||||
|
@ -148,8 +148,7 @@ impl NewPermission {
|
||||
NewPermission::Uniform {
|
||||
perm: Permission::Unique,
|
||||
access: Some(AccessKind::Write),
|
||||
protector: (kind == RetagKind::FnEntry)
|
||||
.then_some(ProtectorKind::WeakProtector),
|
||||
protector: (kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector),
|
||||
}
|
||||
} else {
|
||||
// `!Unpin` boxes do not get `noalias` nor `dereferenceable`.
|
||||
|
@ -13,6 +13,7 @@
|
||||
#![allow(
|
||||
clippy::collapsible_else_if,
|
||||
clippy::collapsible_if,
|
||||
clippy::if_same_then_else,
|
||||
clippy::comparison_chain,
|
||||
clippy::enum_variant_names,
|
||||
clippy::field_reassign_with_default,
|
||||
@ -21,7 +22,7 @@
|
||||
clippy::single_match,
|
||||
clippy::useless_format,
|
||||
clippy::derive_partial_eq_without_eq,
|
||||
clippy::derive_hash_xor_eq,
|
||||
clippy::derived_hash_with_manual_eq,
|
||||
clippy::too_many_arguments,
|
||||
clippy::type_complexity,
|
||||
clippy::single_element_loop,
|
||||
|
@ -477,7 +477,8 @@ pub struct MiriMachine<'mir, 'tcx> {
|
||||
|
||||
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
|
||||
pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self {
|
||||
let local_crates = helpers::get_local_crates(layout_cx.tcx);
|
||||
let tcx = layout_cx.tcx;
|
||||
let local_crates = helpers::get_local_crates(tcx);
|
||||
let layouts =
|
||||
PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types");
|
||||
let profiler = config.measureme_out.as_ref().map(|out| {
|
||||
@ -486,10 +487,13 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
|
||||
let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
|
||||
let borrow_tracker = config.borrow_tracker.map(|bt| bt.instanciate_global_state(config));
|
||||
let data_race = config.data_race_detector.then(|| data_race::GlobalState::new(config));
|
||||
// Determinine page size, stack address, and stack size.
|
||||
// These values are mostly meaningless, but the stack address is also where we start
|
||||
// allocating physical integer addresses for all allocations.
|
||||
let page_size = if let Some(page_size) = config.page_size {
|
||||
page_size
|
||||
} else {
|
||||
let target = &layout_cx.tcx.sess.target;
|
||||
let target = &tcx.sess.target;
|
||||
match target.arch.as_ref() {
|
||||
"wasm32" | "wasm64" => 64 * 1024, // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances
|
||||
"aarch64" =>
|
||||
@ -504,10 +508,12 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
|
||||
_ => 4 * 1024,
|
||||
}
|
||||
};
|
||||
let stack_addr = page_size * 32;
|
||||
let stack_size = page_size * 16;
|
||||
// On 16bit targets, 32 pages is more than the entire address space!
|
||||
let stack_addr = if tcx.pointer_size().bits() < 32 { page_size } else { page_size * 32 };
|
||||
let stack_size =
|
||||
if tcx.pointer_size().bits() < 32 { page_size * 4 } else { page_size * 16 };
|
||||
MiriMachine {
|
||||
tcx: layout_cx.tcx,
|
||||
tcx,
|
||||
borrow_tracker,
|
||||
data_race,
|
||||
intptrcast: RefCell::new(intptrcast::GlobalStateInner::new(config, stack_addr)),
|
||||
@ -902,8 +908,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||
};
|
||||
let (shim_size, shim_align, _kind) = ecx.get_alloc_info(alloc_id);
|
||||
let def_ty = ecx.tcx.type_of(def_id).subst_identity();
|
||||
let extern_decl_layout =
|
||||
ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap();
|
||||
let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap();
|
||||
if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align {
|
||||
throw_unsup_format!(
|
||||
"`extern` static `{name}` from crate `{krate}` has been declared \
|
||||
|
@ -885,6 +885,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
"llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => {
|
||||
let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
|
||||
let arg = this.read_scalar(arg)?.to_i32()?;
|
||||
match arg {
|
||||
// YIELD
|
||||
1 => {
|
||||
this.yield_active_thread();
|
||||
}
|
||||
_ => {
|
||||
throw_unsup_format!("unsupported llvm.arm.hint argument {}", arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Platform-specific shims
|
||||
_ =>
|
||||
|
@ -7,6 +7,8 @@ use socketpair::SocketPair;
|
||||
|
||||
use shims::unix::fs::EvalContextExt as _;
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
pub mod epoll;
|
||||
pub mod event;
|
||||
pub mod socketpair;
|
||||
@ -101,6 +103,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The `epoll_wait()` system call waits for events on the `Epoll`
|
||||
/// instance referred to by the file descriptor `epfd`. The buffer
|
||||
/// pointed to by `events` is used to return information from the ready
|
||||
/// list about file descriptors in the interest list that have some
|
||||
/// events available. Up to `maxevents` are returned by `epoll_wait()`.
|
||||
/// The `maxevents` argument must be greater than zero.
|
||||
|
||||
/// The `timeout` argument specifies the number of milliseconds that
|
||||
/// `epoll_wait()` will block. Time is measured against the
|
||||
/// CLOCK_MONOTONIC clock.
|
||||
|
||||
/// A call to `epoll_wait()` will block until either:
|
||||
/// • a file descriptor delivers an event;
|
||||
/// • the call is interrupted by a signal handler; or
|
||||
/// • the timeout expires.
|
||||
|
||||
/// Note that the timeout interval will be rounded up to the system
|
||||
/// clock granularity, and kernel scheduling delays mean that the
|
||||
/// blocking interval may overrun by a small amount. Specifying a
|
||||
/// timeout of -1 causes `epoll_wait()` to block indefinitely, while
|
||||
/// specifying a timeout equal to zero cause `epoll_wait()` to return
|
||||
/// immediately, even if no events are available.
|
||||
///
|
||||
/// On success, `epoll_wait()` returns the number of file descriptors
|
||||
/// ready for the requested I/O, or zero if no file descriptor became
|
||||
/// ready during the requested timeout milliseconds. On failure,
|
||||
/// `epoll_wait()` returns -1 and errno is set to indicate the error.
|
||||
///
|
||||
/// <https://man7.org/linux/man-pages/man2/epoll_wait.2.html>
|
||||
fn epoll_wait(
|
||||
&mut self,
|
||||
epfd: &OpTy<'tcx, Provenance>,
|
||||
events: &OpTy<'tcx, Provenance>,
|
||||
maxevents: &OpTy<'tcx, Provenance>,
|
||||
timeout: &OpTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let epfd = this.read_scalar(epfd)?.to_i32()?;
|
||||
let _events = this.read_scalar(events)?.to_pointer(this)?;
|
||||
let _maxevents = this.read_scalar(maxevents)?.to_i32()?;
|
||||
let _timeout = this.read_scalar(timeout)?.to_i32()?;
|
||||
|
||||
let numevents = 0;
|
||||
if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
|
||||
let _epfd = epfd.as_epoll_handle()?;
|
||||
|
||||
// FIXME return number of events ready when scheme for marking events ready exists
|
||||
Ok(Scalar::from_i32(numevents))
|
||||
} else {
|
||||
Ok(Scalar::from_i32(this.handle_not_found()?))
|
||||
}
|
||||
}
|
||||
|
||||
/// This function creates an `Event` that is used as an event wait/notify mechanism by
|
||||
/// user-space applications, and by the kernel to notify user-space applications of events.
|
||||
/// The `Event` contains an `u64` counter maintained by the kernel. The counter is initialized
|
||||
@ -142,7 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
}
|
||||
|
||||
let fh = &mut this.machine.file_handler;
|
||||
let fd = fh.insert_fd(Box::new(Event { val }));
|
||||
let fd = fh.insert_fd(Box::new(Event { val: Cell::new(val.into()) }));
|
||||
Ok(Scalar::from_i32(fd))
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ use crate::shims::unix::fs::FileDescriptor;
|
||||
|
||||
use rustc_const_eval::interpret::InterpResult;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::io;
|
||||
|
||||
/// A kind of file descriptor created by `eventfd`.
|
||||
@ -13,7 +14,9 @@ use std::io;
|
||||
/// <https://man.netbsd.org/eventfd.2>
|
||||
#[derive(Debug)]
|
||||
pub struct Event {
|
||||
pub val: u32,
|
||||
/// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the
|
||||
/// kernel. This counter is initialized with the value specified in the argument initval.
|
||||
pub val: Cell<u64>,
|
||||
}
|
||||
|
||||
impl FileDescriptor for Event {
|
||||
@ -22,7 +25,7 @@ impl FileDescriptor for Event {
|
||||
}
|
||||
|
||||
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
|
||||
Ok(Box::new(Event { val: self.val }))
|
||||
Ok(Box::new(Event { val: self.val.clone() }))
|
||||
}
|
||||
|
||||
fn is_tty(&self) -> bool {
|
||||
@ -35,4 +38,32 @@ impl FileDescriptor for Event {
|
||||
) -> InterpResult<'tcx, io::Result<i32>> {
|
||||
Ok(Ok(0))
|
||||
}
|
||||
|
||||
/// A write call adds the 8-byte integer value supplied in
|
||||
/// its buffer to the counter. The maximum value that may be
|
||||
/// stored in the counter is the largest unsigned 64-bit value
|
||||
/// minus 1 (i.e., 0xfffffffffffffffe). If the addition would
|
||||
/// cause the counter's value to exceed the maximum, then the
|
||||
/// write either blocks until a read is performed on the
|
||||
/// file descriptor, or fails with the error EAGAIN if the
|
||||
/// file descriptor has been made nonblocking.
|
||||
|
||||
/// A write fails with the error EINVAL if the size of the
|
||||
/// supplied buffer is less than 8 bytes, or if an attempt is
|
||||
/// made to write the value 0xffffffffffffffff.
|
||||
///
|
||||
/// FIXME: use endianness
|
||||
fn write<'tcx>(
|
||||
&self,
|
||||
_communicate_allowed: bool,
|
||||
bytes: &[u8],
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
let v1 = self.val.get();
|
||||
// FIXME handle blocking when addition results in exceeding the max u64 value
|
||||
// or fail with EAGAIN if the file descriptor is nonblocking.
|
||||
let v2 = v1.checked_add(u64::from_be_bytes(bytes.try_into().unwrap())).unwrap();
|
||||
self.val.set(v2);
|
||||
assert_eq!(8, bytes.len());
|
||||
Ok(Ok(8))
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
let result = this.epoll_ctl(epfd, op, fd, event)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"epoll_wait" => {
|
||||
let [epfd, events, maxevents, timeout] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.epoll_wait(epfd, events, maxevents, timeout)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"eventfd" => {
|
||||
let [val, flag] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
|
@ -23,7 +23,7 @@ fn main() {
|
||||
// (We rely on the test runner to always disable isolation when passing no arguments.)
|
||||
if std::env::args().len() <= 1 {
|
||||
fn host_to_target_path(path: String) -> PathBuf {
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::{c_char, CStr, CString};
|
||||
|
||||
let path = CString::new(path).unwrap();
|
||||
let mut out = Vec::with_capacity(1024);
|
||||
@ -31,8 +31,8 @@ fn main() {
|
||||
unsafe {
|
||||
extern "Rust" {
|
||||
fn miri_host_to_target_path(
|
||||
path: *const i8,
|
||||
out: *mut i8,
|
||||
path: *const c_char,
|
||||
out: *mut c_char,
|
||||
out_size: usize,
|
||||
) -> usize;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ fn main() {
|
||||
println!("subcrate running");
|
||||
|
||||
fn host_to_target_path(path: String) -> PathBuf {
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::{c_char, CStr, CString};
|
||||
|
||||
let path = CString::new(path).unwrap();
|
||||
let mut out = Vec::with_capacity(1024);
|
||||
@ -13,8 +13,8 @@ fn main() {
|
||||
unsafe {
|
||||
extern "Rust" {
|
||||
fn miri_host_to_target_path(
|
||||
path: *const i8,
|
||||
out: *mut i8,
|
||||
path: *const c_char,
|
||||
out: *mut c_char,
|
||||
out_size: usize,
|
||||
) -> usize;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ fn main() {
|
||||
println!("subcrate testing");
|
||||
|
||||
fn host_to_target_path(path: String) -> PathBuf {
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::{c_char, CStr, CString};
|
||||
|
||||
let path = CString::new(path).unwrap();
|
||||
let mut out = Vec::with_capacity(1024);
|
||||
@ -16,8 +16,8 @@ fn main() {
|
||||
unsafe {
|
||||
extern "Rust" {
|
||||
fn miri_host_to_target_path(
|
||||
path: *const i8,
|
||||
out: *mut i8,
|
||||
path: *const c_char,
|
||||
out: *mut c_char,
|
||||
out_size: usize,
|
||||
) -> usize;
|
||||
}
|
||||
|
@ -292,9 +292,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.23.1"
|
||||
version = "1.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38a54aca0c15d014013256222ba0ebed095673f89345dd79119d912eb561b7a8"
|
||||
checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
|
@ -18,6 +18,6 @@ rand = { version = "0.8", features = ["small_rng"] }
|
||||
|
||||
[target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
|
||||
page_size = "0.5"
|
||||
tokio = { version = "1.23", features = ["full"] }
|
||||
tokio = { version = "1.24", features = ["full"] }
|
||||
|
||||
[workspace]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
use std::{ptr, mem};
|
||||
use std::{mem, ptr};
|
||||
|
||||
#[repr(packed)]
|
||||
struct Foo {
|
||||
|
@ -5,7 +5,7 @@
|
||||
#![feature(io_error_uncategorized)]
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::{c_char, CStr, CString};
|
||||
use std::fs::{canonicalize, remove_dir_all, remove_file, File};
|
||||
use std::io::{Error, ErrorKind, Write};
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
@ -31,7 +31,11 @@ fn tmp() -> PathBuf {
|
||||
|
||||
unsafe {
|
||||
extern "Rust" {
|
||||
fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
|
||||
fn miri_host_to_target_path(
|
||||
path: *const c_char,
|
||||
out: *mut c_char,
|
||||
out_size: usize,
|
||||
) -> usize;
|
||||
}
|
||||
let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
|
||||
assert_eq!(ret, 0);
|
||||
|
@ -7,7 +7,7 @@ use std::os::unix::io::AsRawFd;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn tmp() -> PathBuf {
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::{c_char, CStr, CString};
|
||||
|
||||
let path = std::env::var("MIRI_TEMP")
|
||||
.unwrap_or_else(|_| std::env::temp_dir().into_os_string().into_string().unwrap());
|
||||
@ -17,7 +17,11 @@ fn tmp() -> PathBuf {
|
||||
|
||||
unsafe {
|
||||
extern "Rust" {
|
||||
fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
|
||||
fn miri_host_to_target_path(
|
||||
path: *const c_char,
|
||||
out: *mut c_char,
|
||||
out_size: usize,
|
||||
) -> usize;
|
||||
}
|
||||
let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
|
||||
assert_eq!(ret, 0);
|
||||
|
14
src/tools/miri/tests/pass-dep/tokio/sleep.rs
Normal file
14
src/tools/miri/tests/pass-dep/tokio/sleep.rs
Normal file
@ -0,0 +1,14 @@
|
||||
//@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance -Zmiri-backtrace=full
|
||||
//@only-target-x86_64-unknown-linux: support for tokio only on linux and x86
|
||||
|
||||
use tokio::time::{sleep, Duration, Instant};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let start = Instant::now();
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
// It takes 96 millisecond to sleep for 1 millisecond
|
||||
// It takes 1025 millisecond to sleep for 1 second
|
||||
let time_elapsed = &start.elapsed().as_millis();
|
||||
assert!(time_elapsed > &1000, "{}", time_elapsed);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
// Need to disable preemption to stay on the supported MVP codepath in mio.
|
||||
//@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance -Zmiri-preemption-rate=0
|
||||
//@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance
|
||||
//@only-target-x86_64-unknown-linux: support for tokio exists only on linux and x86
|
||||
|
||||
#[tokio::main]
|
@ -1,5 +1,8 @@
|
||||
#![feature(dyn_star)]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(custom_inner_attributes)]
|
||||
// rustfmt destroys `dyn* Trait` syntax
|
||||
#![rustfmt::skip]
|
||||
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
|
81
src/tools/miri/tests/pass/move-data-across-await-point.rs
Normal file
81
src/tools/miri/tests/pass/move-data-across-await-point.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use std::future::Future;
|
||||
use std::ptr;
|
||||
|
||||
// This test:
|
||||
// - Compares addresses of non-Copy data before and after moving it
|
||||
// - Writes to the pointer after it has moved across the await point
|
||||
//
|
||||
// This is only meant to assert current behavior, not guarantee that this is
|
||||
// how it should work in the future. In fact, upcoming changes to rustc
|
||||
// *should* break these tests.
|
||||
// See: https://github.com/rust-lang/rust/issues/62958
|
||||
async fn data_moved_async() {
|
||||
async fn helper(mut data: Vec<u8>, raw_pointer: *mut Vec<u8>) {
|
||||
let raw_pointer2 = ptr::addr_of_mut!(data);
|
||||
// `raw_pointer` points to the original location where the Vec was stored in the caller.
|
||||
// `data` is where that Vec (to be precise, its ptr+capacity+len on-stack data)
|
||||
// got moved to. Those will usually not be the same since the Vec got moved twice
|
||||
// (into the function call, and then into the generator upvar).
|
||||
assert_ne!(raw_pointer, raw_pointer2);
|
||||
unsafe {
|
||||
// This writes into the `x` in `data_moved_async`, re-initializing it.
|
||||
std::ptr::write(raw_pointer, vec![3]);
|
||||
}
|
||||
}
|
||||
// Vec<T> is not Copy
|
||||
let mut x: Vec<u8> = vec![2];
|
||||
let raw_pointer = ptr::addr_of_mut!(x);
|
||||
helper(x, raw_pointer).await;
|
||||
unsafe {
|
||||
assert_eq!(*raw_pointer, vec![3]);
|
||||
// Drop to prevent leak.
|
||||
std::ptr::drop_in_place(raw_pointer);
|
||||
}
|
||||
}
|
||||
|
||||
// Same thing as above, but non-async.
|
||||
fn data_moved() {
|
||||
fn helper(mut data: Vec<u8>, raw_pointer: *mut Vec<u8>) {
|
||||
let raw_pointer2 = ptr::addr_of_mut!(data);
|
||||
assert_ne!(raw_pointer, raw_pointer2);
|
||||
unsafe {
|
||||
std::ptr::write(raw_pointer, vec![3]);
|
||||
}
|
||||
}
|
||||
|
||||
let mut x: Vec<u8> = vec![2];
|
||||
let raw_pointer = ptr::addr_of_mut!(x);
|
||||
helper(x, raw_pointer);
|
||||
unsafe {
|
||||
assert_eq!(*raw_pointer, vec![3]);
|
||||
std::ptr::drop_in_place(raw_pointer);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_fut<T>(fut: impl Future<Output = T>) -> T {
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll, Wake, Waker};
|
||||
|
||||
struct MyWaker;
|
||||
impl Wake for MyWaker {
|
||||
fn wake(self: Arc<Self>) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
let waker = Waker::from(Arc::new(MyWaker));
|
||||
let mut context = Context::from_waker(&waker);
|
||||
|
||||
let mut pinned = Box::pin(fut);
|
||||
loop {
|
||||
match pinned.as_mut().poll(&mut context) {
|
||||
Poll::Pending => continue,
|
||||
Poll::Ready(v) => return v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
run_fut(data_moved_async());
|
||||
data_moved();
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
#![feature(is_terminal)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsString;
|
||||
use std::ffi::{c_char, OsString};
|
||||
use std::fs::{
|
||||
canonicalize, create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename,
|
||||
File, OpenOptions,
|
||||
@ -39,7 +39,11 @@ fn host_to_target_path(path: String) -> PathBuf {
|
||||
|
||||
unsafe {
|
||||
extern "Rust" {
|
||||
fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
|
||||
fn miri_host_to_target_path(
|
||||
path: *const c_char,
|
||||
out: *mut c_char,
|
||||
out_size: usize,
|
||||
) -> usize;
|
||||
}
|
||||
let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
|
||||
assert_eq!(ret, 0);
|
||||
|
@ -0,0 +1,71 @@
|
||||
// edition: 2021
|
||||
// known-bug: #108309
|
||||
|
||||
#![feature(async_fn_in_trait)]
|
||||
#![feature(min_specialization)]
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
trait MyTrait<T> {
|
||||
async fn foo(_: T) -> &'static str;
|
||||
}
|
||||
|
||||
impl<T> MyTrait<T> for MyStruct {
|
||||
default async fn foo(_: T) -> &'static str {
|
||||
"default"
|
||||
}
|
||||
}
|
||||
|
||||
impl MyTrait<i32> for MyStruct {
|
||||
async fn foo(_: i32) -> &'static str {
|
||||
"specialized"
|
||||
}
|
||||
}
|
||||
|
||||
async fn async_main() {
|
||||
assert_eq!(MyStruct::foo(42).await, "specialized");
|
||||
assert_eq!(indirection(42).await, "specialized");
|
||||
}
|
||||
|
||||
async fn indirection<T>(x: T) -> &'static str {
|
||||
//explicit type coercion is currently necessary
|
||||
// because of https://github.com/rust-lang/rust/issues/67918
|
||||
<MyStruct as MyTrait<T>>::foo(x).await
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
// Implementation Details Below...
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::*;
|
||||
|
||||
pub fn noop_waker() -> Waker {
|
||||
let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
|
||||
|
||||
// SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
|
||||
unsafe { Waker::from_raw(raw) }
|
||||
}
|
||||
|
||||
const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
|
||||
|
||||
unsafe fn noop_clone(_p: *const ()) -> RawWaker {
|
||||
RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
|
||||
}
|
||||
|
||||
unsafe fn noop(_p: *const ()) {}
|
||||
|
||||
fn main() {
|
||||
let mut fut = async_main();
|
||||
|
||||
// Poll loop, just to test the future...
|
||||
let waker = noop_waker();
|
||||
let ctx = &mut Context::from_waker(&waker);
|
||||
|
||||
loop {
|
||||
match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
|
||||
Poll::Pending => {}
|
||||
Poll::Ready(()) => break,
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/dont-project-to-specializable-projection.rs:4:12
|
||||
|
|
||||
LL | #![feature(async_fn_in_trait)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0053]: method `foo` has an incompatible type for trait
|
||||
--> $DIR/dont-project-to-specializable-projection.rs:14:35
|
||||
|
|
||||
LL | default async fn foo(_: T) -> &'static str {
|
||||
| ^^^^^^^^^^^^ expected associated type, found future
|
||||
|
|
||||
note: type in trait
|
||||
--> $DIR/dont-project-to-specializable-projection.rs:10:27
|
||||
|
|
||||
LL | async fn foo(_: T) -> &'static str;
|
||||
| ^^^^^^^^^^^^
|
||||
= note: expected signature `fn(_) -> impl Future<Output = &'static str>`
|
||||
found signature `fn(_) -> impl Future<Output = &'static str>`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0053`.
|
13
tests/ui/lifetimes/issue-107988.rs
Normal file
13
tests/ui/lifetimes/issue-107988.rs
Normal file
@ -0,0 +1,13 @@
|
||||
pub trait TraitEngine<'tcx>: 'tcx {}
|
||||
|
||||
pub trait TraitEngineExt<'tcx> {
|
||||
fn register_predicate_obligations(&mut self);
|
||||
}
|
||||
|
||||
impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
||||
//~^ ERROR use of undeclared lifetime name `'tcx`
|
||||
//~| ERROR use of undeclared lifetime name `'tcx`
|
||||
fn register_predicate_obligations(&mut self) {}
|
||||
}
|
||||
|
||||
fn main() {}
|
27
tests/ui/lifetimes/issue-107988.stderr
Normal file
27
tests/ui/lifetimes/issue-107988.stderr
Normal file
@ -0,0 +1,27 @@
|
||||
error[E0261]: use of undeclared lifetime name `'tcx`
|
||||
--> $DIR/issue-107988.rs:7:52
|
||||
|
|
||||
LL | impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
||||
| - ^^^^ undeclared lifetime
|
||||
| |
|
||||
| help: consider introducing lifetime `'tcx` here: `'tcx,`
|
||||
|
||||
error[E0261]: use of undeclared lifetime name `'tcx`
|
||||
--> $DIR/issue-107988.rs:7:30
|
||||
|
|
||||
LL | impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
||||
| ^^^^ undeclared lifetime
|
||||
|
|
||||
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
|
||||
help: consider making the bound lifetime-generic with a new `'tcx` lifetime
|
||||
|
|
||||
LL | impl<T: ?Sized + for<'tcx> TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
||||
| +++++++++
|
||||
help: consider introducing lifetime `'tcx` here
|
||||
|
|
||||
LL | impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
||||
| +++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0261`.
|
@ -2,10 +2,14 @@ error: `match` arm body without braces
|
||||
--> $DIR/match-arm-without-braces.rs:26:27
|
||||
|
|
||||
LL | Some(Val::Foo) => 3;
|
||||
| -- ^- help: use a comma to end a `match` arm expression: `,`
|
||||
| | |
|
||||
| | this statement is not surrounded by a body
|
||||
| -- ^ this statement is not surrounded by a body
|
||||
| |
|
||||
| while parsing the `match` arm starting here
|
||||
|
|
||||
help: replace `;` with `,` to end a `match` arm expression
|
||||
|
|
||||
LL | Some(Val::Foo) => 3,
|
||||
| ~
|
||||
|
||||
error: `match` arm body without braces
|
||||
--> $DIR/match-arm-without-braces.rs:31:11
|
||||
|
@ -9,5 +9,5 @@ extern crate p1;
|
||||
extern crate p2;
|
||||
|
||||
#[rustc_diagnostic_item = "Foo"]
|
||||
pub struct Foo {} //~ ERROR duplicate diagnostic item found
|
||||
pub struct Foo {} //~ ERROR duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo`
|
||||
fn main() {}
|
||||
|
@ -2,11 +2,13 @@ error: duplicate diagnostic item in crate `p2`: `Foo`.
|
||||
|
|
||||
= note: the diagnostic item is first defined in crate `p1`.
|
||||
|
||||
error: duplicate diagnostic item found: `Foo`.
|
||||
error: duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo`.
|
||||
--> $DIR/duplicate-diagnostic.rs:12:1
|
||||
|
|
||||
LL | pub struct Foo {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the diagnostic item is first defined in crate `p2`.
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -482,7 +482,6 @@ compiler-team = [
|
||||
"@davidtwco",
|
||||
"@oli-obk",
|
||||
"@lcnr",
|
||||
"@nagisa",
|
||||
"@wesleywiser",
|
||||
"@michaelwoerister",
|
||||
]
|
||||
@ -552,7 +551,6 @@ mir = [
|
||||
"@oli-obk",
|
||||
]
|
||||
mir-opt = [
|
||||
"@nagisa",
|
||||
"@oli-obk",
|
||||
"@wesleywiser",
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user