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:
bors 2022-08-12 16:32:24 +00:00
commit f22819bcce
50 changed files with 583 additions and 257 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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) {}
/// }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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">&quot;lib&quot;</span>]</span>
<pre><code><span class="attribute">#![<span class="ident">crate_type</span> = <span class="string">&quot;lib&quot;</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">&quot;linux&quot;</span>)]</span>
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">target_os</span> = <span class="string">&quot;linux&quot;</span>)]</span>
<span class="kw">fn</span> <span class="ident">main</span>() -&gt; () {
<span class="kw">let</span> <span class="ident">foo</span> <span class="op">=</span> <span class="bool-val">true</span> <span class="op">&amp;&amp;</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">&amp;</span><span class="ident">foo</span>;
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="op">&amp;&amp;</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> &amp;&amp; <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">&amp;</span><span class="ident">foo</span>;
<span class="kw">let</span> <span class="kw">_</span> = &amp;&amp;<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">&amp;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">&lt;</span> <span class="ident">N</span> <span class="op">&amp;&amp;</span> <span class="ident">index</span> <span class="op">&lt;</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> &lt; <span class="ident">N</span> &amp;&amp; <span class="ident">index</span> &lt;= <span class="self">self</span>.<span class="ident">length</span>);
<span class="ident">::std::env::var</span>(<span class="string">&quot;gateau&quot;</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">&amp;</span><span class="ident">s</span> {
<span class="kw-2">ref</span> <span class="kw-2">mut</span> <span class="ident">x</span> =&gt; {}

View file

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

View file

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

View file

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

View 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

View 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

View file

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

View file

@ -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 - '{ () =&gt; { ... }; ($('
// @has - '//span[@class="macro-nonterminal"]' '$'
// @has - '//span[@class="macro-nonterminal"]' 'arg'
// @has - ':'
// @has - '//span[@class="ident"]' 'tt'
// @has - '),'
// @has - '//span[@class="op"]' '+'
// @has - ')+'
// @has - ') =&gt; { ... }; }'
pub use std::todo;

View file

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

View 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() {}

View file

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

View file

@ -3,7 +3,6 @@
trait Foo<X = Box<dyn Foo>> {
//~^ ERROR cycle detected
//~| ERROR cycle detected
}
fn main() { }

View file

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

View file

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

View 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() {}

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

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

View 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

View file

@ -0,0 +1,6 @@
let X: i32 = 12;
//~^ ERROR expected item, found keyword `let`
fn main() {
println!("{}", X);
}

View 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

View 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() {}

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

View 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() {}

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