mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #100456 - Dylan-DPC:rollup-fn17z9f, r=Dylan-DPC
Rollup of 9 pull requests Successful merges: - #100022 (Optimize thread ID generation) - #100030 (cleanup code w/ pointers in std a little) - #100229 (add -Zextra-const-ub-checks to enable more UB checking in const-eval) - #100247 (Generalize trait object generic param check to aliases.) - #100255 (Adding more verbose documentation for `std::fmt::Write`) - #100366 (errors: don't fail on broken primary translations) - #100396 (Suggest const and static for global variable) - #100409 (rustdoc: don't generate DOM element for operator) - #100443 (Add two let else regression tests) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
f22819bcce
@ -236,6 +236,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||
|
||||
const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
|
||||
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
|
||||
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
|
||||
}
|
||||
|
||||
fn load_mir(
|
||||
ecx: &InterpCx<'mir, 'tcx, Self>,
|
||||
instance: ty::InstanceDef<'tcx>,
|
||||
|
@ -436,24 +436,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
||||
type AllocExtra = ();
|
||||
type FrameExtra = ();
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_alignment(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
|
||||
// We do not check for alignment to avoid having to carry an `Align`
|
||||
// in `ConstValue::ByRef`.
|
||||
false
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn force_int_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
|
||||
// We do not support `force_int`.
|
||||
false
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
|
||||
false // for now, we don't enforce validity
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
|
||||
true
|
||||
|
@ -1005,6 +1005,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
/// It will error if the bits at the destination do not match the ones described by the layout.
|
||||
#[inline(always)]
|
||||
pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
|
||||
// Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
|
||||
// still correct to not use `ctfe_mode`: that mode is for validation of the final constant
|
||||
// value, it rules out things like `UnsafeCell` in awkward places. It also can make checking
|
||||
// recurse through references which, for now, we don't want here, either.
|
||||
self.validate_operand_internal(op, vec![], None, None)
|
||||
}
|
||||
}
|
||||
|
@ -273,40 +273,58 @@ pub trait Emitter {
|
||||
DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
|
||||
};
|
||||
|
||||
let bundle = match self.fluent_bundle() {
|
||||
Some(bundle) if bundle.has_message(&identifier) => bundle,
|
||||
_ => self.fallback_fluent_bundle(),
|
||||
let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> {
|
||||
let message = bundle.get_message(&identifier)?;
|
||||
let value = match attr {
|
||||
Some(attr) => message.get_attribute(attr)?.value(),
|
||||
None => message.value()?,
|
||||
};
|
||||
debug!(?message, ?value);
|
||||
|
||||
let mut errs = vec![];
|
||||
let translated = bundle.format_pattern(value, Some(&args), &mut errs);
|
||||
debug!(?translated, ?errs);
|
||||
Some((translated, errs))
|
||||
};
|
||||
|
||||
let message = bundle.get_message(&identifier).expect("missing diagnostic in fluent bundle");
|
||||
let value = match attr {
|
||||
Some(attr) => {
|
||||
if let Some(attr) = message.get_attribute(attr) {
|
||||
attr.value()
|
||||
} else {
|
||||
panic!("missing attribute `{attr}` in fluent message `{identifier}`")
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if let Some(value) = message.value() {
|
||||
value
|
||||
} else {
|
||||
panic!("missing value in fluent message `{identifier}`")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut err = vec![];
|
||||
let translated = bundle.format_pattern(value, Some(&args), &mut err);
|
||||
trace!(?translated, ?err);
|
||||
debug_assert!(
|
||||
err.is_empty(),
|
||||
"identifier: {:?}, args: {:?}, errors: {:?}",
|
||||
identifier,
|
||||
args,
|
||||
err
|
||||
);
|
||||
translated
|
||||
self.fluent_bundle()
|
||||
.and_then(|bundle| translate_with_bundle(bundle))
|
||||
// If `translate_with_bundle` returns `None` with the primary bundle, this is likely
|
||||
// just that the primary bundle doesn't contain the message being translated, so
|
||||
// proceed to the fallback bundle.
|
||||
//
|
||||
// However, when errors are produced from translation, then that means the translation
|
||||
// is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided).
|
||||
//
|
||||
// In debug builds, assert so that compiler devs can spot the broken translation and
|
||||
// fix it..
|
||||
.inspect(|(_, errs)| {
|
||||
debug_assert!(
|
||||
errs.is_empty(),
|
||||
"identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
|
||||
identifier,
|
||||
attr,
|
||||
args,
|
||||
errs
|
||||
);
|
||||
})
|
||||
// ..otherwise, for end users, an error about this wouldn't be useful or actionable, so
|
||||
// just hide it and try with the fallback bundle.
|
||||
.filter(|(_, errs)| errs.is_empty())
|
||||
.or_else(|| translate_with_bundle(self.fallback_fluent_bundle()))
|
||||
.map(|(translated, errs)| {
|
||||
// Always bail out for errors with the fallback bundle.
|
||||
assert!(
|
||||
errs.is_empty(),
|
||||
"identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
|
||||
identifier,
|
||||
attr,
|
||||
args,
|
||||
errs
|
||||
);
|
||||
translated
|
||||
})
|
||||
.expect("failed to find message in primary or fallback fluent bundles")
|
||||
}
|
||||
|
||||
/// Formats the substitutions of the primary_span
|
||||
|
@ -6,9 +6,10 @@
|
||||
#![feature(drain_filter)]
|
||||
#![feature(if_let_guard)]
|
||||
#![cfg_attr(bootstrap, feature(let_chains))]
|
||||
#![feature(adt_const_params)]
|
||||
#![feature(let_else)]
|
||||
#![feature(never_type)]
|
||||
#![feature(adt_const_params)]
|
||||
#![feature(result_option_inspect)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(incomplete_features)]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
|
@ -183,6 +183,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
||||
|
||||
type MemoryKind = !;
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
|
||||
// We do not check for alignment to avoid having to carry an `Align`
|
||||
// in `ConstValue::ByRef`.
|
||||
false
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
|
||||
false // for now, we don't enforce validity
|
||||
}
|
||||
|
||||
fn load_mir(
|
||||
_ecx: &InterpCx<'mir, 'tcx, Self>,
|
||||
_instance: ty::InstanceDef<'tcx>,
|
||||
|
@ -68,7 +68,12 @@ impl<'a> Parser<'a> {
|
||||
if !self.maybe_consume_incorrect_semicolon(&items) {
|
||||
let msg = &format!("expected item, found {token_str}");
|
||||
let mut err = self.struct_span_err(self.token.span, msg);
|
||||
err.span_label(self.token.span, "expected item");
|
||||
let label = if self.is_kw_followed_by_ident(kw::Let) {
|
||||
"consider using `const` or `static` instead of `let` for global variables"
|
||||
} else {
|
||||
"expected item"
|
||||
};
|
||||
err.span_label(self.token.span, label);
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
@ -1310,6 +1310,8 @@ options! {
|
||||
"emit the bc module with thin LTO info (default: yes)"),
|
||||
export_executable_symbols: bool = (false, parse_bool, [TRACKED],
|
||||
"export symbols from executables, as if they were dynamic libraries"),
|
||||
extra_const_ub_checks: bool = (false, parse_bool, [TRACKED],
|
||||
"turns on more checks to detect const UB, which can be slow (default: no)"),
|
||||
#[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field"))]
|
||||
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
|
||||
|
@ -44,7 +44,7 @@ use rustc_trait_selection::traits::error_reporting::{
|
||||
};
|
||||
use rustc_trait_selection::traits::wf::object_region_bounds;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::collections::BTreeSet;
|
||||
use std::slice;
|
||||
|
||||
@ -368,36 +368,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
return (tcx.intern_substs(&[]), arg_count);
|
||||
}
|
||||
|
||||
let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self);
|
||||
|
||||
struct SubstsForAstPathCtxt<'a, 'tcx> {
|
||||
astconv: &'a (dyn AstConv<'tcx> + 'a),
|
||||
def_id: DefId,
|
||||
generic_args: &'a GenericArgs<'a>,
|
||||
span: Span,
|
||||
missing_type_params: Vec<Symbol>,
|
||||
inferred_params: Vec<Span>,
|
||||
infer_args: bool,
|
||||
is_object: bool,
|
||||
}
|
||||
|
||||
impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> {
|
||||
fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool {
|
||||
let tcx = self.astconv.tcx();
|
||||
if let GenericParamDefKind::Type { has_default, .. } = param.kind {
|
||||
if self.is_object && has_default {
|
||||
let default_ty = tcx.at(self.span).type_of(param.def_id);
|
||||
let self_param = tcx.types.self_param;
|
||||
if default_ty.walk().any(|arg| arg == self_param.into()) {
|
||||
// There is no suitable inference default for a type parameter
|
||||
// that references self, in an object type.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> {
|
||||
@ -500,41 +477,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
GenericParamDefKind::Type { has_default, .. } => {
|
||||
if !infer_args && has_default {
|
||||
// No type parameter provided, but a default exists.
|
||||
|
||||
// If we are converting an object type, then the
|
||||
// `Self` parameter is unknown. However, some of the
|
||||
// other type parameters may reference `Self` in their
|
||||
// defaults. This will lead to an ICE if we are not
|
||||
// careful!
|
||||
if self.default_needs_object_self(param) {
|
||||
self.missing_type_params.push(param.name);
|
||||
tcx.ty_error().into()
|
||||
} else {
|
||||
// This is a default type parameter.
|
||||
let substs = substs.unwrap();
|
||||
if substs.iter().any(|arg| match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => ty.references_error(),
|
||||
_ => false,
|
||||
}) {
|
||||
// Avoid ICE #86756 when type error recovery goes awry.
|
||||
return tcx.ty_error().into();
|
||||
}
|
||||
self.astconv
|
||||
.normalize_ty(
|
||||
self.span,
|
||||
EarlyBinder(tcx.at(self.span).type_of(param.def_id))
|
||||
.subst(tcx, substs),
|
||||
)
|
||||
.into()
|
||||
let substs = substs.unwrap();
|
||||
if substs.iter().any(|arg| match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => ty.references_error(),
|
||||
_ => false,
|
||||
}) {
|
||||
// Avoid ICE #86756 when type error recovery goes awry.
|
||||
return tcx.ty_error().into();
|
||||
}
|
||||
self.astconv
|
||||
.normalize_ty(
|
||||
self.span,
|
||||
EarlyBinder(tcx.at(self.span).type_of(param.def_id))
|
||||
.subst(tcx, substs),
|
||||
)
|
||||
.into()
|
||||
} else if infer_args {
|
||||
// No type parameters were provided, we can infer all.
|
||||
let param = if !self.default_needs_object_self(param) {
|
||||
Some(param)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.astconv.ty_infer(param, self.span).into()
|
||||
self.astconv.ty_infer(Some(param), self.span).into()
|
||||
} else {
|
||||
// We've already errored above about the mismatch.
|
||||
tcx.ty_error().into()
|
||||
@ -564,10 +523,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
def_id,
|
||||
span,
|
||||
generic_args,
|
||||
missing_type_params: vec![],
|
||||
inferred_params: vec![],
|
||||
infer_args,
|
||||
is_object,
|
||||
};
|
||||
let substs = Self::create_substs_for_generic_args(
|
||||
tcx,
|
||||
@ -579,13 +536,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
&mut substs_ctx,
|
||||
);
|
||||
|
||||
self.complain_about_missing_type_params(
|
||||
substs_ctx.missing_type_params,
|
||||
def_id,
|
||||
span,
|
||||
generic_args.args.is_empty(),
|
||||
);
|
||||
|
||||
debug!(
|
||||
"create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}",
|
||||
generics, self_ty, substs
|
||||
@ -1490,23 +1440,71 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
// Erase the `dummy_self` (`trait_object_dummy_self`) used above.
|
||||
let existential_trait_refs = regular_traits.iter().map(|i| {
|
||||
i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
|
||||
if trait_ref.self_ty() != dummy_self {
|
||||
// FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
|
||||
// which picks up non-supertraits where clauses - but also, the object safety
|
||||
// completely ignores trait aliases, which could be object safety hazards. We
|
||||
// `delay_span_bug` here to avoid an ICE in stable even when the feature is
|
||||
// disabled. (#66420)
|
||||
tcx.sess.delay_span_bug(
|
||||
DUMMY_SP,
|
||||
&format!(
|
||||
"trait_ref_to_existential called on {:?} with non-dummy Self",
|
||||
trait_ref,
|
||||
),
|
||||
assert_eq!(trait_ref.self_ty(), dummy_self);
|
||||
|
||||
// Verify that `dummy_self` did not leak inside default type parameters. This
|
||||
// could not be done at path creation, since we need to see through trait aliases.
|
||||
let mut missing_type_params = vec![];
|
||||
let mut references_self = false;
|
||||
let generics = tcx.generics_of(trait_ref.def_id);
|
||||
let substs: Vec<_> = trait_ref
|
||||
.substs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(1) // Remove `Self` for `ExistentialPredicate`.
|
||||
.map(|(index, arg)| {
|
||||
if let ty::GenericArgKind::Type(ty) = arg.unpack() {
|
||||
debug!(?ty);
|
||||
if ty == dummy_self {
|
||||
let param = &generics.params[index];
|
||||
missing_type_params.push(param.name);
|
||||
tcx.ty_error().into()
|
||||
} else if ty.walk().any(|arg| arg == dummy_self.into()) {
|
||||
references_self = true;
|
||||
tcx.ty_error().into()
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let substs = tcx.intern_substs(&substs[..]);
|
||||
|
||||
let span = i.bottom().1;
|
||||
let empty_generic_args = trait_bounds.iter().any(|hir_bound| {
|
||||
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
|
||||
&& hir_bound.span.contains(span)
|
||||
});
|
||||
self.complain_about_missing_type_params(
|
||||
missing_type_params,
|
||||
trait_ref.def_id,
|
||||
span,
|
||||
empty_generic_args,
|
||||
);
|
||||
|
||||
if references_self {
|
||||
let def_id = i.bottom().0.def_id();
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
i.bottom().1,
|
||||
E0038,
|
||||
"the {} `{}` cannot be made into an object",
|
||||
tcx.def_kind(def_id).descr(def_id),
|
||||
tcx.item_name(def_id),
|
||||
);
|
||||
err.note(
|
||||
rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![])
|
||||
.error_msg(),
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
||||
|
||||
ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs }
|
||||
})
|
||||
});
|
||||
|
||||
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
|
||||
bound.map_bound(|b| {
|
||||
if b.projection_ty.self_ty() != dummy_self {
|
||||
|
@ -74,7 +74,7 @@ use crate::ptr;
|
||||
/// {
|
||||
/// return null_mut();
|
||||
/// };
|
||||
/// (self.arena.get() as *mut u8).add(allocated)
|
||||
/// self.arena.get().cast::<u8>().add(allocated)
|
||||
/// }
|
||||
/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
|
||||
/// }
|
||||
|
@ -119,6 +119,10 @@ pub trait Write {
|
||||
///
|
||||
/// This function will return an instance of [`Error`] on error.
|
||||
///
|
||||
/// The purpose of std::fmt::Error is to abort the formatting operation when the underlying
|
||||
/// destination encounters some error preventing it from accepting more text; it should
|
||||
/// generally be propagated rather than handled, at least when implementing formatting traits.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
@ -1267,20 +1267,21 @@ impl<T: ?Sized> *const T {
|
||||
/// Accessing adjacent `u8` as `u16`
|
||||
///
|
||||
/// ```
|
||||
/// # fn foo(n: usize) {
|
||||
/// # use std::mem::align_of;
|
||||
/// use std::mem::align_of;
|
||||
///
|
||||
/// # unsafe {
|
||||
/// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
|
||||
/// let ptr = x.as_ptr().add(n) as *const u8;
|
||||
/// let x = [5_u8, 6, 7, 8, 9];
|
||||
/// let ptr = x.as_ptr();
|
||||
/// let offset = ptr.align_offset(align_of::<u16>());
|
||||
/// if offset < x.len() - n - 1 {
|
||||
/// let u16_ptr = ptr.add(offset) as *const u16;
|
||||
/// assert_ne!(*u16_ptr, 500);
|
||||
///
|
||||
/// if offset < x.len() - 1 {
|
||||
/// let u16_ptr = ptr.add(offset).cast::<u16>();
|
||||
/// assert!(*u16_ptr == u16::from_ne_bytes([5, 6]) || *u16_ptr == u16::from_ne_bytes([6, 7]));
|
||||
/// } else {
|
||||
/// // while the pointer can be aligned via `offset`, it would point
|
||||
/// // outside the allocation
|
||||
/// }
|
||||
/// # } }
|
||||
/// # }
|
||||
/// ```
|
||||
#[stable(feature = "align_offset", since = "1.36.0")]
|
||||
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
|
||||
|
@ -1545,20 +1545,23 @@ impl<T: ?Sized> *mut T {
|
||||
/// Accessing adjacent `u8` as `u16`
|
||||
///
|
||||
/// ```
|
||||
/// # fn foo(n: usize) {
|
||||
/// # use std::mem::align_of;
|
||||
/// use std::mem::align_of;
|
||||
///
|
||||
/// # unsafe {
|
||||
/// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
|
||||
/// let ptr = x.as_ptr().add(n) as *const u8;
|
||||
/// let mut x = [5_u8, 6, 7, 8, 9];
|
||||
/// let ptr = x.as_mut_ptr();
|
||||
/// let offset = ptr.align_offset(align_of::<u16>());
|
||||
/// if offset < x.len() - n - 1 {
|
||||
/// let u16_ptr = ptr.add(offset) as *const u16;
|
||||
/// assert_ne!(*u16_ptr, 500);
|
||||
///
|
||||
/// if offset < x.len() - 1 {
|
||||
/// let u16_ptr = ptr.add(offset).cast::<u16>();
|
||||
/// *u16_ptr = 0;
|
||||
///
|
||||
/// assert!(x == [0, 0, 7, 8, 9] || x == [5, 0, 0, 8, 9]);
|
||||
/// } else {
|
||||
/// // while the pointer can be aligned via `offset`, it would point
|
||||
/// // outside the allocation
|
||||
/// }
|
||||
/// # } }
|
||||
/// # }
|
||||
/// ```
|
||||
#[stable(feature = "align_offset", since = "1.36.0")]
|
||||
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
|
||||
|
@ -92,7 +92,7 @@ impl<'a, T> Iter<'a, T> {
|
||||
assume(!ptr.is_null());
|
||||
|
||||
let end = if mem::size_of::<T>() == 0 {
|
||||
(ptr as *const u8).wrapping_add(slice.len()) as *const T
|
||||
ptr.wrapping_byte_add(slice.len())
|
||||
} else {
|
||||
ptr.add(slice.len())
|
||||
};
|
||||
@ -228,7 +228,7 @@ impl<'a, T> IterMut<'a, T> {
|
||||
assume(!ptr.is_null());
|
||||
|
||||
let end = if mem::size_of::<T>() == 0 {
|
||||
(ptr as *mut u8).wrapping_add(slice.len()) as *mut T
|
||||
ptr.wrapping_byte_add(slice.len())
|
||||
} else {
|
||||
ptr.add(slice.len())
|
||||
};
|
||||
|
@ -3,7 +3,7 @@ const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x
|
||||
|
||||
const fn unaligned_ptr() -> *const u16 {
|
||||
// Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16
|
||||
unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 }
|
||||
unsafe { DATA.as_ptr().byte_add(1) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -67,7 +67,7 @@ fn write() {
|
||||
const fn write_unaligned() -> [u16; 2] {
|
||||
let mut two_aligned = [0u16; 2];
|
||||
unsafe {
|
||||
let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
|
||||
let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1);
|
||||
ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45]));
|
||||
}
|
||||
two_aligned
|
||||
@ -91,7 +91,7 @@ fn mut_ptr_write() {
|
||||
const fn write_unaligned() -> [u16; 2] {
|
||||
let mut two_aligned = [0u16; 2];
|
||||
unsafe {
|
||||
let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
|
||||
let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1);
|
||||
unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45]));
|
||||
}
|
||||
two_aligned
|
||||
|
@ -14,6 +14,7 @@
|
||||
#![feature(const_maybe_uninit_assume_init_read)]
|
||||
#![feature(const_nonnull_new)]
|
||||
#![feature(const_num_from_num)]
|
||||
#![feature(const_pointer_byte_offsets)]
|
||||
#![feature(const_ptr_as_ref)]
|
||||
#![feature(const_ptr_read)]
|
||||
#![feature(const_ptr_write)]
|
||||
@ -74,6 +75,7 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(unwrap_infallible)]
|
||||
#![feature(result_into_ok_or_err)]
|
||||
#![feature(pointer_byte_offsets)]
|
||||
#![feature(portable_simd)]
|
||||
#![feature(ptr_metadata)]
|
||||
#![feature(once_cell)]
|
||||
|
@ -115,7 +115,7 @@ pub unsafe trait UserSafe {
|
||||
/// * the pointer is null.
|
||||
/// * the pointed-to range is not in user memory.
|
||||
unsafe fn check_ptr(ptr: *const Self) {
|
||||
let is_aligned = |p| -> bool { 0 == (p as usize) & (Self::align_of() - 1) };
|
||||
let is_aligned = |p: *const u8| -> bool { 0 == p.addr() & (Self::align_of() - 1) };
|
||||
|
||||
assert!(is_aligned(ptr as *const u8));
|
||||
assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr })));
|
||||
|
@ -1,15 +1,16 @@
|
||||
use crate::alloc::{GlobalAlloc, Layout, System};
|
||||
use crate::ptr::null_mut;
|
||||
|
||||
#[stable(feature = "alloc_system_type", since = "1.28.0")]
|
||||
unsafe impl GlobalAlloc for System {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
|
||||
0 as *mut u8
|
||||
null_mut()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&self, _layout: Layout) -> *mut u8 {
|
||||
0 as *mut u8
|
||||
null_mut()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -17,6 +18,6 @@ unsafe impl GlobalAlloc for System {
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(&self, _ptr: *mut u8, _layout: Layout, _new_size: usize) -> *mut u8 {
|
||||
0 as *mut u8
|
||||
null_mut()
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +170,6 @@ use crate::ptr::addr_of_mut;
|
||||
use crate::str;
|
||||
use crate::sync::Arc;
|
||||
use crate::sys::thread as imp;
|
||||
use crate::sys_common::mutex;
|
||||
use crate::sys_common::thread;
|
||||
use crate::sys_common::thread_info;
|
||||
use crate::sys_common::thread_parker::Parker;
|
||||
@ -1033,24 +1032,48 @@ pub struct ThreadId(NonZeroU64);
|
||||
impl ThreadId {
|
||||
// Generate a new unique thread ID.
|
||||
fn new() -> ThreadId {
|
||||
// It is UB to attempt to acquire this mutex reentrantly!
|
||||
static GUARD: mutex::StaticMutex = mutex::StaticMutex::new();
|
||||
static mut COUNTER: u64 = 1;
|
||||
#[cold]
|
||||
fn exhausted() -> ! {
|
||||
panic!("failed to generate unique thread ID: bitspace exhausted")
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let guard = GUARD.lock();
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_has_atomic = "64")] {
|
||||
use crate::sync::atomic::{AtomicU64, Ordering::Relaxed};
|
||||
|
||||
// If we somehow use up all our bits, panic so that we're not
|
||||
// covering up subtle bugs of IDs being reused.
|
||||
if COUNTER == u64::MAX {
|
||||
drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
|
||||
panic!("failed to generate unique thread ID: bitspace exhausted");
|
||||
static COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
let mut last = COUNTER.load(Relaxed);
|
||||
loop {
|
||||
let Some(id) = last.checked_add(1) else {
|
||||
exhausted();
|
||||
};
|
||||
|
||||
match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) {
|
||||
Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()),
|
||||
Err(id) => last = id,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
use crate::sys_common::mutex::StaticMutex;
|
||||
|
||||
// It is UB to attempt to acquire this mutex reentrantly!
|
||||
static GUARD: StaticMutex = StaticMutex::new();
|
||||
static mut COUNTER: u64 = 0;
|
||||
|
||||
unsafe {
|
||||
let guard = GUARD.lock();
|
||||
|
||||
let Some(id) = COUNTER.checked_add(1) else {
|
||||
drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
|
||||
exhausted();
|
||||
};
|
||||
|
||||
COUNTER = id;
|
||||
drop(guard);
|
||||
ThreadId(NonZeroU64::new(id).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
let id = COUNTER;
|
||||
COUNTER += 1;
|
||||
|
||||
ThreadId(NonZeroU64::new(id).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,6 @@ enum Class {
|
||||
// Keywords that do pointer/reference stuff.
|
||||
RefKeyWord,
|
||||
Self_(Span),
|
||||
Op,
|
||||
Macro(Span),
|
||||
MacroNonTerminal,
|
||||
String,
|
||||
@ -187,7 +186,6 @@ impl Class {
|
||||
Class::KeyWord => "kw",
|
||||
Class::RefKeyWord => "kw-2",
|
||||
Class::Self_(_) => "self",
|
||||
Class::Op => "op",
|
||||
Class::Macro(_) => "macro",
|
||||
Class::MacroNonTerminal => "macro-nonterminal",
|
||||
Class::String => "string",
|
||||
@ -212,7 +210,6 @@ impl Class {
|
||||
| Self::Attribute
|
||||
| Self::KeyWord
|
||||
| Self::RefKeyWord
|
||||
| Self::Op
|
||||
| Self::MacroNonTerminal
|
||||
| Self::String
|
||||
| Self::Number
|
||||
@ -516,7 +513,7 @@ impl<'a> Classifier<'a> {
|
||||
// or a reference or pointer type. Unless, of course, it looks like
|
||||
// a logical and or a multiplication operator: `&&` or `* `.
|
||||
TokenKind::Star => match self.tokens.peek() {
|
||||
Some((TokenKind::Whitespace, _)) => Class::Op,
|
||||
Some((TokenKind::Whitespace, _)) => return no_highlight(sink),
|
||||
Some((TokenKind::Ident, "mut")) => {
|
||||
self.next();
|
||||
sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) });
|
||||
@ -532,15 +529,15 @@ impl<'a> Classifier<'a> {
|
||||
TokenKind::And => match self.tokens.peek() {
|
||||
Some((TokenKind::And, _)) => {
|
||||
self.next();
|
||||
sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
|
||||
sink(Highlight::Token { text: "&&", class: None });
|
||||
return;
|
||||
}
|
||||
Some((TokenKind::Eq, _)) => {
|
||||
self.next();
|
||||
sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
|
||||
sink(Highlight::Token { text: "&=", class: None });
|
||||
return;
|
||||
}
|
||||
Some((TokenKind::Whitespace, _)) => Class::Op,
|
||||
Some((TokenKind::Whitespace, _)) => return no_highlight(sink),
|
||||
Some((TokenKind::Ident, "mut")) => {
|
||||
self.next();
|
||||
sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) });
|
||||
@ -553,7 +550,7 @@ impl<'a> Classifier<'a> {
|
||||
TokenKind::Eq => match lookahead {
|
||||
Some(TokenKind::Eq) => {
|
||||
self.next();
|
||||
sink(Highlight::Token { text: "==", class: Some(Class::Op) });
|
||||
sink(Highlight::Token { text: "==", class: None });
|
||||
return;
|
||||
}
|
||||
Some(TokenKind::Gt) => {
|
||||
@ -561,7 +558,7 @@ impl<'a> Classifier<'a> {
|
||||
sink(Highlight::Token { text: "=>", class: None });
|
||||
return;
|
||||
}
|
||||
_ => Class::Op,
|
||||
_ => return no_highlight(sink),
|
||||
},
|
||||
TokenKind::Minus if lookahead == Some(TokenKind::Gt) => {
|
||||
self.next();
|
||||
@ -578,7 +575,7 @@ impl<'a> Classifier<'a> {
|
||||
| TokenKind::Percent
|
||||
| TokenKind::Bang
|
||||
| TokenKind::Lt
|
||||
| TokenKind::Gt => Class::Op,
|
||||
| TokenKind::Gt => return no_highlight(sink),
|
||||
|
||||
// Miscellaneous, no highlighting.
|
||||
TokenKind::Dot
|
||||
|
@ -1,2 +1,2 @@
|
||||
<span class="example"><span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="number">1</span>;</span>
|
||||
<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="number">2</span>;
|
||||
<span class="example"><span class="kw">let</span> <span class="ident">x</span> = <span class="number">1</span>;</span>
|
||||
<span class="kw">let</span> <span class="ident">y</span> = <span class="number">2</span>;
|
@ -1,4 +1,4 @@
|
||||
<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::a::foo</span>;
|
||||
<span class="kw">use</span> <span class="ident"><span class="self">self</span>::whatever</span>;
|
||||
<span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="ident"><span class="kw">super</span>::b::foo</span>;
|
||||
<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="ident"><span class="self">Self</span>::whatever</span>;
|
||||
<span class="kw">let</span> <span class="ident">x</span> = <span class="ident"><span class="kw">super</span>::b::foo</span>;
|
||||
<span class="kw">let</span> <span class="ident">y</span> = <span class="ident"><span class="self">Self</span>::whatever</span>;
|
@ -8,23 +8,23 @@
|
||||
.lifetime { color: #B76514; }
|
||||
.question-mark { color: #ff9011; }
|
||||
</style>
|
||||
<pre><code><span class="attribute">#![<span class="ident">crate_type</span> <span class="op">=</span> <span class="string">"lib"</span>]</span>
|
||||
<pre><code><span class="attribute">#![<span class="ident">crate_type</span> = <span class="string">"lib"</span>]</span>
|
||||
|
||||
<span class="kw">use</span> <span class="ident">std::path</span>::{<span class="ident">Path</span>, <span class="ident">PathBuf</span>};
|
||||
|
||||
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">target_os</span> <span class="op">=</span> <span class="string">"linux"</span>)]</span>
|
||||
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">target_os</span> = <span class="string">"linux"</span>)]</span>
|
||||
<span class="kw">fn</span> <span class="ident">main</span>() -> () {
|
||||
<span class="kw">let</span> <span class="ident">foo</span> <span class="op">=</span> <span class="bool-val">true</span> <span class="op">&&</span> <span class="bool-val">false</span> <span class="op">|</span><span class="op">|</span> <span class="bool-val">true</span>;
|
||||
<span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*const</span> () <span class="op">=</span> <span class="number">0</span>;
|
||||
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">&</span><span class="ident">foo</span>;
|
||||
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="op">&&</span><span class="ident">foo</span>;
|
||||
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">*</span><span class="ident">foo</span>;
|
||||
<span class="kw">let</span> <span class="ident">foo</span> = <span class="bool-val">true</span> && <span class="bool-val">false</span> || <span class="bool-val">true</span>;
|
||||
<span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*const</span> () = <span class="number">0</span>;
|
||||
<span class="kw">let</span> <span class="kw">_</span> = <span class="kw-2">&</span><span class="ident">foo</span>;
|
||||
<span class="kw">let</span> <span class="kw">_</span> = &&<span class="ident">foo</span>;
|
||||
<span class="kw">let</span> <span class="kw">_</span> = <span class="kw-2">*</span><span class="ident">foo</span>;
|
||||
<span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&mut</span> <span class="ident">bar</span>);
|
||||
<span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op"><</span> <span class="ident">N</span> <span class="op">&&</span> <span class="ident">index</span> <span class="op"><</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>);
|
||||
<span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> < <span class="ident">N</span> && <span class="ident">index</span> <= <span class="self">self</span>.<span class="ident">length</span>);
|
||||
<span class="ident">::std::env::var</span>(<span class="string">"gateau"</span>).<span class="ident">is_ok</span>();
|
||||
<span class="attribute">#[<span class="ident">rustfmt::skip</span>]</span>
|
||||
<span class="kw">let</span> <span class="ident">s</span>:<span class="ident">std::path::PathBuf</span> <span class="op">=</span> <span class="ident">std::path::PathBuf::new</span>();
|
||||
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">s</span> <span class="op">=</span> <span class="ident">String::new</span>();
|
||||
<span class="kw">let</span> <span class="ident">s</span>:<span class="ident">std::path::PathBuf</span> = <span class="ident">std::path::PathBuf::new</span>();
|
||||
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">s</span> = <span class="ident">String::new</span>();
|
||||
|
||||
<span class="kw">match</span> <span class="kw-2">&</span><span class="ident">s</span> {
|
||||
<span class="kw-2">ref</span> <span class="kw-2">mut</span> <span class="ident">x</span> => {}
|
||||
|
@ -4,5 +4,5 @@
|
||||
}
|
||||
|
||||
<span class="kw">fn</span> <span class="ident">main</span>() {
|
||||
<span class="kw">let</span> <span class="ident">union</span> <span class="op">=</span> <span class="number">0</span>;
|
||||
<span class="kw">let</span> <span class="ident">union</span> = <span class="number">0</span>;
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ details.rustdoc-toggle > summary::before {
|
||||
pre.rust .number, pre.rust .string { color: #b8cc52; }
|
||||
pre.rust .kw, pre.rust .kw-2, pre.rust .prelude-ty,
|
||||
pre.rust .bool-val, pre.rust .prelude-val,
|
||||
pre.rust .op, pre.rust .lifetime { color: #ff7733; }
|
||||
pre.rust .lifetime { color: #ff7733; }
|
||||
pre.rust .macro, pre.rust .macro-nonterminal { color: #a37acc; }
|
||||
pre.rust .question-mark {
|
||||
color: #ff9011;
|
||||
@ -250,7 +250,7 @@ pre.rust .self {
|
||||
pre.rust .attribute {
|
||||
color: #e6e1cf;
|
||||
}
|
||||
pre.rust .attribute .ident, pre.rust .attribute .op {
|
||||
pre.rust .attribute .ident {
|
||||
color: #e6e1cf;
|
||||
}
|
||||
|
||||
|
@ -9,16 +9,29 @@ FAKEROOT=$(TMPDIR)/fakeroot
|
||||
|
||||
all: normal custom sysroot
|
||||
|
||||
normal: basic-translation.rs
|
||||
# Check that the test works normally, using the built-in fallback bundle.
|
||||
normal: test.rs
|
||||
$(RUSTC) $< 2>&1 | grep "struct literal body without path"
|
||||
|
||||
custom: basic-translation.rs basic-translation.ftl
|
||||
$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/basic-translation.ftl 2>&1 | grep "this is a test message"
|
||||
# Check that a primary bundle can be loaded and will be preferentially used
|
||||
# where possible.
|
||||
custom: test.rs working.ftl
|
||||
$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/working.ftl 2>&1 | grep "this is a test message"
|
||||
|
||||
# Check that a primary bundle with a broken message (e.g. a interpolated
|
||||
# variable is missing) will use the fallback bundle.
|
||||
missing: test.rs missing.ftl
|
||||
$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/missing.ftl 2>&1 | grep "struct literal body without path"
|
||||
|
||||
# Check that a primary bundle without the desired message will use the fallback
|
||||
# bundle.
|
||||
broken: test.rs broken.ftl
|
||||
$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/broken.ftl 2>&1 | grep "struct literal body without path"
|
||||
|
||||
# Check that a locale can be loaded from the sysroot given a language
|
||||
# identifier by making a local copy of the sysroot and adding the custom locale
|
||||
# to it.
|
||||
sysroot: basic-translation.rs basic-translation.ftl
|
||||
sysroot: test.rs working.ftl
|
||||
mkdir $(FAKEROOT)
|
||||
ln -s $(SYSROOT)/* $(FAKEROOT)
|
||||
rm -f $(FAKEROOT)/lib
|
||||
@ -31,7 +44,7 @@ sysroot: basic-translation.rs basic-translation.ftl
|
||||
mkdir $(FAKEROOT)/lib/rustlib/src
|
||||
ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src
|
||||
mkdir -p $(FAKEROOT)/share/locale/zh-CN/
|
||||
ln -s $(CURDIR)/basic-translation.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl
|
||||
ln -s $(CURDIR)/working.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl
|
||||
$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | grep "this is a test message"
|
||||
|
||||
# Check that the compiler errors out when the sysroot requested cannot be
|
||||
@ -43,7 +56,7 @@ sysroot-missing:
|
||||
# Check that the compiler errors out when the sysroot requested cannot be
|
||||
# found. This test might start failing if there actually exists a Klingon
|
||||
# translation of rustc's error messages.
|
||||
sysroot-invalid: basic-translation.rs basic-translation.ftl
|
||||
sysroot-invalid: test.rs working.ftl
|
||||
mkdir $(FAKEROOT)
|
||||
ln -s $(SYSROOT)/* $(FAKEROOT)
|
||||
rm -f $(FAKEROOT)/lib
|
||||
|
3
src/test/run-make/translation/broken.ftl
Normal file
3
src/test/run-make/translation/broken.ftl
Normal file
@ -0,0 +1,3 @@
|
||||
# `foo` isn't provided by this diagnostic so it is expected that the fallback message is used.
|
||||
parser-struct-literal-body-without-path = this is a {$foo} message
|
||||
.suggestion = this is a test suggestion
|
3
src/test/run-make/translation/missing.ftl
Normal file
3
src/test/run-make/translation/missing.ftl
Normal file
@ -0,0 +1,3 @@
|
||||
# `parser-struct-literal-body-without-path` isn't provided by this resource at all, so the
|
||||
# fallback should be used.
|
||||
foo = bar
|
@ -38,6 +38,7 @@
|
||||
-Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
|
||||
-Z emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes)
|
||||
-Z export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries
|
||||
-Z extra-const-ub-checks=val -- turns on more checks to detect const UB, which can be slow (default: no)
|
||||
-Z fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
|
||||
-Z force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
|
||||
-Z fuel=val -- set the optimization fuel quota for a crate
|
||||
|
@ -6,16 +6,13 @@
|
||||
// @has 'foo/macro.todo.html'
|
||||
// @has - '//span[@class="macro"]' 'macro_rules!'
|
||||
// @has - '//span[@class="ident"]' 'todo'
|
||||
// Note: the only op is the `+`
|
||||
// @count - '//pre[@class="rust macro"]//span[@class="op"]' 1
|
||||
|
||||
// @has - '{ () => { ... }; ($('
|
||||
// @has - '//span[@class="macro-nonterminal"]' '$'
|
||||
// @has - '//span[@class="macro-nonterminal"]' 'arg'
|
||||
// @has - ':'
|
||||
// @has - '//span[@class="ident"]' 'tt'
|
||||
// @has - '),'
|
||||
// @has - '//span[@class="op"]' '+'
|
||||
// @has - ')+'
|
||||
// @has - ') => { ... }; }'
|
||||
pub use std::todo;
|
||||
|
||||
|
@ -1,25 +1,3 @@
|
||||
error[E0393]: the type parameter `Rhs` must be explicitly specified
|
||||
--> $DIR/issue-22560.rs:9:23
|
||||
|
|
||||
LL | trait Sub<Rhs=Self> {
|
||||
| ------------------- type parameter `Rhs` must be specified for this
|
||||
...
|
||||
LL | type Test = dyn Add + Sub;
|
||||
| ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
|
||||
|
|
||||
= note: because of the default `Self` reference, type parameters must be specified on object types
|
||||
|
||||
error[E0393]: the type parameter `Rhs` must be explicitly specified
|
||||
--> $DIR/issue-22560.rs:9:17
|
||||
|
|
||||
LL | trait Add<Rhs=Self> {
|
||||
| ------------------- type parameter `Rhs` must be specified for this
|
||||
...
|
||||
LL | type Test = dyn Add + Sub;
|
||||
| ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
|
||||
|
|
||||
= note: because of the default `Self` reference, type parameters must be specified on object types
|
||||
|
||||
error[E0225]: only auto traits can be used as additional traits in a trait object
|
||||
--> $DIR/issue-22560.rs:9:23
|
||||
|
|
||||
@ -28,7 +6,7 @@ LL | type Test = dyn Add + Sub;
|
||||
| |
|
||||
| first non-auto trait
|
||||
|
|
||||
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}`
|
||||
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub {}`
|
||||
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||
|
||||
error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified
|
||||
@ -50,6 +28,28 @@ help: specify the associated types
|
||||
LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>;
|
||||
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0393]: the type parameter `Rhs` must be explicitly specified
|
||||
--> $DIR/issue-22560.rs:9:17
|
||||
|
|
||||
LL | trait Add<Rhs=Self> {
|
||||
| ------------------- type parameter `Rhs` must be specified for this
|
||||
...
|
||||
LL | type Test = dyn Add + Sub;
|
||||
| ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
|
||||
|
|
||||
= note: because of the default `Self` reference, type parameters must be specified on object types
|
||||
|
||||
error[E0393]: the type parameter `Rhs` must be explicitly specified
|
||||
--> $DIR/issue-22560.rs:9:23
|
||||
|
|
||||
LL | trait Sub<Rhs=Self> {
|
||||
| ------------------- type parameter `Rhs` must be specified for this
|
||||
...
|
||||
LL | type Test = dyn Add + Sub;
|
||||
| ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
|
||||
|
|
||||
= note: because of the default `Self` reference, type parameters must be specified on object types
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0191, E0225, E0393.
|
||||
|
45
src/test/ui/consts/extra-const-ub/detect-extra-ub.rs
Normal file
45
src/test/ui/consts/extra-const-ub/detect-extra-ub.rs
Normal file
@ -0,0 +1,45 @@
|
||||
// revisions: no_flag with_flag
|
||||
// [no_flag] check-pass
|
||||
// [with_flag] compile-flags: -Zextra-const-ub-checks
|
||||
#![feature(const_ptr_read)]
|
||||
|
||||
use std::mem::transmute;
|
||||
|
||||
const INVALID_BOOL: () = unsafe {
|
||||
let _x: bool = transmute(3u8);
|
||||
//[with_flag]~^ ERROR: evaluation of constant value failed
|
||||
//[with_flag]~| invalid value
|
||||
};
|
||||
|
||||
const INVALID_PTR_IN_INT: () = unsafe {
|
||||
let _x: usize = transmute(&3u8);
|
||||
//[with_flag]~^ ERROR: evaluation of constant value failed
|
||||
//[with_flag]~| invalid value
|
||||
};
|
||||
|
||||
const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe {
|
||||
let x: &[u8] = &[0; 32];
|
||||
let _x: (usize, usize) = transmute(x);
|
||||
//[with_flag]~^ ERROR: evaluation of constant value failed
|
||||
//[with_flag]~| invalid value
|
||||
};
|
||||
|
||||
const UNALIGNED_PTR: () = unsafe {
|
||||
let _x: &u32 = transmute(&[0u8; 4]);
|
||||
//[with_flag]~^ ERROR: evaluation of constant value failed
|
||||
//[with_flag]~| invalid value
|
||||
};
|
||||
|
||||
const UNALIGNED_READ: () = {
|
||||
INNER; //[with_flag]~ERROR any use of this value will cause an error
|
||||
//[with_flag]~| previously accepted
|
||||
// There is an error here but its span is in the standard library so we cannot match it...
|
||||
// so we have this in a *nested* const, such that the *outer* const fails to use it.
|
||||
const INNER: () = unsafe {
|
||||
let x = &[0u8; 4];
|
||||
let ptr = x.as_ptr().cast::<u32>();
|
||||
ptr.read();
|
||||
};
|
||||
};
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,71 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/detect-extra-ub.rs:9:20
|
||||
|
|
||||
LL | let _x: bool = transmute(3u8);
|
||||
| ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean
|
||||
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/detect-extra-ub.rs:15:21
|
||||
|
|
||||
LL | let _x: usize = transmute(&3u8);
|
||||
| ^^^^^^^^^^^^^^^ constructing invalid value: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
|
||||
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/detect-extra-ub.rs:22:30
|
||||
|
|
||||
LL | let _x: (usize, usize) = transmute(x);
|
||||
| ^^^^^^^^^^^^ constructing invalid value at .0: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
|
||||
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/detect-extra-ub.rs:28:20
|
||||
|
|
||||
LL | let _x: &u32 = transmute(&[0u8; 4]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
|
||||
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||
|
|
||||
LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| accessing memory with alignment 1, but alignment 4 is required
|
||||
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||
|
|
||||
::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | unsafe { read(self) }
|
||||
| ---------- inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
::: $DIR/detect-extra-ub.rs:41:9
|
||||
|
|
||||
LL | ptr.read();
|
||||
| ---------- inside `INNER` at $DIR/detect-extra-ub.rs:41:9
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/detect-extra-ub.rs:34:5
|
||||
|
|
||||
LL | const UNALIGNED_READ: () = {
|
||||
| ------------------------
|
||||
LL | INNER;
|
||||
| ^^^^^ referenced constant has errors
|
||||
|
|
||||
= note: `#[deny(const_err)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
Future incompatibility report: Future breakage diagnostic:
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/detect-extra-ub.rs:34:5
|
||||
|
|
||||
LL | const UNALIGNED_READ: () = {
|
||||
| ------------------------
|
||||
LL | INNER;
|
||||
| ^^^^^ referenced constant has errors
|
||||
|
|
||||
= note: `#[deny(const_err)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
trait Foo<X = Box<dyn Foo>> {
|
||||
//~^ ERROR cycle detected
|
||||
//~| ERROR cycle detected
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
@ -10,30 +10,11 @@ note: cycle used when collecting item types in top-level module
|
||||
|
|
||||
LL | / trait Foo<X = Box<dyn Foo>> {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
LL | |
|
||||
LL | | fn main() { }
|
||||
| |_____________^
|
||||
|
||||
error[E0391]: cycle detected when computing type of `Foo::X`
|
||||
--> $DIR/cycle-trait-default-type-trait.rs:4:23
|
||||
|
|
||||
LL | trait Foo<X = Box<dyn Foo>> {
|
||||
| ^^^
|
||||
|
|
||||
= note: ...which immediately requires computing type of `Foo::X` again
|
||||
note: cycle used when collecting item types in top-level module
|
||||
--> $DIR/cycle-trait-default-type-trait.rs:4:1
|
||||
|
|
||||
LL | / trait Foo<X = Box<dyn Foo>> {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
LL | |
|
||||
LL | | fn main() { }
|
||||
| |_____________^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0391`.
|
||||
|
@ -1,3 +1,12 @@
|
||||
error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified
|
||||
--> $DIR/issue-21950.rs:10:25
|
||||
|
|
||||
LL | type Output;
|
||||
| ----------- `Output` defined here
|
||||
...
|
||||
LL | let x = &10 as &dyn Add;
|
||||
| ^^^ help: specify the associated type: `Add<Output = Type>`
|
||||
|
||||
error[E0393]: the type parameter `Rhs` must be explicitly specified
|
||||
--> $DIR/issue-21950.rs:10:25
|
||||
|
|
||||
@ -9,15 +18,6 @@ LL | let x = &10 as &dyn Add;
|
||||
|
|
||||
= note: because of the default `Self` reference, type parameters must be specified on object types
|
||||
|
||||
error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified
|
||||
--> $DIR/issue-21950.rs:10:25
|
||||
|
|
||||
LL | type Output;
|
||||
| ----------- `Output` defined here
|
||||
...
|
||||
LL | let x = &10 as &dyn Add;
|
||||
| ^^^ help: specify the associated type: `Add<Output = Type>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0191, E0393.
|
||||
|
10
src/test/ui/let-else/issue-94176.rs
Normal file
10
src/test/ui/let-else/issue-94176.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// Issue #94176: wrong span for the error message of a mismatched type error,
|
||||
// if the function uses a `let else` construct.
|
||||
#![feature(let_else)]
|
||||
|
||||
pub fn test(a: Option<u32>) -> Option<u32> { //~ ERROR mismatched types
|
||||
let Some(_) = a else { return None; };
|
||||
println!("Foo");
|
||||
}
|
||||
|
||||
fn main() {}
|
19
src/test/ui/let-else/issue-94176.stderr
Normal file
19
src/test/ui/let-else/issue-94176.stderr
Normal file
@ -0,0 +1,19 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-94176.rs:5:32
|
||||
|
|
||||
LL | pub fn test(a: Option<u32>) -> Option<u32> {
|
||||
| ---- ^^^^^^^^^^^ expected enum `Option`, found `()`
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
|
||||
= note: expected enum `Option<u32>`
|
||||
found unit type `()`
|
||||
help: consider returning the local binding `a`
|
||||
|
|
||||
LL ~ println!("Foo");
|
||||
LL + a
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
19
src/test/ui/let-else/let-else-then-diverge.rs
Normal file
19
src/test/ui/let-else/let-else-then-diverge.rs
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// popped up in in #94012, where an alternative desugaring was
|
||||
// causing unreachable code errors
|
||||
|
||||
#![feature(let_else)]
|
||||
#![deny(unused_variables)]
|
||||
#![deny(unreachable_code)]
|
||||
|
||||
fn let_else_diverge() -> bool {
|
||||
let Some(_) = Some("test") else {
|
||||
let x = 5; //~ ERROR unused variable: `x`
|
||||
return false;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let_else_diverge();
|
||||
}
|
14
src/test/ui/let-else/let-else-then-diverge.stderr
Normal file
14
src/test/ui/let-else/let-else-then-diverge.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error: unused variable: `x`
|
||||
--> $DIR/let-else-then-diverge.rs:11:13
|
||||
|
|
||||
LL | let x = 5;
|
||||
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/let-else-then-diverge.rs:6:9
|
||||
|
|
||||
LL | #![deny(unused_variables)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
6
src/test/ui/parser/suggest-const-for-global-var.rs
Normal file
6
src/test/ui/parser/suggest-const-for-global-var.rs
Normal file
@ -0,0 +1,6 @@
|
||||
let X: i32 = 12;
|
||||
//~^ ERROR expected item, found keyword `let`
|
||||
|
||||
fn main() {
|
||||
println!("{}", X);
|
||||
}
|
8
src/test/ui/parser/suggest-const-for-global-var.stderr
Normal file
8
src/test/ui/parser/suggest-const-for-global-var.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: expected item, found keyword `let`
|
||||
--> $DIR/suggest-const-for-global-var.rs:1:1
|
||||
|
|
||||
LL | let X: i32 = 12;
|
||||
| ^^^ consider using `const` or `static` instead of `let` for global variables
|
||||
|
||||
error: aborting due to previous error
|
||||
|
10
src/test/ui/traits/alias/generic-default-in-dyn.rs
Normal file
10
src/test/ui/traits/alias/generic-default-in-dyn.rs
Normal file
@ -0,0 +1,10 @@
|
||||
trait SendEqAlias<T> = PartialEq;
|
||||
//~^ ERROR trait aliases are experimental
|
||||
|
||||
struct Foo<T>(dyn SendEqAlias<T>);
|
||||
//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393]
|
||||
|
||||
struct Bar<T>(dyn SendEqAlias<T>, T);
|
||||
//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393]
|
||||
|
||||
fn main() {}
|
39
src/test/ui/traits/alias/generic-default-in-dyn.stderr
Normal file
39
src/test/ui/traits/alias/generic-default-in-dyn.stderr
Normal file
@ -0,0 +1,39 @@
|
||||
error[E0658]: trait aliases are experimental
|
||||
--> $DIR/generic-default-in-dyn.rs:1:1
|
||||
|
|
||||
LL | trait SendEqAlias<T> = PartialEq;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
|
||||
= help: add `#![feature(trait_alias)]` to the crate attributes to enable
|
||||
|
||||
error[E0393]: the type parameter `Rhs` must be explicitly specified
|
||||
--> $DIR/generic-default-in-dyn.rs:4:19
|
||||
|
|
||||
LL | struct Foo<T>(dyn SendEqAlias<T>);
|
||||
| ^^^^^^^^^^^^^^ missing reference to `Rhs`
|
||||
|
|
||||
::: $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
|
|
||||
LL | pub trait PartialEq<Rhs: ?Sized = Self> {
|
||||
| --------------------------------------- type parameter `Rhs` must be specified for this
|
||||
|
|
||||
= note: because of the default `Self` reference, type parameters must be specified on object types
|
||||
|
||||
error[E0393]: the type parameter `Rhs` must be explicitly specified
|
||||
--> $DIR/generic-default-in-dyn.rs:7:19
|
||||
|
|
||||
LL | struct Bar<T>(dyn SendEqAlias<T>, T);
|
||||
| ^^^^^^^^^^^^^^ missing reference to `Rhs`
|
||||
|
|
||||
::: $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
|
|
||||
LL | pub trait PartialEq<Rhs: ?Sized = Self> {
|
||||
| --------------------------------------- type parameter `Rhs` must be specified for this
|
||||
|
|
||||
= note: because of the default `Self` reference, type parameters must be specified on object types
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0393, E0658.
|
||||
For more information about an error, try `rustc --explain E0393`.
|
8
src/test/ui/traits/alias/self-in-generics.rs
Normal file
8
src/test/ui/traits/alias/self-in-generics.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#![feature(trait_alias)]
|
||||
|
||||
pub trait SelfInput = Fn(&mut Self);
|
||||
|
||||
pub fn f(_f: &dyn SelfInput) {}
|
||||
//~^ ERROR the trait alias `SelfInput` cannot be made into an object [E0038]
|
||||
|
||||
fn main() {}
|
11
src/test/ui/traits/alias/self-in-generics.stderr
Normal file
11
src/test/ui/traits/alias/self-in-generics.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0038]: the trait alias `SelfInput` cannot be made into an object
|
||||
--> $DIR/self-in-generics.rs:5:19
|
||||
|
|
||||
LL | pub fn f(_f: &dyn SelfInput) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0038`.
|
Loading…
Reference in New Issue
Block a user