mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Auto merge of #122241 - matthiaskrgr:rollup-r8q87ok, r=matthiaskrgr
Rollup of 12 pull requests Successful merges: - #121358 (Reduce alignment of TypeId to u64 alignment) - #121813 (Misc improvements to non local defs lint implementation) - #122160 (Eagerly translate `HelpUseLatestEdition` in parser diagnostics) - #122178 (ci: add a runner for vanilla LLVM 18) - #122187 (Move metadata header and version checks together) - #122209 (fix incorrect path resolution in tidy) - #122215 (Some tweaks to the parallel query cycle handler) - #122223 (Fix typo in `VisitorResult`) - #122224 (Add missing regression tests) - #122232 (library/core: fix a comment, and a cfg(miri) warning) - #122233 (miri: do not apply aliasing restrictions to Box with custom allocator) - #122237 (Remove `Ord` from `ClosureKind`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8401645716
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -315,6 +315,10 @@ jobs:
|
||||
- name: x86_64-gnu-distcheck
|
||||
os: ubuntu-20.04-8core-32gb
|
||||
env: {}
|
||||
- name: x86_64-gnu-llvm-18
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
os: ubuntu-20.04-8core-32gb
|
||||
- name: x86_64-gnu-llvm-17
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
@ -4133,7 +4133,6 @@ dependencies = [
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
"rustc_type_ir",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
"unicode-security",
|
||||
]
|
||||
|
@ -14,7 +14,7 @@ impl VisitorResult for () {
|
||||
type Residual = !;
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
type Residual = core::ops::Infallible;
|
||||
type Residual = core::convert::Infallible;
|
||||
|
||||
fn output() -> Self {}
|
||||
fn from_residual(_: Self::Residual) -> Self {}
|
||||
|
@ -17,8 +17,8 @@ use rustc_middle::mir::interpret::{
|
||||
ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance,
|
||||
ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*,
|
||||
};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_target::abi::{
|
||||
Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange,
|
||||
@ -783,7 +783,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_box(&mut self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
|
||||
fn visit_box(
|
||||
&mut self,
|
||||
_box_ty: Ty<'tcx>,
|
||||
op: &OpTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
self.check_safe_pointer(op, PointerKind::Box)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::interpret::InterpResult;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_target::abi::FieldIdx;
|
||||
use rustc_target::abi::{FieldsShape, VariantIdx, Variants};
|
||||
|
||||
@ -47,10 +47,10 @@ pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
|
||||
Ok(())
|
||||
}
|
||||
/// Visits the given value as the pointer of a `Box`. There is nothing to recurse into.
|
||||
/// The type of `v` will be a raw pointer, but this is a field of `Box<T>` and the
|
||||
/// pointee type is the actual `T`.
|
||||
/// The type of `v` will be a raw pointer to `T`, but this is a field of `Box<T>` and the
|
||||
/// pointee type is the actual `T`. `box_ty` provides the full type of the `Box` itself.
|
||||
#[inline(always)]
|
||||
fn visit_box(&mut self, _v: &Self::V) -> InterpResult<'tcx> {
|
||||
fn visit_box(&mut self, _box_ty: Ty<'tcx>, _v: &Self::V) -> InterpResult<'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
|
||||
assert_eq!(nonnull_ptr.layout().fields.count(), 1);
|
||||
let raw_ptr = self.ecx().project_field(&nonnull_ptr, 0)?; // the actual raw ptr
|
||||
// ... whose only field finally is a raw ptr we can dereference.
|
||||
self.visit_box(&raw_ptr)?;
|
||||
self.visit_box(ty, &raw_ptr)?;
|
||||
|
||||
// The second `Box` field is the allocator, which we recursively check for validity
|
||||
// like in regular structs.
|
||||
|
@ -676,6 +676,7 @@ fn list_metadata(early_dcx: &EarlyDiagCtxt, sess: &Session, metadata_loader: &dy
|
||||
metadata_loader,
|
||||
&mut v,
|
||||
&sess.opts.unstable_opts.ls,
|
||||
sess.cfg_version,
|
||||
)
|
||||
.unwrap();
|
||||
safe_println!("{}", String::from_utf8(v).unwrap());
|
||||
|
@ -657,6 +657,10 @@ pub fn check_intrinsic_type(
|
||||
sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)),
|
||||
sym::simd_shuffle_generic => (2, 1, vec![param(0), param(0)], param(1)),
|
||||
|
||||
sym::retag_box_to_raw => {
|
||||
(2, 0, vec![Ty::new_mut_ptr(tcx, param(0))], Ty::new_mut_ptr(tcx, param(0)))
|
||||
}
|
||||
|
||||
other => {
|
||||
tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other });
|
||||
return;
|
||||
|
@ -19,7 +19,7 @@ use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits;
|
||||
use rustc_trait_selection::traits::error_reporting::ArgKind;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use std::cmp;
|
||||
use rustc_type_ir::ClosureKind;
|
||||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
@ -437,10 +437,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
};
|
||||
|
||||
if let Some(found_kind) = found_kind {
|
||||
expected_kind = Some(
|
||||
expected_kind
|
||||
.map_or_else(|| found_kind, |current| cmp::min(current, found_kind)),
|
||||
);
|
||||
// always use the closure kind that is more permissive.
|
||||
match (expected_kind, found_kind) {
|
||||
(None, _) => expected_kind = Some(found_kind),
|
||||
(Some(ClosureKind::FnMut), ClosureKind::Fn) => {
|
||||
expected_kind = Some(ClosureKind::Fn)
|
||||
}
|
||||
(Some(ClosureKind::FnOnce), ClosureKind::Fn | ClosureKind::FnMut) => {
|
||||
expected_kind = Some(found_kind)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,10 +101,11 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
threads: usize,
|
||||
f: F,
|
||||
) -> R {
|
||||
use rustc_data_structures::{jobserver, sync::FromDyn};
|
||||
use rustc_data_structures::{defer, jobserver, sync::FromDyn};
|
||||
use rustc_middle::ty::tls;
|
||||
use rustc_query_impl::QueryCtxt;
|
||||
use rustc_query_system::query::{deadlock, QueryContext};
|
||||
use rustc_query_system::query::{break_query_cycles, QueryContext};
|
||||
use std::process;
|
||||
|
||||
let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
|
||||
|
||||
@ -128,7 +129,19 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
let query_map =
|
||||
FromDyn::from(tls::with(|tcx| QueryCtxt::new(tcx).collect_active_jobs()));
|
||||
let registry = rayon_core::Registry::current();
|
||||
thread::spawn(move || deadlock(query_map.into_inner(), ®istry));
|
||||
thread::Builder::new()
|
||||
.name("rustc query cycle handler".to_string())
|
||||
.spawn(move || {
|
||||
let on_panic = defer(|| {
|
||||
eprintln!("query cycle handler thread panicked, aborting process");
|
||||
// We need to abort here as we failed to resolve the deadlock,
|
||||
// otherwise the compiler could just hang,
|
||||
process::abort();
|
||||
});
|
||||
break_query_cycles(query_map.into_inner(), ®istry);
|
||||
on_panic.disable();
|
||||
})
|
||||
.unwrap();
|
||||
});
|
||||
if let Some(size) = get_stack_size() {
|
||||
builder = builder.stack_size(size);
|
||||
|
@ -23,7 +23,6 @@ rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||
rustc_type_ir = { path = "../rustc_type_ir" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
tracing = "0.1"
|
||||
unicode-security = "0.1.0"
|
||||
# tidy-alphabetical-end
|
||||
|
@ -2,8 +2,6 @@ use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, Path, QPath, TyKind};
|
||||
use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
|
||||
@ -85,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
||||
if let Some(def_id) = oexpn.macro_def_id
|
||||
&& let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
|
||||
&& def_id.krate != LOCAL_CRATE
|
||||
&& std::env::var_os("CARGO").is_some()
|
||||
&& rustc_session::utils::was_invoked_from_cargo()
|
||||
{
|
||||
Some(NonLocalDefinitionsCargoUpdateNote {
|
||||
macro_kind: macro_kind.descr(),
|
||||
@ -114,25 +112,25 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
||||
// is using local items and so we don't lint on it.
|
||||
|
||||
// We also ignore anon-const in item by including the anon-const
|
||||
// parent as well; and since it's quite uncommon, we use smallvec
|
||||
// to avoid unnecessary heap allocations.
|
||||
let local_parents: SmallVec<[DefId; 1]> = if parent_def_kind == DefKind::Const
|
||||
// parent as well.
|
||||
let parent_parent = if parent_def_kind == DefKind::Const
|
||||
&& parent_opt_item_name == Some(kw::Underscore)
|
||||
{
|
||||
smallvec![parent, cx.tcx.parent(parent)]
|
||||
Some(cx.tcx.parent(parent))
|
||||
} else {
|
||||
smallvec![parent]
|
||||
None
|
||||
};
|
||||
|
||||
let self_ty_has_local_parent = match impl_.self_ty.kind {
|
||||
TyKind::Path(QPath::Resolved(_, ty_path)) => {
|
||||
path_has_local_parent(ty_path, cx, &*local_parents)
|
||||
path_has_local_parent(ty_path, cx, parent, parent_parent)
|
||||
}
|
||||
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
|
||||
path_has_local_parent(
|
||||
principle_poly_trait_ref.trait_ref.path,
|
||||
cx,
|
||||
&*local_parents,
|
||||
parent,
|
||||
parent_parent,
|
||||
)
|
||||
}
|
||||
TyKind::TraitObject([], _, _)
|
||||
@ -154,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
||||
|
||||
let of_trait_has_local_parent = impl_
|
||||
.of_trait
|
||||
.map(|of_trait| path_has_local_parent(of_trait.path, cx, &*local_parents))
|
||||
.map(|of_trait| path_has_local_parent(of_trait.path, cx, parent, parent_parent))
|
||||
.unwrap_or(false);
|
||||
|
||||
// If none of them have a local parent (LOGICAL NOR) this means that
|
||||
@ -218,6 +216,16 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
||||
/// std::convert::PartialEq<Foo<Bar>>
|
||||
/// ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
fn path_has_local_parent(path: &Path<'_>, cx: &LateContext<'_>, local_parents: &[DefId]) -> bool {
|
||||
path.res.opt_def_id().is_some_and(|did| local_parents.contains(&cx.tcx.parent(did)))
|
||||
fn path_has_local_parent(
|
||||
path: &Path<'_>,
|
||||
cx: &LateContext<'_>,
|
||||
impl_parent: DefId,
|
||||
impl_parent_parent: Option<DefId>,
|
||||
) -> bool {
|
||||
path.res.opt_def_id().is_some_and(|did| {
|
||||
did.is_local() && {
|
||||
let res_parent = cx.tcx.parent(did);
|
||||
res_parent == impl_parent || Some(res_parent) == impl_parent_parent
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -569,31 +569,47 @@ impl<'a> CrateLocator<'a> {
|
||||
debug!("skipping empty file");
|
||||
continue;
|
||||
}
|
||||
let (hash, metadata) =
|
||||
match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) {
|
||||
Ok(blob) => {
|
||||
if let Some(h) = self.crate_matches(&blob, &lib) {
|
||||
(h, blob)
|
||||
} else {
|
||||
info!("metadata mismatch");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(MetadataError::LoadFailure(err)) => {
|
||||
info!("no metadata found: {}", err);
|
||||
// The file was present and created by the same compiler version, but we
|
||||
// couldn't load it for some reason. Give a hard error instead of silently
|
||||
// ignoring it, but only if we would have given an error anyway.
|
||||
self.crate_rejections
|
||||
.via_invalid
|
||||
.push(CrateMismatch { path: lib, got: err });
|
||||
let (hash, metadata) = match get_metadata_section(
|
||||
self.target,
|
||||
flavor,
|
||||
&lib,
|
||||
self.metadata_loader,
|
||||
self.cfg_version,
|
||||
) {
|
||||
Ok(blob) => {
|
||||
if let Some(h) = self.crate_matches(&blob, &lib) {
|
||||
(h, blob)
|
||||
} else {
|
||||
info!("metadata mismatch");
|
||||
continue;
|
||||
}
|
||||
Err(err @ MetadataError::NotPresent(_)) => {
|
||||
info!("no metadata found: {}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(MetadataError::VersionMismatch { expected_version, found_version }) => {
|
||||
// The file was present and created by the same compiler version, but we
|
||||
// couldn't load it for some reason. Give a hard error instead of silently
|
||||
// ignoring it, but only if we would have given an error anyway.
|
||||
info!(
|
||||
"Rejecting via version: expected {} got {}",
|
||||
expected_version, found_version
|
||||
);
|
||||
self.crate_rejections
|
||||
.via_version
|
||||
.push(CrateMismatch { path: lib, got: found_version });
|
||||
continue;
|
||||
}
|
||||
Err(MetadataError::LoadFailure(err)) => {
|
||||
info!("no metadata found: {}", err);
|
||||
// The file was present and created by the same compiler version, but we
|
||||
// couldn't load it for some reason. Give a hard error instead of silently
|
||||
// ignoring it, but only if we would have given an error anyway.
|
||||
self.crate_rejections.via_invalid.push(CrateMismatch { path: lib, got: err });
|
||||
continue;
|
||||
}
|
||||
Err(err @ MetadataError::NotPresent(_)) => {
|
||||
info!("no metadata found: {}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
// If we see multiple hashes, emit an error about duplicate candidates.
|
||||
if slot.as_ref().is_some_and(|s| s.0 != hash) {
|
||||
if let Some(candidates) = err_data {
|
||||
@ -648,16 +664,6 @@ impl<'a> CrateLocator<'a> {
|
||||
}
|
||||
|
||||
fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
|
||||
let rustc_version = rustc_version(self.cfg_version);
|
||||
let found_version = metadata.get_rustc_version();
|
||||
if found_version != rustc_version {
|
||||
info!("Rejecting via version: expected {} got {}", rustc_version, found_version);
|
||||
self.crate_rejections
|
||||
.via_version
|
||||
.push(CrateMismatch { path: libpath.to_path_buf(), got: found_version });
|
||||
return None;
|
||||
}
|
||||
|
||||
let header = metadata.get_header();
|
||||
if header.is_proc_macro_crate != self.is_proc_macro {
|
||||
info!(
|
||||
@ -770,6 +776,7 @@ fn get_metadata_section<'p>(
|
||||
flavor: CrateFlavor,
|
||||
filename: &'p Path,
|
||||
loader: &dyn MetadataLoader,
|
||||
cfg_version: &'static str,
|
||||
) -> Result<MetadataBlob, MetadataError<'p>> {
|
||||
if !filename.exists() {
|
||||
return Err(MetadataError::NotPresent(filename));
|
||||
@ -847,13 +854,18 @@ fn get_metadata_section<'p>(
|
||||
}
|
||||
};
|
||||
let blob = MetadataBlob(raw_bytes);
|
||||
if blob.is_compatible() {
|
||||
Ok(blob)
|
||||
} else {
|
||||
Err(MetadataError::LoadFailure(format!(
|
||||
match blob.check_compatibility(cfg_version) {
|
||||
Ok(()) => Ok(blob),
|
||||
Err(None) => Err(MetadataError::LoadFailure(format!(
|
||||
"invalid metadata version found: {}",
|
||||
filename.display()
|
||||
)))
|
||||
))),
|
||||
Err(Some(found_version)) => {
|
||||
return Err(MetadataError::VersionMismatch {
|
||||
expected_version: rustc_version(cfg_version),
|
||||
found_version,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -864,9 +876,10 @@ pub fn list_file_metadata(
|
||||
metadata_loader: &dyn MetadataLoader,
|
||||
out: &mut dyn Write,
|
||||
ls_kinds: &[String],
|
||||
cfg_version: &'static str,
|
||||
) -> IoResult<()> {
|
||||
let flavor = get_flavor_from_path(path);
|
||||
match get_metadata_section(target, flavor, path, metadata_loader) {
|
||||
match get_metadata_section(target, flavor, path, metadata_loader, cfg_version) {
|
||||
Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds),
|
||||
Err(msg) => write!(out, "{msg}\n"),
|
||||
}
|
||||
@ -932,6 +945,8 @@ enum MetadataError<'a> {
|
||||
NotPresent(&'a Path),
|
||||
/// The file was present and invalid.
|
||||
LoadFailure(String),
|
||||
/// The file was present, but compiled with a different rustc version.
|
||||
VersionMismatch { expected_version: String, found_version: String },
|
||||
}
|
||||
|
||||
impl fmt::Display for MetadataError<'_> {
|
||||
@ -941,6 +956,12 @@ impl fmt::Display for MetadataError<'_> {
|
||||
f.write_str(&format!("no such file: '{}'", filename.display()))
|
||||
}
|
||||
MetadataError::LoadFailure(msg) => f.write_str(msg),
|
||||
MetadataError::VersionMismatch { expected_version, found_version } => {
|
||||
f.write_str(&format!(
|
||||
"rustc version mismatch. expected {}, found {}",
|
||||
expected_version, found_version,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -684,13 +684,25 @@ impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T>
|
||||
implement_ty_decoder!(DecodeContext<'a, 'tcx>);
|
||||
|
||||
impl MetadataBlob {
|
||||
pub(crate) fn is_compatible(&self) -> bool {
|
||||
self.blob().starts_with(METADATA_HEADER)
|
||||
}
|
||||
pub(crate) fn check_compatibility(
|
||||
&self,
|
||||
cfg_version: &'static str,
|
||||
) -> Result<(), Option<String>> {
|
||||
if !self.blob().starts_with(METADATA_HEADER) {
|
||||
if self.blob().starts_with(b"rust") {
|
||||
return Err(Some("<unknown rustc version>".to_owned()));
|
||||
}
|
||||
return Err(None);
|
||||
}
|
||||
|
||||
pub(crate) fn get_rustc_version(&self) -> String {
|
||||
LazyValue::<String>::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap())
|
||||
.decode(self)
|
||||
let found_version =
|
||||
LazyValue::<String>::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap())
|
||||
.decode(self);
|
||||
if rustc_version(cfg_version) != found_version {
|
||||
return Err(Some(found_version));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn root_pos(&self) -> NonZero<usize> {
|
||||
|
@ -30,7 +30,7 @@ pub struct Instance<'tcx> {
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub enum InstanceDef<'tcx> {
|
||||
/// A user-defined callable item.
|
||||
|
@ -2008,13 +2008,10 @@ impl<'tcx> Ty<'tcx> {
|
||||
// Single-argument Box is always global. (for "minicore" tests)
|
||||
return true;
|
||||
};
|
||||
if let Some(alloc_adt) = alloc.expect_ty().ty_adt_def() {
|
||||
alloc.expect_ty().ty_adt_def().is_some_and(|alloc_adt| {
|
||||
let global_alloc = tcx.require_lang_item(LangItem::GlobalAlloc, None);
|
||||
alloc_adt.did() == global_alloc
|
||||
} else {
|
||||
// Allocator is not an ADT...
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
|
@ -667,7 +667,7 @@ impl<'a> Parser<'a> {
|
||||
{
|
||||
err.note("you may be trying to write a c-string literal");
|
||||
err.note("c-string literals require Rust 2021 or later");
|
||||
HelpUseLatestEdition::new().add_to_diagnostic(&mut err);
|
||||
err.subdiagnostic(self.dcx(), HelpUseLatestEdition::new());
|
||||
}
|
||||
|
||||
// `pub` may be used for an item or `pub(crate)`
|
||||
|
@ -17,10 +17,9 @@ use std::num::NonZero;
|
||||
use {
|
||||
parking_lot::{Condvar, Mutex},
|
||||
rustc_data_structures::fx::FxHashSet,
|
||||
rustc_data_structures::{defer, jobserver},
|
||||
rustc_data_structures::jobserver,
|
||||
rustc_span::DUMMY_SP,
|
||||
std::iter,
|
||||
std::process,
|
||||
std::sync::Arc,
|
||||
};
|
||||
|
||||
@ -514,12 +513,7 @@ fn remove_cycle(
|
||||
/// There may be multiple cycles involved in a deadlock, so this searches
|
||||
/// all active queries for cycles before finally resuming all the waiters at once.
|
||||
#[cfg(parallel_compiler)]
|
||||
pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
|
||||
let on_panic = defer(|| {
|
||||
eprintln!("deadlock handler panicked, aborting process");
|
||||
process::abort();
|
||||
});
|
||||
|
||||
pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) {
|
||||
let mut wakelist = Vec::new();
|
||||
let mut jobs: Vec<QueryJobId> = query_map.keys().cloned().collect();
|
||||
|
||||
@ -539,19 +533,17 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
|
||||
// X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here
|
||||
// only considers the true dependency and won't detect a cycle.
|
||||
if !found_cycle {
|
||||
if query_map.len() == 0 {
|
||||
panic!("deadlock detected without any query!")
|
||||
} else {
|
||||
panic!("deadlock detected! current query map:\n{:#?}", query_map);
|
||||
}
|
||||
panic!(
|
||||
"deadlock detected as we're unable to find a query cycle to break\n\
|
||||
current query map:\n{:#?}",
|
||||
query_map
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME: Ensure this won't cause a deadlock before we return
|
||||
for waiter in wakelist.into_iter() {
|
||||
waiter.notify(registry);
|
||||
}
|
||||
|
||||
on_panic.disable();
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
|
@ -3,7 +3,7 @@ pub use self::plumbing::*;
|
||||
|
||||
mod job;
|
||||
#[cfg(parallel_compiler)]
|
||||
pub use self::job::deadlock;
|
||||
pub use self::job::break_query_cycles;
|
||||
pub use self::job::{
|
||||
print_query_stack, report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap,
|
||||
};
|
||||
|
@ -1450,6 +1450,7 @@ symbols! {
|
||||
residual,
|
||||
result,
|
||||
resume,
|
||||
retag_box_to_raw,
|
||||
return_position_impl_trait_in_trait,
|
||||
return_type_notation,
|
||||
rhs,
|
||||
|
@ -7,6 +7,7 @@ use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::sym;
|
||||
use rustc_trait_selection::traits;
|
||||
use rustc_type_ir::ClosureKind;
|
||||
use traits::{translate_args, Reveal};
|
||||
|
||||
use crate::errors::UnexpectedFnPtrAssociatedItem;
|
||||
@ -296,23 +297,25 @@ fn resolve_associated_item<'tcx>(
|
||||
{
|
||||
match *rcvr_args.type_at(0).kind() {
|
||||
ty::CoroutineClosure(coroutine_closure_def_id, args) => {
|
||||
// If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure,
|
||||
// or `AsyncFnOnce` for a by-mut closure, then construct a new body that
|
||||
// has the right return types.
|
||||
//
|
||||
// Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs
|
||||
// to have its input and output types fixed (`&mut self` and returning
|
||||
// `i16` coroutine kind).
|
||||
if target_kind > args.as_coroutine_closure().kind() {
|
||||
Some(Instance {
|
||||
def: ty::InstanceDef::ConstructCoroutineInClosureShim {
|
||||
coroutine_closure_def_id,
|
||||
target_kind,
|
||||
},
|
||||
args,
|
||||
})
|
||||
} else {
|
||||
Some(Instance::new(coroutine_closure_def_id, args))
|
||||
match (target_kind, args.as_coroutine_closure().kind()) {
|
||||
(ClosureKind::FnOnce | ClosureKind::FnMut, ClosureKind::Fn)
|
||||
| (ClosureKind::FnOnce, ClosureKind::FnMut) => {
|
||||
// If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure,
|
||||
// or `AsyncFnOnce` for a by-mut closure, then construct a new body that
|
||||
// has the right return types.
|
||||
//
|
||||
// Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs
|
||||
// to have its input and output types fixed (`&mut self` and returning
|
||||
// `i16` coroutine kind).
|
||||
Some(Instance {
|
||||
def: ty::InstanceDef::ConstructCoroutineInClosureShim {
|
||||
coroutine_closure_def_id,
|
||||
target_kind,
|
||||
},
|
||||
args,
|
||||
})
|
||||
}
|
||||
_ => Some(Instance::new(coroutine_closure_def_id, args)),
|
||||
}
|
||||
}
|
||||
ty::Closure(closure_def_id, args) => {
|
||||
|
@ -369,12 +369,9 @@ rustc_index::newtype_index! {
|
||||
///
|
||||
/// You can get the environment type of a closure using
|
||||
/// `tcx.closure_env_ty()`.
|
||||
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
|
||||
pub enum ClosureKind {
|
||||
// Warning: Ordering is significant here! The ordering is chosen
|
||||
// because the trait Fn is a subtrait of FnMut and so in turn, and
|
||||
// hence we order it so that Fn < FnMut < FnOnce.
|
||||
Fn,
|
||||
FnMut,
|
||||
FnOnce,
|
||||
@ -394,8 +391,15 @@ impl ClosureKind {
|
||||
|
||||
/// Returns `true` if a type that impls this closure kind
|
||||
/// must also implement `other`.
|
||||
#[rustfmt::skip]
|
||||
pub fn extends(self, other: ClosureKind) -> bool {
|
||||
self <= other
|
||||
use ClosureKind::*;
|
||||
match (self, other) {
|
||||
(Fn, Fn | FnMut | FnOnce)
|
||||
| (FnMut, FnMut | FnOnce)
|
||||
| (FnOnce, FnOnce) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,6 +155,7 @@ use core::error::Error;
|
||||
use core::fmt;
|
||||
use core::future::Future;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::intrinsics::retag_box_to_raw;
|
||||
use core::iter::FusedIterator;
|
||||
use core::marker::Tuple;
|
||||
use core::marker::Unsize;
|
||||
@ -1110,8 +1111,16 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
|
||||
let (leaked, alloc) = Box::into_unique(b);
|
||||
(leaked.as_ptr(), alloc)
|
||||
// This is the transition point from `Box` to raw pointers. For Stacked Borrows, these casts
|
||||
// are relevant -- if this is a global allocator Box and we just get the pointer from `b.0`,
|
||||
// it will have `Unique` permission, which is not what we want from a raw pointer. We could
|
||||
// fix that by going through `&mut`, but then if this is *not* a global allocator Box, we'd
|
||||
// be adding uniqueness assertions that we do not want. So for Miri's sake we pass this
|
||||
// pointer through an intrinsic for box-to-raw casts, which can do the right thing wrt the
|
||||
// aliasing model.
|
||||
let b = mem::ManuallyDrop::new(b);
|
||||
let alloc = unsafe { ptr::read(&b.1) };
|
||||
(unsafe { retag_box_to_raw::<T, A>(b.0.as_ptr()) }, alloc)
|
||||
}
|
||||
|
||||
#[unstable(
|
||||
@ -1122,13 +1131,8 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
pub fn into_unique(b: Self) -> (Unique<T>, A) {
|
||||
// Box is recognized as a "unique pointer" by Stacked Borrows, but internally it is a
|
||||
// raw pointer for the type system. Turning it directly into a raw pointer would not be
|
||||
// recognized as "releasing" the unique pointer to permit aliased raw accesses,
|
||||
// so all raw pointer methods have to go through `Box::leak`. Turning *that* to a raw pointer
|
||||
// behaves correctly.
|
||||
let alloc = unsafe { ptr::read(&b.1) };
|
||||
(Unique::from(Box::leak(b)), alloc)
|
||||
let (ptr, alloc) = Box::into_raw_with_allocator(b);
|
||||
unsafe { (Unique::from(&mut *ptr), alloc) }
|
||||
}
|
||||
|
||||
/// Returns a reference to the underlying allocator.
|
||||
@ -1184,7 +1188,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
||||
where
|
||||
A: 'a,
|
||||
{
|
||||
unsafe { &mut *mem::ManuallyDrop::new(b).0.as_ptr() }
|
||||
unsafe { &mut *Box::into_raw(b) }
|
||||
}
|
||||
|
||||
/// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
|
||||
|
@ -605,7 +605,9 @@ impl dyn Any + Send + Sync {
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialOrd, Ord)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct TypeId {
|
||||
t: u128,
|
||||
// We avoid using `u128` because that imposes higher alignment requirements on many platforms.
|
||||
// See issue #115620 for more information.
|
||||
t: (u64, u64),
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -637,7 +639,10 @@ impl TypeId {
|
||||
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
|
||||
pub const fn of<T: ?Sized + 'static>() -> TypeId {
|
||||
let t: u128 = intrinsics::type_id::<T>();
|
||||
TypeId { t }
|
||||
|
||||
let t1 = (t >> 64) as u64;
|
||||
let t2 = t as u64;
|
||||
TypeId { t: (t1, t2) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -657,7 +662,7 @@ impl hash::Hash for TypeId {
|
||||
// - It is correct to do so -- only hashing a subset of `self` is still
|
||||
// with an `Eq` implementation that considers the entire value, as
|
||||
// ours does.
|
||||
(self.t as u64).hash(state);
|
||||
self.t.1.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2695,6 +2695,19 @@ pub unsafe fn vtable_size(_ptr: *const ()) -> usize {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
/// Retag a box pointer as part of casting it to a raw pointer. This is the `Box` equivalent of
|
||||
/// `(x: &mut T) as *mut T`. The input pointer must be the pointer of a `Box` (passed as raw pointer
|
||||
/// to avoid all questions around move semantics and custom allocators), and `A` must be the `Box`'s
|
||||
/// allocator.
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_nounwind]
|
||||
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
|
||||
#[cfg_attr(bootstrap, inline)]
|
||||
pub unsafe fn retag_box_to_raw<T: ?Sized, A>(ptr: *mut T) -> *mut T {
|
||||
// Miri needs to adjust the provenance, but for regular codegen this is not needed
|
||||
ptr
|
||||
}
|
||||
|
||||
// Some functions are defined here because they accidentally got made
|
||||
// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
|
||||
// (`transmute` also falls into this category, but it cannot be wrapped due to the
|
||||
@ -3120,6 +3133,7 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize
|
||||
|
||||
const fn compiletime(_ptr: *const (), _align: usize) {}
|
||||
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||
// SAFETY: the extra behavior at runtime is for UB checks only.
|
||||
unsafe {
|
||||
const_eval_select((ptr, align), compiletime, runtime);
|
||||
|
@ -1628,12 +1628,12 @@ impl<T: ?Sized> *const T {
|
||||
#[inline]
|
||||
const fn const_impl(ptr: *const (), align: usize) -> bool {
|
||||
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
|
||||
// The cast to `()` is used to
|
||||
// 1. deal with fat pointers; and
|
||||
// 2. ensure that `align_offset` doesn't actually try to compute an offset.
|
||||
ptr.align_offset(align) == 0
|
||||
}
|
||||
|
||||
// The cast to `()` is used to
|
||||
// 1. deal with fat pointers; and
|
||||
// 2. ensure that `align_offset` (in `const_impl`) doesn't actually try to compute an offset.
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||
// SAFETY: The two versions are equivalent at runtime.
|
||||
unsafe {
|
||||
|
@ -1900,12 +1900,12 @@ impl<T: ?Sized> *mut T {
|
||||
#[inline]
|
||||
const fn const_impl(ptr: *mut (), align: usize) -> bool {
|
||||
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
|
||||
// The cast to `()` is used to
|
||||
// 1. deal with fat pointers; and
|
||||
// 2. ensure that `align_offset` doesn't actually try to compute an offset.
|
||||
ptr.align_offset(align) == 0
|
||||
}
|
||||
|
||||
// The cast to `()` is used to
|
||||
// 1. deal with fat pointers; and
|
||||
// 2. ensure that `align_offset` (in `const_impl`) doesn't actually try to compute an offset.
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||
// SAFETY: The two versions are equivalent at runtime.
|
||||
unsafe {
|
||||
|
@ -42,6 +42,10 @@ RUN sh /scripts/sccache.sh
|
||||
ENV NO_DOWNLOAD_CI_LLVM 1
|
||||
ENV EXTERNAL_LLVM 1
|
||||
|
||||
# This is not the latest LLVM version, so some components required by tests may
|
||||
# be missing.
|
||||
ENV IS_NOT_LATEST_LLVM 1
|
||||
|
||||
# Using llvm-link-shared due to libffi issues -- see #34486
|
||||
ENV RUST_CONFIGURE_ARGS \
|
||||
--build=x86_64-unknown-linux-gnu \
|
||||
|
55
src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile
Normal file
55
src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile
Normal file
@ -0,0 +1,55 @@
|
||||
FROM ubuntu:24.04
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
g++ \
|
||||
gcc-multilib \
|
||||
make \
|
||||
ninja-build \
|
||||
file \
|
||||
curl \
|
||||
ca-certificates \
|
||||
python3 \
|
||||
git \
|
||||
cmake \
|
||||
sudo \
|
||||
gdb \
|
||||
llvm-18-tools \
|
||||
llvm-18-dev \
|
||||
libedit-dev \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
zlib1g-dev \
|
||||
xz-utils \
|
||||
nodejs \
|
||||
mingw-w64 \
|
||||
libgccjit-13-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Note: libgccjit needs to match the default gcc version for the linker to find it.
|
||||
|
||||
# Install powershell (universal package) so we can test x.ps1 on Linux
|
||||
# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep.
|
||||
RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
|
||||
dpkg --ignore-depends=libicu72 -i powershell.deb && \
|
||||
rm -f powershell.deb
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
# We are disabling CI LLVM since this builder is intentionally using a host
|
||||
# LLVM, rather than the typical src/llvm-project LLVM.
|
||||
ENV NO_DOWNLOAD_CI_LLVM 1
|
||||
ENV EXTERNAL_LLVM 1
|
||||
|
||||
# Using llvm-link-shared due to libffi issues -- see #34486
|
||||
ENV RUST_CONFIGURE_ARGS \
|
||||
--build=x86_64-unknown-linux-gnu \
|
||||
--llvm-root=/usr/lib/llvm-18 \
|
||||
--enable-llvm-link-shared \
|
||||
--set rust.thin-lto-import-instr-limit=10
|
||||
|
||||
COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/
|
||||
|
||||
ENV SCRIPT /tmp/script.sh
|
@ -510,6 +510,11 @@ jobs:
|
||||
- name: x86_64-gnu-distcheck
|
||||
<<: *job-linux-8c
|
||||
|
||||
- name: x86_64-gnu-llvm-18
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
<<: *job-linux-8c
|
||||
|
||||
- name: x86_64-gnu-llvm-17
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
@ -5,7 +5,7 @@ use std::num::NonZero;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_middle::mir::RetagKind;
|
||||
use rustc_middle::{mir::RetagKind, ty::Ty};
|
||||
use rustc_target::abi::Size;
|
||||
|
||||
use crate::*;
|
||||
@ -291,6 +291,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn retag_box_to_raw(
|
||||
&mut self,
|
||||
val: &ImmTy<'tcx, Provenance>,
|
||||
alloc_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
|
||||
let this = self.eval_context_mut();
|
||||
let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
|
||||
match method {
|
||||
BorrowTrackerMethod::StackedBorrows => this.sb_retag_box_to_raw(val, alloc_ty),
|
||||
BorrowTrackerMethod::TreeBorrows => this.tb_retag_box_to_raw(val, alloc_ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn retag_place_contents(
|
||||
&mut self,
|
||||
kind: RetagKind,
|
||||
|
@ -865,6 +865,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
this.sb_retag_reference(val, new_perm, RetagInfo { cause, in_field: false })
|
||||
}
|
||||
|
||||
fn sb_retag_box_to_raw(
|
||||
&mut self,
|
||||
val: &ImmTy<'tcx, Provenance>,
|
||||
alloc_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
|
||||
let this = self.eval_context_mut();
|
||||
let is_global_alloc = alloc_ty.ty_adt_def().is_some_and(|adt| {
|
||||
let global_alloc = this.tcx.require_lang_item(rustc_hir::LangItem::GlobalAlloc, None);
|
||||
adt.did() == global_alloc
|
||||
});
|
||||
if is_global_alloc {
|
||||
// Retag this as-if it was a mutable reference.
|
||||
this.sb_retag_ptr_value(RetagKind::Raw, val)
|
||||
} else {
|
||||
Ok(val.clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn sb_retag_place_contents(
|
||||
&mut self,
|
||||
kind: RetagKind,
|
||||
@ -916,10 +934,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
self.ecx
|
||||
}
|
||||
|
||||
fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||
// Boxes get a weak protectors, since they may be deallocated.
|
||||
let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
|
||||
self.retag_ptr_inplace(place, new_perm)
|
||||
fn visit_box(
|
||||
&mut self,
|
||||
box_ty: Ty<'tcx>,
|
||||
place: &PlaceTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Only boxes for the global allocator get any special treatment.
|
||||
if box_ty.is_box_global(*self.ecx.tcx) {
|
||||
// Boxes get a weak protectors, since they may be deallocated.
|
||||
let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
|
||||
self.retag_ptr_inplace(place, new_perm)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||
|
@ -392,6 +392,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn tb_retag_box_to_raw(
|
||||
&mut self,
|
||||
val: &ImmTy<'tcx, Provenance>,
|
||||
_alloc_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
|
||||
// Casts to raw pointers are NOPs in Tree Borrows.
|
||||
Ok(val.clone())
|
||||
}
|
||||
|
||||
/// Retag all pointers that are stored in this place.
|
||||
fn tb_retag_place_contents(
|
||||
&mut self,
|
||||
@ -441,14 +450,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
/// Regardless of how `Unique` is handled, Boxes are always reborrowed.
|
||||
/// When `Unique` is also reborrowed, then it behaves exactly like `Box`
|
||||
/// except for the fact that `Box` has a non-zero-sized reborrow.
|
||||
fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||
let new_perm = NewPermission::from_unique_ty(
|
||||
place.layout.ty,
|
||||
self.kind,
|
||||
self.ecx,
|
||||
/* zero_size */ false,
|
||||
);
|
||||
self.retag_ptr_inplace(place, new_perm)
|
||||
fn visit_box(
|
||||
&mut self,
|
||||
box_ty: Ty<'tcx>,
|
||||
place: &PlaceTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Only boxes for the global allocator get any special treatment.
|
||||
if box_ty.is_box_global(*self.ecx.tcx) {
|
||||
let new_perm = NewPermission::from_unique_ty(
|
||||
place.layout.ty,
|
||||
self.kind,
|
||||
self.ecx,
|
||||
/* zero_size */ false,
|
||||
);
|
||||
self.retag_ptr_inplace(place, new_perm)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||
|
@ -129,6 +129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
this.write_bytes_ptr(ptr, iter::repeat(val_byte).take(byte_count.bytes_usize()))?;
|
||||
}
|
||||
|
||||
// Memory model / provenance manipulation
|
||||
"ptr_mask" => {
|
||||
let [ptr, mask] = check_arg_count(args)?;
|
||||
|
||||
@ -139,6 +140,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
|
||||
this.write_pointer(Pointer::new(ptr.provenance, masked_addr), dest)?;
|
||||
}
|
||||
"retag_box_to_raw" => {
|
||||
let [ptr] = check_arg_count(args)?;
|
||||
let alloc_ty = generic_args[1].expect_ty();
|
||||
|
||||
let val = this.read_immediate(ptr)?;
|
||||
let new_val = if this.machine.borrow_tracker.is_some() {
|
||||
this.retag_box_to_raw(&val, alloc_ty)?
|
||||
} else {
|
||||
val
|
||||
};
|
||||
this.write_immediate(*new_val, dest)?;
|
||||
}
|
||||
|
||||
// We want to return either `true` or `false` at random, or else something like
|
||||
// ```
|
||||
|
123
src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs
Normal file
123
src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs
Normal file
@ -0,0 +1,123 @@
|
||||
//! Regression test for <https://github.com/rust-lang/miri/issues/3341>:
|
||||
//! If `Box` has a local allocator, then it can't be `noalias` as the allocator
|
||||
//! may want to access allocator state based on the data pointer.
|
||||
|
||||
//@revisions: stack tree
|
||||
//@[tree]compile-flags: -Zmiri-tree-borrows
|
||||
#![feature(allocator_api)]
|
||||
#![feature(strict_provenance)]
|
||||
|
||||
use std::{
|
||||
alloc::{AllocError, Allocator, Layout},
|
||||
cell::{Cell, UnsafeCell},
|
||||
ptr::{self, addr_of, NonNull},
|
||||
thread::{self, ThreadId},
|
||||
mem,
|
||||
};
|
||||
|
||||
const BIN_SIZE: usize = 8;
|
||||
|
||||
// A bin represents a collection of blocks of a specific layout.
|
||||
#[repr(align(128))]
|
||||
struct MyBin {
|
||||
top: Cell<usize>,
|
||||
thread_id: ThreadId,
|
||||
memory: UnsafeCell<[usize; BIN_SIZE]>,
|
||||
}
|
||||
|
||||
impl MyBin {
|
||||
fn pop(&self) -> Option<NonNull<u8>> {
|
||||
let top = self.top.get();
|
||||
if top == BIN_SIZE {
|
||||
return None;
|
||||
}
|
||||
// Cast the *entire* thing to a raw pointer to not restrict its provenance.
|
||||
let bin = self as *const MyBin;
|
||||
let base_ptr = UnsafeCell::raw_get(unsafe{ addr_of!((*bin).memory )}).cast::<usize>();
|
||||
let ptr = unsafe { NonNull::new_unchecked(base_ptr.add(top)) };
|
||||
self.top.set(top + 1);
|
||||
Some(ptr.cast())
|
||||
}
|
||||
|
||||
// Pretends to not be a throwaway allocation method like this. A more realistic
|
||||
// substitute is using intrusive linked lists, which requires access to the
|
||||
// metadata of this bin as well.
|
||||
unsafe fn push(&self, ptr: NonNull<u8>) {
|
||||
// For now just check that this really is in this bin.
|
||||
let start = self.memory.get().addr();
|
||||
let end = start + BIN_SIZE * mem::size_of::<usize>();
|
||||
let addr = ptr.addr().get();
|
||||
assert!((start..end).contains(&addr));
|
||||
}
|
||||
}
|
||||
|
||||
// A collection of bins.
|
||||
struct MyAllocator {
|
||||
thread_id: ThreadId,
|
||||
// Pretends to be some complex collection of bins, such as an array of linked lists.
|
||||
bins: Box<[MyBin; 1]>,
|
||||
}
|
||||
|
||||
impl MyAllocator {
|
||||
fn new() -> Self {
|
||||
let thread_id = thread::current().id();
|
||||
MyAllocator {
|
||||
thread_id,
|
||||
bins: Box::new(
|
||||
[MyBin {
|
||||
top: Cell::new(0),
|
||||
thread_id,
|
||||
memory: UnsafeCell::default(),
|
||||
}; 1],
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Pretends to be expensive finding a suitable bin for the layout.
|
||||
fn find_bin(&self, layout: Layout) -> Option<&MyBin> {
|
||||
if layout == Layout::new::<usize>() {
|
||||
Some(&self.bins[0])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Allocator for MyAllocator {
|
||||
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
|
||||
// Expensive bin search.
|
||||
let bin = self.find_bin(layout).ok_or(AllocError)?;
|
||||
let ptr = bin.pop().ok_or(AllocError)?;
|
||||
Ok(NonNull::slice_from_raw_parts(ptr, layout.size()))
|
||||
}
|
||||
|
||||
unsafe fn deallocate(&self, ptr: NonNull<u8>, _layout: Layout) {
|
||||
// Since manually finding the corresponding bin of `ptr` is very expensive,
|
||||
// doing pointer arithmetics is preferred.
|
||||
// But this means we access `top` via `ptr` rather than `self`!
|
||||
// That is fundamentally the source of the aliasing trouble in this example.
|
||||
let their_bin = ptr.as_ptr().map_addr(|addr| addr & !127).cast::<MyBin>();
|
||||
let thread_id = ptr::read(ptr::addr_of!((*their_bin).thread_id));
|
||||
if self.thread_id == thread_id {
|
||||
unsafe { (*their_bin).push(ptr) };
|
||||
} else {
|
||||
todo!("Deallocating from another thread")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure to involve `Box` in allocating these,
|
||||
// as that's where `noalias` may come from.
|
||||
fn v<T, A: Allocator>(t: T, a: A) -> Vec<T, A> {
|
||||
(Box::new_in([t], a) as Box<[T], A>).into_vec()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert!(mem::size_of::<MyBin>() <= 128); // if it grows bigger, the trick to access the "header" no longer works
|
||||
let my_alloc = MyAllocator::new();
|
||||
let a = v(1usize, &my_alloc);
|
||||
let b = v(2usize, &my_alloc);
|
||||
assert_eq!(a[0] + 1, b[0]);
|
||||
assert_eq!(addr_of!(a[0]).wrapping_add(1), addr_of!(b[0]));
|
||||
drop((a, b));
|
||||
}
|
@ -102,7 +102,7 @@ fn main() {
|
||||
check!(tests_placement, &root_path);
|
||||
check!(tests_revision_unpaired_stdout_stderr, &tests_path);
|
||||
check!(debug_artifacts, &tests_path);
|
||||
check!(ui_tests, &tests_path, bless);
|
||||
check!(ui_tests, &root_path, bless);
|
||||
check!(mir_opt_tests, &tests_path, bless);
|
||||
check!(rustdoc_gui_tests, &tests_path);
|
||||
check!(rustdoc_css_themes, &librustdoc_path);
|
||||
|
@ -99,7 +99,8 @@ fn check_entries(tests_path: &Path, bad: &mut bool) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check(path: &Path, bless: bool, bad: &mut bool) {
|
||||
pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
|
||||
let path = &root_path.join("tests");
|
||||
check_entries(&path, bad);
|
||||
|
||||
// the list of files in ui tests that are allowed to start with `issue-XXXX`
|
||||
@ -193,7 +194,7 @@ pub fn check(path: &Path, bless: bool, bad: &mut bool) {
|
||||
*/
|
||||
[
|
||||
"#;
|
||||
let tidy_src = std::env::current_dir().unwrap().join("src/tools/tidy/src");
|
||||
let tidy_src = root_path.join("src/tools/tidy/src");
|
||||
// instead of overwriting the file, recreate it and use an "atomic rename"
|
||||
// so we don't bork things on panic or a contributor using Ctrl+C
|
||||
let blessed_issues_path = tidy_src.join("issues_blessed.txt");
|
||||
|
@ -1,7 +1,7 @@
|
||||
//@ check-pass
|
||||
//@ edition:2021
|
||||
//@ aux-build:non_local_macro.rs
|
||||
//@ rustc-env:CARGO=/usr/bin/cargo
|
||||
//@ rustc-env:CARGO_CRATE_NAME=non_local_def
|
||||
|
||||
#![feature(inline_const)]
|
||||
#![warn(non_local_definitions)]
|
||||
@ -245,6 +245,26 @@ fn bad() {
|
||||
//~^ WARN non-local `impl` definition
|
||||
}
|
||||
|
||||
trait Uto9 {}
|
||||
trait Uto10 {}
|
||||
const _: u32 = {
|
||||
let _a = || {
|
||||
impl Uto9 for Test {}
|
||||
//~^ WARN non-local `impl` definition
|
||||
|
||||
1
|
||||
};
|
||||
|
||||
type A = [u32; {
|
||||
impl Uto10 for Test {}
|
||||
//~^ WARN non-local `impl` definition
|
||||
|
||||
1
|
||||
}];
|
||||
|
||||
1
|
||||
};
|
||||
|
||||
struct UwU<T>(T);
|
||||
|
||||
fn fun() {
|
||||
|
@ -442,7 +442,29 @@ LL | impl<T> Uto8 for T {}
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:253:5
|
||||
--> $DIR/non_local_definitions.rs:252:9
|
||||
|
|
||||
LL | impl Uto9 for Test {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: move this `impl` block outside the of the current closure `<unnameable>` and up 2 bodies
|
||||
= note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block
|
||||
= note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:259:9
|
||||
|
|
||||
LL | impl Uto10 for Test {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies
|
||||
= note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block
|
||||
= note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:273:5
|
||||
|
|
||||
LL | / impl Default for UwU<OwO> {
|
||||
LL | |
|
||||
@ -458,7 +480,7 @@ LL | | }
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:264:5
|
||||
--> $DIR/non_local_definitions.rs:284:5
|
||||
|
|
||||
LL | / impl From<Cat> for () {
|
||||
LL | |
|
||||
@ -474,7 +496,7 @@ LL | | }
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:273:5
|
||||
--> $DIR/non_local_definitions.rs:293:5
|
||||
|
|
||||
LL | / impl AsRef<Cat> for () {
|
||||
LL | |
|
||||
@ -488,7 +510,7 @@ LL | | }
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:284:5
|
||||
--> $DIR/non_local_definitions.rs:304:5
|
||||
|
|
||||
LL | / impl PartialEq<B> for G {
|
||||
LL | |
|
||||
@ -504,7 +526,7 @@ LL | | }
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:301:5
|
||||
--> $DIR/non_local_definitions.rs:321:5
|
||||
|
|
||||
LL | / impl PartialEq<Dog> for &Dog {
|
||||
LL | |
|
||||
@ -520,7 +542,7 @@ LL | | }
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:308:5
|
||||
--> $DIR/non_local_definitions.rs:328:5
|
||||
|
|
||||
LL | / impl PartialEq<()> for Dog {
|
||||
LL | |
|
||||
@ -536,7 +558,7 @@ LL | | }
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:315:5
|
||||
--> $DIR/non_local_definitions.rs:335:5
|
||||
|
|
||||
LL | / impl PartialEq<()> for &Dog {
|
||||
LL | |
|
||||
@ -552,7 +574,7 @@ LL | | }
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:322:5
|
||||
--> $DIR/non_local_definitions.rs:342:5
|
||||
|
|
||||
LL | / impl PartialEq<Dog> for () {
|
||||
LL | |
|
||||
@ -568,7 +590,7 @@ LL | | }
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:344:5
|
||||
--> $DIR/non_local_definitions.rs:364:5
|
||||
|
|
||||
LL | / impl From<Wrap<Wrap<Lion>>> for () {
|
||||
LL | |
|
||||
@ -584,7 +606,7 @@ LL | | }
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:351:5
|
||||
--> $DIR/non_local_definitions.rs:371:5
|
||||
|
|
||||
LL | / impl From<()> for Wrap<Lion> {
|
||||
LL | |
|
||||
@ -600,7 +622,7 @@ LL | | }
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:364:13
|
||||
--> $DIR/non_local_definitions.rs:384:13
|
||||
|
|
||||
LL | impl MacroTrait for OutsideStruct {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -615,7 +637,7 @@ LL | m!();
|
||||
= note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: non-local `impl` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:374:1
|
||||
--> $DIR/non_local_definitions.rs:394:1
|
||||
|
|
||||
LL | non_local_macro::non_local_impl!(CargoUpdate);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -628,7 +650,7 @@ LL | non_local_macro::non_local_impl!(CargoUpdate);
|
||||
= note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation
|
||||
--> $DIR/non_local_definitions.rs:377:1
|
||||
--> $DIR/non_local_definitions.rs:397:1
|
||||
|
|
||||
LL | non_local_macro::non_local_macro_rules!(my_macro);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -640,5 +662,5 @@ LL | non_local_macro::non_local_macro_rules!(my_macro);
|
||||
= note: the macro `non_local_macro::non_local_macro_rules` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro`
|
||||
= note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: 50 warnings emitted
|
||||
warning: 52 warnings emitted
|
||||
|
||||
|
5
tests/ui/parser/help-set-edition-ice-122130.rs
Normal file
5
tests/ui/parser/help-set-edition-ice-122130.rs
Normal file
@ -0,0 +1,5 @@
|
||||
enum will {
|
||||
s#[c"owned_box"]
|
||||
//~^ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `#`
|
||||
//~|ERROR expected item, found `"owned_box"`
|
||||
}
|
21
tests/ui/parser/help-set-edition-ice-122130.stderr
Normal file
21
tests/ui/parser/help-set-edition-ice-122130.stderr
Normal file
@ -0,0 +1,21 @@
|
||||
error: expected one of `(`, `,`, `=`, `{`, or `}`, found `#`
|
||||
--> $DIR/help-set-edition-ice-122130.rs:2:6
|
||||
|
|
||||
LL | s#[c"owned_box"]
|
||||
| ^ expected one of `(`, `,`, `=`, `{`, or `}`
|
||||
|
|
||||
= note: you may be trying to write a c-string literal
|
||||
= note: c-string literals require Rust 2021 or later
|
||||
= help: pass `--edition 2021` to `rustc`
|
||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||
|
||||
error: expected item, found `"owned_box"`
|
||||
--> $DIR/help-set-edition-ice-122130.rs:2:9
|
||||
|
|
||||
LL | s#[c"owned_box"]
|
||||
| ^^^^^^^^^^^ expected item
|
||||
|
|
||||
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
13
tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.rs
Normal file
13
tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Regression test for issue #121612
|
||||
|
||||
trait Trait {}
|
||||
impl Trait for bool {}
|
||||
struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
|
||||
//~^ ERROR cannot find type `Idx` in this scope
|
||||
//~| ERROR cannot find type `Idx` in this scope
|
||||
type MySliceBool = MySlice<[bool]>;
|
||||
const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
|
||||
//~^ ERROR the size for values of type `[bool]` cannot be known at compilation time
|
||||
//~| ERROR the size for values of type `[bool]` cannot be known at compilation time
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,57 @@
|
||||
error[E0412]: cannot find type `Idx` in this scope
|
||||
--> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:30
|
||||
|
|
||||
LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0412]: cannot find type `Idx` in this scope
|
||||
--> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:38
|
||||
|
|
||||
LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0277]: the size for values of type `[bool]` cannot be known at compilation time
|
||||
--> $DIR/ice-unsized-struct-arg-issue-121612.rs:9:22
|
||||
|
|
||||
LL | const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
|
||||
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `[bool]`
|
||||
note: required by an implicit `Sized` bound in `MySlice`
|
||||
--> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:16
|
||||
|
|
||||
LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
|
||||
| ^ required by the implicit `Sized` requirement on this type parameter in `MySlice`
|
||||
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
|
||||
--> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:16
|
||||
|
|
||||
LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
|
||||
| ^ - ...if indirection were used here: `Box<T>`
|
||||
| |
|
||||
| this could be changed to `T: ?Sized`...
|
||||
|
||||
error[E0277]: the size for values of type `[bool]` cannot be known at compilation time
|
||||
--> $DIR/ice-unsized-struct-arg-issue-121612.rs:9:22
|
||||
|
|
||||
LL | const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
|
||||
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `[bool]`
|
||||
note: required by an implicit `Sized` bound in `MySlice`
|
||||
--> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:16
|
||||
|
|
||||
LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
|
||||
| ^ required by the implicit `Sized` requirement on this type parameter in `MySlice`
|
||||
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
|
||||
--> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:16
|
||||
|
|
||||
LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
|
||||
| ^ - ...if indirection were used here: `Box<T>`
|
||||
| |
|
||||
| this could be changed to `T: ?Sized`...
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0412.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
@ -0,0 +1,9 @@
|
||||
// Regression test for issue #121424
|
||||
#[repr(C)]
|
||||
struct MySlice<T: Copy>(bool, T);
|
||||
type MySliceBool = MySlice<[bool]>;
|
||||
const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
|
||||
//~^ ERROR the trait bound `[bool]: Copy` is not satisfied
|
||||
//~| ERROR the trait bound `[bool]: Copy` is not satisfied
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,30 @@
|
||||
error[E0277]: the trait bound `[bool]: Copy` is not satisfied
|
||||
--> $DIR/ice-unsized-struct-arg-issue2-121424.rs:5:22
|
||||
|
|
||||
LL | const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
|
||||
| ^^^^^^^^^^^ the trait `Copy` is not implemented for `[bool]`
|
||||
|
|
||||
= help: the trait `Copy` is implemented for `[T; N]`
|
||||
note: required by a bound in `MySlice`
|
||||
--> $DIR/ice-unsized-struct-arg-issue2-121424.rs:3:19
|
||||
|
|
||||
LL | struct MySlice<T: Copy>(bool, T);
|
||||
| ^^^^ required by this bound in `MySlice`
|
||||
|
||||
error[E0277]: the trait bound `[bool]: Copy` is not satisfied
|
||||
--> $DIR/ice-unsized-struct-arg-issue2-121424.rs:5:22
|
||||
|
|
||||
LL | const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
|
||||
| ^^^^^^^^^^^ the trait `Copy` is not implemented for `[bool]`
|
||||
|
|
||||
= help: the trait `Copy` is implemented for `[T; N]`
|
||||
note: required by a bound in `MySlice`
|
||||
--> $DIR/ice-unsized-struct-arg-issue2-121424.rs:3:19
|
||||
|
|
||||
LL | struct MySlice<T: Copy>(bool, T);
|
||||
| ^^^^ required by this bound in `MySlice`
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user