Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2025-02-17 05:16:18 +00:00
commit 9743852f3b
63 changed files with 1016 additions and 251 deletions

View file

@ -14,7 +14,10 @@ use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
use rustc_middle::bug;
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::{self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeVisitor};
use rustc_middle::ty::fold::fold_regions;
use rustc_middle::ty::{
self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor,
};
use rustc_span::{Ident, Span, kw};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::error_reporting::infer::nice_region_error::{
@ -183,6 +186,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}
/// Map the regions in the type to named regions, where possible.
fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
fold_regions(tcx, ty, |region, _| match *region {
ty::ReVar(vid) => self.to_error_region(vid).unwrap_or(region),
_ => region,
})
}
/// Returns `true` if a closure is inferred to be an `FnMut` closure.
fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
if let Some(ty::ReLateParam(late_param)) = self.to_error_region(fr).as_deref()
@ -314,7 +328,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let type_test_span = type_test.span;
if let Some(lower_bound_region) = lower_bound_region {
let generic_ty = self.regioncx.name_regions(
let generic_ty = self.name_regions(
self.infcx.tcx,
type_test.generic_kind.to_ty(self.infcx.tcx),
);
@ -323,7 +337,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.body.source.def_id().expect_local(),
type_test_span,
Some(origin),
self.regioncx.name_regions(self.infcx.tcx, type_test.generic_kind),
self.name_regions(self.infcx.tcx, type_test.generic_kind),
lower_bound_region,
));
} else {
@ -354,9 +368,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, key, member_region } => {
let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
let named_key = self.regioncx.name_regions(self.infcx.tcx, key);
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
let named_ty =
self.regioncx.name_regions_for_member_constraint(self.infcx.tcx, hidden_ty);
let named_key =
self.regioncx.name_regions_for_member_constraint(self.infcx.tcx, key);
let named_region = self
.regioncx
.name_regions_for_member_constraint(self.infcx.tcx, member_region);
let diag = unexpected_hidden_region_diagnostic(
self.infcx,
self.mir_def_id(),

View file

@ -204,7 +204,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// that the regions produced are in fact equal to the named region they are
/// replaced with. This is fine because this function is only to improve the
/// region names in error messages.
pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
///
/// This differs from `MirBorrowckCtxt::name_regions` since it is particularly
/// lax with mapping region vids that are *shorter* than a universal region to
/// that universal region. This is useful for member region constraints since
/// we want to suggest a universal region name to capture even if it's technically
/// not equal to the error region.
pub(crate) fn name_regions_for_member_constraint<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{

View file

@ -2806,31 +2806,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
});
let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
info.bad_modifiers = true;
// If the user-provided binding modifier doesn't match the default binding mode, we'll
// need to suggest reference patterns, which can affect other bindings.
// For simplicity, we opt to suggest making the pattern fully explicit.
info.suggest_eliding_modes &=
user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
"binding modifier"
} else {
info.bad_ref_pats = true;
// For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll
// suggest adding them instead, which can affect the types assigned to bindings.
// As such, we opt to suggest making the pattern fully explicit.
info.suggest_eliding_modes = false;
"reference pattern"
};
// Only provide a detailed label if the problematic subpattern isn't from an expansion.
// In the case that it's from a macro, we'll add a more detailed note in the emitter.
let from_expansion = subpat.span.from_expansion();
let primary_label = if from_expansion {
// We can't suggest eliding modifiers within expansions.
info.suggest_eliding_modes = false;
// NB: This wording assumes the only expansions that can produce problematic reference
// patterns and bindings are macros. If a desugaring or AST pass is added that can do
// so, we may want to inspect the span's source callee or macro backtrace.
"occurs within macro expansion".to_owned()
} else {
let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
info.bad_modifiers |= true;
// If the user-provided binding modifier doesn't match the default binding mode, we'll
// need to suggest reference patterns, which can affect other bindings.
// For simplicity, we opt to suggest making the pattern fully explicit.
info.suggest_eliding_modes &=
user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
"binding modifier"
} else {
info.bad_ref_pats |= true;
// For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll
// suggest adding them instead, which can affect the types assigned to bindings.
// As such, we opt to suggest making the pattern fully explicit.
info.suggest_eliding_modes = false;
"reference pattern"
};
let dbm_str = match def_br_mutbl {
Mutability::Not => "ref",
Mutability::Mut => "ref mut",

View file

@ -86,6 +86,14 @@ impl<'tcx> PlaceTy<'tcx> {
}
}
pub fn multi_projection_ty(
self,
tcx: TyCtxt<'tcx>,
elems: &[PlaceElem<'tcx>],
) -> PlaceTy<'tcx> {
elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem))
}
/// Convenience wrapper around `projection_ty_core` for
/// `PlaceElem`, where we can just use the `Ty` that is already
/// stored inline on field projection elems.
@ -167,11 +175,7 @@ impl<'tcx> Place<'tcx> {
where
D: HasLocalDecls<'tcx>,
{
projection
.iter()
.fold(PlaceTy::from_ty(local_decls.local_decls()[local].ty), |place_ty, &elem| {
place_ty.projection_ty(tcx, elem)
})
PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection)
}
pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>

View file

@ -89,6 +89,7 @@ pub(crate) trait DropElaborator<'a, 'tcx>: fmt::Debug {
// Accessors
fn patch_ref(&self) -> &MirPatch<'tcx>;
fn patch(&mut self) -> &mut MirPatch<'tcx>;
fn body(&self) -> &'a Body<'tcx>;
fn tcx(&self) -> TyCtxt<'tcx>;
@ -180,7 +181,14 @@ where
{
#[instrument(level = "trace", skip(self), ret)]
fn place_ty(&self, place: Place<'tcx>) -> Ty<'tcx> {
place.ty(self.elaborator.body(), self.tcx()).ty
if place.local < self.elaborator.body().local_decls.next_index() {
place.ty(self.elaborator.body(), self.tcx()).ty
} else {
// We don't have a slice with all the locals, since some are in the patch.
tcx::PlaceTy::from_ty(self.elaborator.patch_ref().local_ty(place.local))
.multi_projection_ty(self.elaborator.tcx(), place.projection)
.ty
}
}
fn tcx(&self) -> TyCtxt<'tcx> {
@ -410,12 +418,26 @@ where
let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::ZERO, unique_ty);
let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::ZERO, nonnull_ty);
let ptr_place = self.tcx().mk_place_field(nonnull_place, FieldIdx::ZERO, ptr_ty);
let interior = self.tcx().mk_place_deref(ptr_place);
let ptr_local = self.new_temp(ptr_ty);
let interior = self.tcx().mk_place_deref(Place::from(ptr_local));
let interior_path = self.elaborator.deref_subpath(self.path);
self.drop_subpath(interior, interior_path, succ, unwind)
let do_drop_bb = self.drop_subpath(interior, interior_path, succ, unwind);
let setup_bbd = BasicBlockData {
statements: vec![self.assign(
Place::from(ptr_local),
Rvalue::Cast(CastKind::Transmute, Operand::Copy(nonnull_place), ptr_ty),
)],
terminator: Some(Terminator {
kind: TerminatorKind::Goto { target: do_drop_bb },
source_info: self.source_info,
}),
is_cleanup: unwind.is_cleanup(),
};
self.elaborator.patch().new_block(setup_bbd)
}
#[instrument(level = "debug", ret)]

View file

@ -138,6 +138,10 @@ impl InitializationData<'_, '_> {
impl<'a, 'tcx> DropElaborator<'a, 'tcx> for ElaborateDropsCtxt<'a, 'tcx> {
type Path = MovePathIndex;
fn patch_ref(&self) -> &MirPatch<'tcx> {
&self.patch
}
fn patch(&mut self) -> &mut MirPatch<'tcx> {
&mut self.patch
}

View file

@ -166,6 +166,14 @@ impl<'tcx> MirPatch<'tcx> {
Local::new(index)
}
/// Returns the type of a local that's newly-added in the patch.
pub(crate) fn local_ty(&self, local: Local) -> Ty<'tcx> {
let local = local.as_usize();
assert!(local < self.next_local);
let new_local_idx = self.new_locals.len() - (self.next_local - local);
self.new_locals[new_local_idx].ty
}
pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
let block = BasicBlock::new(self.patch_map.len());
debug!("MirPatch: new_block: {:?}: {:?}", block, data);

View file

@ -350,6 +350,9 @@ impl fmt::Debug for DropShimElaborator<'_, '_> {
impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
type Path = ();
fn patch_ref(&self) -> &MirPatch<'tcx> {
&self.patch
}
fn patch(&mut self) -> &mut MirPatch<'tcx> {
&mut self.patch
}

View file

@ -7,7 +7,7 @@ use pulldown_cmark::{
use rustc_ast as ast;
use rustc_ast::attr::AttributeExt;
use rustc_ast::util::comments::beautify_doc_string;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::DefId;
use rustc_span::{DUMMY_SP, InnerSpan, Span, Symbol, kw, sym};
@ -422,9 +422,11 @@ fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
);
let mut links = Vec::new();
let mut refids = FxHashSet::default();
while let Some(event) = event_iter.next() {
match event {
Event::Start(Tag::Link { link_type, dest_url, title: _, id: _ })
Event::Start(Tag::Link { link_type, dest_url, title: _, id })
if may_be_doc_link(link_type) =>
{
if matches!(
@ -439,6 +441,12 @@ fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
links.push(display_text);
}
}
if matches!(
link_type,
LinkType::Reference | LinkType::Shortcut | LinkType::Collapsed
) {
refids.insert(id);
}
links.push(preprocess_link(&dest_url));
}
@ -446,6 +454,12 @@ fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
}
}
for (label, refdef) in event_iter.reference_definitions().iter() {
if !refids.contains(label) {
links.push(preprocess_link(&refdef.dest));
}
}
links
}

View file

@ -29,7 +29,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_lint_defs::BuiltinLintDiag;
use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS;
use rustc_span::{Symbol, sym};
use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, TARGETS, Target, TargetTuple};
use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, Target};
use crate::Session;
use crate::config::{CrateType, FmtDebug};
@ -432,11 +432,7 @@ impl CheckCfg {
panic!("unable to get all the check-cfg values buckets");
};
for target in TARGETS
.iter()
.map(|target| Target::expect_builtin(&TargetTuple::from_tuple(target)))
.chain(iter::once(current_target.clone()))
{
for target in Target::builtins().chain(iter::once(current_target.clone())) {
values_target_abi.insert(Symbol::intern(&target.options.abi));
values_target_arch.insert(Symbol::intern(&target.arch));
values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));

View file

@ -1658,6 +1658,14 @@ macro_rules! supported_targets {
Some(t)
}
fn load_all_builtins() -> impl Iterator<Item = Target> {
[
$( targets::$module::target, )+
]
.into_iter()
.map(|f| f())
}
#[cfg(test)]
mod tests {
// Cannot put this into a separate file without duplication, make an exception.
@ -3360,6 +3368,11 @@ impl Target {
}
}
/// Load all built-in targets
pub fn builtins() -> impl Iterator<Item = Target> {
load_all_builtins()
}
/// Search for a JSON file specifying the given target tuple.
///
/// If none is found in `$RUST_TARGET_PATH`, look for a file called `target.json` inside the

View file

@ -1053,7 +1053,6 @@ impl<T: ?Sized> Box<T> {
/// ```
///
/// [memory layout]: self#memory-layout
/// [`Layout`]: crate::Layout
#[stable(feature = "box_raw", since = "1.4.0")]
#[inline]
#[must_use = "call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`"]
@ -1108,7 +1107,6 @@ impl<T: ?Sized> Box<T> {
/// ```
///
/// [memory layout]: self#memory-layout
/// [`Layout`]: crate::Layout
#[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
#[inline]
#[must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`"]
@ -1165,7 +1163,6 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
/// ```
///
/// [memory layout]: self#memory-layout
/// [`Layout`]: crate::Layout
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
@ -1219,7 +1216,6 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
/// ```
///
/// [memory layout]: self#memory-layout
/// [`Layout`]: crate::Layout
#[unstable(feature = "allocator_api", issue = "32838")]
// #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]

View file

@ -70,7 +70,7 @@ use crate::{cmp, ptr};
/// {
/// return null_mut();
/// };
/// self.arena.get().cast::<u8>().add(allocated)
/// unsafe { self.arena.get().cast::<u8>().add(allocated) }
/// }
/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
/// }

View file

@ -22,6 +22,30 @@ use crate::fmt::{self, Debug, Display, Formatter};
/// accessing that error via [`Error::source()`]. This makes it possible for the
/// high-level module to provide its own errors while also revealing some of the
/// implementation for debugging.
///
/// # Example
///
/// Implementing the `Error` trait only requires that `Debug` and `Display` are implemented too.
///
/// ```
/// use std::error::Error;
/// use std::fmt;
/// use std::path::PathBuf;
///
/// #[derive(Debug)]
/// struct ReadConfigError {
/// path: PathBuf
/// }
///
/// impl fmt::Display for ReadConfigError {
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// let path = self.path.display();
/// write!(f, "unable to read configuration at {path}")
/// }
/// }
///
/// impl Error for ReadConfigError {}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
#[rustc_has_incoherent_inherent_impls]

View file

@ -52,7 +52,7 @@ use crate::{intrinsics, ub_checks};
/// // Safety: `divisor` can't be zero because of `prepare_inputs`,
/// // but the compiler does not know about this. We *promise*
/// // that we always call `prepare_inputs`.
/// std::hint::unreachable_unchecked()
/// unsafe { std::hint::unreachable_unchecked() }
/// }
/// // The compiler would normally introduce a check here that prevents
/// // a division by zero. However, if `divisor` was zero, the branch

View file

@ -1703,12 +1703,12 @@ pub const fn forget<T: ?Sized>(_: T) {
/// ```
/// struct R<'a>(&'a i32);
/// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {
/// std::mem::transmute::<R<'b>, R<'static>>(r)
/// unsafe { std::mem::transmute::<R<'b>, R<'static>>(r) }
/// }
///
/// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>)
/// -> &'b mut R<'c> {
/// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r)
/// unsafe { std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) }
/// }
/// ```
///
@ -4498,11 +4498,11 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
///
/// // SAFETY: Our precondition ensures the source is aligned and valid,
/// // and `Vec::with_capacity` ensures that we have usable space to write them.
/// ptr::copy(ptr, dst.as_mut_ptr(), elts);
/// unsafe { ptr::copy(ptr, dst.as_mut_ptr(), elts); }
///
/// // SAFETY: We created it with this much capacity earlier,
/// // and the previous `copy` has initialized these elements.
/// dst.set_len(elts);
/// unsafe { dst.set_len(elts); }
/// dst
/// }
/// ```

View file

@ -98,7 +98,7 @@ use crate::{fmt, intrinsics, ptr, slice};
///
/// unsafe fn make_vec(out: *mut Vec<i32>) {
/// // `write` does not drop the old contents, which is important.
/// out.write(vec![1, 2, 3]);
/// unsafe { out.write(vec![1, 2, 3]); }
/// }
///
/// let mut v = MaybeUninit::uninit();
@ -844,7 +844,7 @@ impl<T> MaybeUninit<T> {
/// # #![allow(unexpected_cfgs)]
/// use std::mem::MaybeUninit;
///
/// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 1024]) { *buf = [0; 1024] }
/// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 1024]) { unsafe { *buf = [0; 1024] } }
/// # #[cfg(FALSE)]
/// extern "C" {
/// /// Initializes *all* the bytes of the input buffer.

View file

@ -32,7 +32,7 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy};
/// src: ManuallyDrop::new(src),
/// };
///
/// let dst = transmute.dst;
/// let dst = unsafe { transmute.dst };
///
/// ManuallyDrop::into_inner(dst)
/// }

View file

@ -724,13 +724,13 @@ impl<T: ?Sized> *const T {
/// that their safety preconditions are met:
/// ```rust
/// # #![feature(ptr_sub_ptr)]
/// # unsafe fn blah(ptr: *const i32, origin: *const i32, count: usize) -> bool {
/// # unsafe fn blah(ptr: *const i32, origin: *const i32, count: usize) -> bool { unsafe {
/// ptr.sub_ptr(origin) == count
/// # &&
/// origin.add(count) == ptr
/// # &&
/// ptr.sub(count) == origin
/// # }
/// # } }
/// ```
///
/// # Safety

View file

@ -896,13 +896,13 @@ impl<T: ?Sized> *mut T {
/// that their safety preconditions are met:
/// ```rust
/// # #![feature(ptr_sub_ptr)]
/// # unsafe fn blah(ptr: *mut i32, origin: *mut i32, count: usize) -> bool {
/// # unsafe fn blah(ptr: *mut i32, origin: *mut i32, count: usize) -> bool { unsafe {
/// ptr.sub_ptr(origin) == count
/// # &&
/// origin.add(count) == ptr
/// # &&
/// ptr.sub(count) == origin
/// # }
/// # } }
/// ```
///
/// # Safety

View file

@ -857,13 +857,13 @@ impl<T: ?Sized> NonNull<T> {
/// that their safety preconditions are met:
/// ```rust
/// # #![feature(ptr_sub_ptr)]
/// # unsafe fn blah(ptr: std::ptr::NonNull<u32>, origin: std::ptr::NonNull<u32>, count: usize) -> bool {
/// # unsafe fn blah(ptr: std::ptr::NonNull<u32>, origin: std::ptr::NonNull<u32>, count: usize) -> bool { unsafe {
/// ptr.sub_ptr(origin) == count
/// # &&
/// origin.add(count) == ptr
/// # &&
/// ptr.sub(count) == origin
/// # }
/// # } }
/// ```
///
/// # Safety

View file

@ -40,17 +40,14 @@ impl RawWaker {
/// of the `vtable` as the first parameter.
///
/// It is important to consider that the `data` pointer must point to a
/// thread safe type such as an `[Arc]<T: Send + Sync>`
/// thread safe type such as an `Arc<T: Send + Sync>`
/// when used to construct a [`Waker`]. This restriction is lifted when
/// constructing a [`LocalWaker`], which allows using types that do not implement
/// <code>[Send] + [Sync]</code> like `[Rc]<T>`.
/// <code>[Send] + [Sync]</code> like `Rc<T>`.
///
/// The `vtable` customizes the behavior of a `Waker` which gets created
/// from a `RawWaker`. For each operation on the `Waker`, the associated
/// function in the `vtable` of the underlying `RawWaker` will be called.
///
/// [`Arc`]: std::sync::Arc
/// [`Rc`]: std::rc::Rc
#[inline]
#[rustc_promotable]
#[stable(feature = "futures_api", since = "1.36.0")]

View file

@ -16,9 +16,10 @@ type SetAbortMessageType = unsafe extern "C" fn(*const libc::c_char) -> ();
// Weakly resolve the symbol for android_set_abort_message. This function is only available
// for API >= 21.
pub(crate) unsafe fn android_set_abort_message(payload: &mut dyn PanicPayload) {
let func_addr =
let func_addr = unsafe {
libc::dlsym(libc::RTLD_DEFAULT, ANDROID_SET_ABORT_MESSAGE.as_ptr() as *const libc::c_char)
as usize;
as usize
};
if func_addr == 0 {
return;
}
@ -37,13 +38,14 @@ pub(crate) unsafe fn android_set_abort_message(payload: &mut dyn PanicPayload) {
// Allocate a new buffer to append the null byte.
let size = msg.len() + 1usize;
let buf = libc::malloc(size) as *mut libc::c_char;
let buf = unsafe { libc::malloc(size) as *mut libc::c_char };
if buf.is_null() {
return; // allocation failure
}
copy_nonoverlapping(msg.as_ptr(), buf as *mut u8, msg.len());
buf.add(msg.len()).write(0);
let func = transmute::<usize, SetAbortMessageType>(func_addr);
func(buf);
unsafe {
copy_nonoverlapping(msg.as_ptr(), buf as *mut u8, msg.len());
buf.add(msg.len()).write(0);
let func = transmute::<usize, SetAbortMessageType>(func_addr);
func(buf);
}
}

View file

@ -15,6 +15,7 @@
#![feature(staged_api)]
#![feature(rustc_attrs)]
#![allow(internal_features)]
#![deny(unsafe_op_in_unsafe_fn)]
#[cfg(target_os = "android")]
mod android;
@ -36,16 +37,22 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen
pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
// Android has the ability to attach a message as part of the abort.
#[cfg(target_os = "android")]
android::android_set_abort_message(_payload);
unsafe {
android::android_set_abort_message(_payload);
}
#[cfg(target_os = "zkvm")]
zkvm::zkvm_set_abort_message(_payload);
unsafe {
zkvm::zkvm_set_abort_message(_payload);
}
abort();
unsafe {
abort();
}
cfg_if::cfg_if! {
if #[cfg(any(unix, target_os = "solid_asp3"))] {
unsafe fn abort() -> ! {
libc::abort();
unsafe { libc::abort(); }
}
} else if #[cfg(any(target_os = "hermit",
all(target_vendor = "fortanix", target_env = "sgx"),
@ -57,7 +64,7 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
unsafe extern "C" {
pub fn __rust_abort() -> !;
}
__rust_abort();
unsafe { __rust_abort(); }
}
} else if #[cfg(all(windows, not(miri)))] {
// On Windows, use the processor-specific __fastfail mechanism. In Windows 8
@ -75,11 +82,17 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
core::arch::asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
unsafe {
core::arch::asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
}
} else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
core::arch::asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
unsafe {
core::arch::asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
}
} else if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] {
core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
unsafe {
core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
}
} else {
core::intrinsics::abort();
}
@ -93,7 +106,7 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
}
unsafe fn abort() -> ! {
teeos::TEE_Panic(1);
unsafe { teeos::TEE_Panic(1); }
}
} else {
unsafe fn abort() -> ! {

View file

@ -20,5 +20,7 @@ pub(crate) unsafe fn zkvm_set_abort_message(payload: &mut dyn PanicPayload) {
fn sys_panic(msg_ptr: *const u8, len: usize) -> !;
}
sys_panic(msg.as_ptr(), msg.len());
unsafe {
sys_panic(msg.as_ptr(), msg.len());
}
}

View file

@ -71,42 +71,46 @@ pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
ptr: *mut u8,
is_rust_panic: bool,
}
let catch_data = &*(ptr as *mut CatchData);
unsafe {
let catch_data = &*(ptr as *mut CatchData);
let adjusted_ptr = __cxa_begin_catch(catch_data.ptr as *mut libc::c_void) as *mut Exception;
if !catch_data.is_rust_panic {
super::__rust_foreign_exception();
}
let adjusted_ptr = __cxa_begin_catch(catch_data.ptr as *mut libc::c_void) as *mut Exception;
if !catch_data.is_rust_panic {
super::__rust_foreign_exception();
}
let canary = (&raw const (*adjusted_ptr).canary).read();
if !ptr::eq(canary, &EXCEPTION_TYPE_INFO) {
super::__rust_foreign_exception();
}
let canary = (&raw const (*adjusted_ptr).canary).read();
if !ptr::eq(canary, &EXCEPTION_TYPE_INFO) {
super::__rust_foreign_exception();
}
let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::Relaxed);
if was_caught {
// Since cleanup() isn't allowed to panic, we just abort instead.
intrinsics::abort();
let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::Relaxed);
if was_caught {
// Since cleanup() isn't allowed to panic, we just abort instead.
intrinsics::abort();
}
let out = (*adjusted_ptr).data.take().unwrap();
__cxa_end_catch();
out
}
let out = (*adjusted_ptr).data.take().unwrap();
__cxa_end_catch();
out
}
pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
let exception = __cxa_allocate_exception(mem::size_of::<Exception>()) as *mut Exception;
if exception.is_null() {
return uw::_URC_FATAL_PHASE1_ERROR as u32;
unsafe {
let exception = __cxa_allocate_exception(mem::size_of::<Exception>()) as *mut Exception;
if exception.is_null() {
return uw::_URC_FATAL_PHASE1_ERROR as u32;
}
ptr::write(
exception,
Exception {
canary: &EXCEPTION_TYPE_INFO,
caught: AtomicBool::new(false),
data: Some(data),
},
);
__cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup);
}
ptr::write(
exception,
Exception {
canary: &EXCEPTION_TYPE_INFO,
caught: AtomicBool::new(false),
data: Some(data),
},
);
__cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup);
}
extern "C" fn exception_cleanup(ptr: *mut libc::c_void) -> *mut libc::c_void {

View file

@ -69,7 +69,7 @@ pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
cause: data,
});
let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
return uw::_Unwind_RaiseException(exception_param) as u32;
return unsafe { uw::_Unwind_RaiseException(exception_param) as u32 };
extern "C" fn exception_cleanup(
_unwind_code: uw::_Unwind_Reason_Code,
@ -83,26 +83,28 @@ pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
}
pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
let exception = ptr as *mut uw::_Unwind_Exception;
if (*exception).exception_class != RUST_EXCEPTION_CLASS {
uw::_Unwind_DeleteException(exception);
super::__rust_foreign_exception();
}
unsafe {
let exception = ptr as *mut uw::_Unwind_Exception;
if (*exception).exception_class != RUST_EXCEPTION_CLASS {
uw::_Unwind_DeleteException(exception);
super::__rust_foreign_exception();
}
let exception = exception.cast::<Exception>();
// Just access the canary field, avoid accessing the entire `Exception` as
// it can be a foreign Rust exception.
let canary = (&raw const (*exception).canary).read();
if !ptr::eq(canary, &CANARY) {
// A foreign Rust exception, treat it slightly differently from other
// foreign exceptions, because call into `_Unwind_DeleteException` will
// call into `__rust_drop_panic` which produces a confusing
// "Rust panic must be rethrown" message.
super::__rust_foreign_exception();
}
let exception = exception.cast::<Exception>();
// Just access the canary field, avoid accessing the entire `Exception` as
// it can be a foreign Rust exception.
let canary = (&raw const (*exception).canary).read();
if !ptr::eq(canary, &CANARY) {
// A foreign Rust exception, treat it slightly differently from other
// foreign exceptions, because call into `_Unwind_DeleteException` will
// call into `__rust_drop_panic` which produces a confusing
// "Rust panic must be rethrown" message.
super::__rust_foreign_exception();
}
let exception = Box::from_raw(exception as *mut Exception);
exception.cause
let exception = Box::from_raw(exception as *mut Exception);
exception.cause
}
}
// Rust's exception class identifier. This is used by personality routines to

View file

@ -9,12 +9,16 @@ pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
unsafe extern "C" {
fn __rust_abort() -> !;
}
__rust_abort();
unsafe {
__rust_abort();
}
}
pub(crate) unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
unsafe extern "C" {
fn __rust_abort() -> !;
}
__rust_abort();
unsafe {
__rust_abort();
}
}

View file

@ -27,6 +27,7 @@
#![allow(internal_features)]
#![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))]
#![warn(unreachable_pub)]
#![deny(unsafe_op_in_unsafe_fn)]
use alloc::boxed::Box;
use core::any::Any;
@ -87,14 +88,16 @@ unsafe extern "C" {
#[rustc_std_internal_symbol]
#[allow(improper_ctypes_definitions)]
pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
Box::into_raw(imp::cleanup(payload))
unsafe { Box::into_raw(imp::cleanup(payload)) }
}
// Entry point for raising an exception, just delegates to the platform-specific
// implementation.
#[rustc_std_internal_symbol]
pub unsafe fn __rust_start_panic(payload: &mut dyn PanicPayload) -> u32 {
let payload = Box::from_raw(payload.take_box());
unsafe {
let payload = Box::from_raw(payload.take_box());
imp::panic(payload)
imp::panic(payload)
}
}

View file

@ -16,11 +16,11 @@ pub(crate) unsafe fn panic(payload: Box<dyn Any + Send>) -> u32 {
// The payload we pass to `miri_start_unwind` will be exactly the argument we get
// in `cleanup` below. So we just box it up once, to get something pointer-sized.
let payload_box: Payload = Box::new(payload);
miri_start_unwind(Box::into_raw(payload_box) as *mut u8)
unsafe { miri_start_unwind(Box::into_raw(payload_box) as *mut u8) }
}
pub(crate) unsafe fn cleanup(payload_box: *mut u8) -> Box<dyn Any + Send> {
// Recover the underlying `Box`.
let payload_box: Payload = Box::from_raw(payload_box as *mut _);
let payload_box: Payload = unsafe { Box::from_raw(payload_box as *mut _) };
*payload_box
}

View file

@ -268,9 +268,11 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
macro_rules! define_cleanup {
($abi:tt $abi2:tt) => {
unsafe extern $abi fn exception_cleanup(e: *mut Exception) {
if let Exception { data: Some(b), .. } = e.read() {
drop(b);
super::__rust_drop_panic();
unsafe {
if let Exception { data: Some(b), .. } = e.read() {
drop(b);
super::__rust_drop_panic();
}
}
}
unsafe extern $abi2 fn exception_copy(
@ -322,45 +324,51 @@ pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
//
// In any case, we basically need to do something like this until we can
// express more operations in statics (and we may never be able to).
atomic_store_seqcst(
(&raw mut THROW_INFO.pmfnUnwind).cast(),
ptr_t::new(exception_cleanup as *mut u8).raw(),
);
atomic_store_seqcst(
(&raw mut THROW_INFO.pCatchableTypeArray).cast(),
ptr_t::new((&raw mut CATCHABLE_TYPE_ARRAY).cast()).raw(),
);
atomic_store_seqcst(
(&raw mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(),
ptr_t::new((&raw mut CATCHABLE_TYPE).cast()).raw(),
);
atomic_store_seqcst(
(&raw mut CATCHABLE_TYPE.pType).cast(),
ptr_t::new((&raw mut TYPE_DESCRIPTOR).cast()).raw(),
);
atomic_store_seqcst(
(&raw mut CATCHABLE_TYPE.copyFunction).cast(),
ptr_t::new(exception_copy as *mut u8).raw(),
);
unsafe {
atomic_store_seqcst(
(&raw mut THROW_INFO.pmfnUnwind).cast(),
ptr_t::new(exception_cleanup as *mut u8).raw(),
);
atomic_store_seqcst(
(&raw mut THROW_INFO.pCatchableTypeArray).cast(),
ptr_t::new((&raw mut CATCHABLE_TYPE_ARRAY).cast()).raw(),
);
atomic_store_seqcst(
(&raw mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(),
ptr_t::new((&raw mut CATCHABLE_TYPE).cast()).raw(),
);
atomic_store_seqcst(
(&raw mut CATCHABLE_TYPE.pType).cast(),
ptr_t::new((&raw mut TYPE_DESCRIPTOR).cast()).raw(),
);
atomic_store_seqcst(
(&raw mut CATCHABLE_TYPE.copyFunction).cast(),
ptr_t::new(exception_copy as *mut u8).raw(),
);
}
unsafe extern "system-unwind" {
fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !;
}
_CxxThrowException(throw_ptr, (&raw mut THROW_INFO) as *mut _);
unsafe {
_CxxThrowException(throw_ptr, (&raw mut THROW_INFO) as *mut _);
}
}
pub(crate) unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
// A null payload here means that we got here from the catch (...) of
// __rust_try. This happens when a non-Rust foreign exception is caught.
if payload.is_null() {
super::__rust_foreign_exception();
unsafe {
// A null payload here means that we got here from the catch (...) of
// __rust_try. This happens when a non-Rust foreign exception is caught.
if payload.is_null() {
super::__rust_foreign_exception();
}
let exception = payload as *mut Exception;
let canary = (&raw const (*exception).canary).read();
if !core::ptr::eq(canary, &raw const TYPE_DESCRIPTOR) {
// A foreign Rust exception.
super::__rust_foreign_exception();
}
(*exception).data.take().unwrap()
}
let exception = payload as *mut Exception;
let canary = (&raw const (*exception).canary).read();
if !core::ptr::eq(canary, &raw const TYPE_DESCRIPTOR) {
// A foreign Rust exception.
super::__rust_foreign_exception();
}
(*exception).data.take().unwrap()
}

View file

@ -19,7 +19,7 @@ struct Env;
impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> {
fn from(f: &'a mut F) -> Self {
unsafe extern "C" fn call<A, R, F: FnMut(A) -> R>(env: *mut Env, arg: A) -> R {
(*(env as *mut _ as *mut F))(arg)
unsafe { (*(env as *mut _ as *mut F))(arg) }
}
Closure { call: call::<A, R, F>, env: f as *mut _ as *mut Env, _marker: PhantomData }
}

View file

@ -33,6 +33,7 @@
#![deny(ffi_unwind_calls)]
#![warn(rustdoc::unescaped_backticks)]
#![warn(unreachable_pub)]
#![deny(unsafe_op_in_unsafe_fn)]
#[unstable(feature = "proc_macro_internals", issue = "27812")]
#[doc(hidden)]

View file

@ -20,11 +20,11 @@
//!
//! unsafe impl GlobalAlloc for MyAllocator {
//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
//! System.alloc(layout)
//! unsafe { System.alloc(layout) }
//! }
//!
//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
//! System.dealloc(ptr, layout)
//! unsafe { System.dealloc(ptr, layout) }
//! }
//! }
//!
@ -102,7 +102,7 @@ pub use alloc_crate::alloc::*;
///
/// unsafe impl GlobalAlloc for Counter {
/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
/// let ret = System.alloc(layout);
/// let ret = unsafe { System.alloc(layout) };
/// if !ret.is_null() {
/// ALLOCATED.fetch_add(layout.size(), Relaxed);
/// }
@ -110,7 +110,7 @@ pub use alloc_crate::alloc::*;
/// }
///
/// unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
/// System.dealloc(ptr, layout);
/// unsafe { System.dealloc(ptr, layout); }
/// ALLOCATED.fetch_sub(layout.size(), Relaxed);
/// }
/// }

View file

@ -56,7 +56,7 @@ impl Thread {
}
};
let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) };
// Note: if the thread creation fails and this assert fails, then p will
// be leaked. However, an alternative design could cause double-free
// which is clearly worse.

View file

@ -1,4 +1,4 @@
#![cfg_attr(test, allow(dead_code))]
pub unsafe fn reserve_stack() {}
pub unsafe fn init() {}
pub fn reserve_stack() {}
pub fn init() {}

View file

@ -9,6 +9,7 @@
)]
#![allow(internal_features)]
#![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))]
#![deny(unsafe_op_in_unsafe_fn)]
// Force libc to be included even if unused. This is required by many platforms.
#[cfg(not(all(windows, target_env = "msvc")))]

View file

@ -218,36 +218,38 @@ if #[cfg(any(target_vendor = "apple", target_os = "netbsd", not(target_arch = "a
pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
let mut val: _Unwind_Word = core::ptr::null();
_Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
(&raw mut val) as *mut c_void);
unsafe { _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
(&raw mut val) as *mut c_void); }
val
}
pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
let mut value = value;
_Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
(&raw mut value) as *mut c_void);
unsafe { _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
(&raw mut value) as *mut c_void); }
}
pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
-> _Unwind_Word {
let val = _Unwind_GetGR(ctx, UNWIND_IP_REG);
let val = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG) };
val.map_addr(|v| v & !1)
}
pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context,
value: _Unwind_Word) {
// Propagate thumb bit to instruction pointer
let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG).addr() & 1;
let thumb_state = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG).addr() & 1 };
let value = value.map_addr(|v| v | thumb_state);
_Unwind_SetGR(ctx, UNWIND_IP_REG, value);
unsafe { _Unwind_SetGR(ctx, UNWIND_IP_REG, value); }
}
pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
ip_before_insn: *mut c_int)
-> _Unwind_Word {
*ip_before_insn = 0;
_Unwind_GetIP(ctx)
unsafe {
*ip_before_insn = 0;
_Unwind_GetIP(ctx)
}
}
// This function also doesn't exist on Android or ARM/Linux, so make it a no-op

View file

@ -95,7 +95,7 @@ impl Step for Std {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.crate_or_deps("sysroot").path("library").alias("core")
run.crate_or_deps("sysroot").path("library")
}
fn make_run(run: RunConfig<'_>) {

View file

@ -572,10 +572,7 @@ impl Step for Std {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
run.crate_or_deps("sysroot")
.path("library")
.alias("core")
.default_condition(builder.config.docs)
run.crate_or_deps("sysroot").path("library").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig<'_>) {

View file

@ -127,10 +127,14 @@ impl RunConfig<'_> {
pub fn cargo_crates_in_set(&self) -> Vec<String> {
let mut crates = Vec::new();
for krate in &self.paths {
let path = krate.assert_single_path();
let Some(crate_name) = self.builder.crate_paths.get(&path.path) else {
panic!("missing crate for path {}", path.path.display())
};
let path = &krate.assert_single_path().path;
let crate_name = self
.builder
.crate_paths
.get(path)
.unwrap_or_else(|| panic!("missing crate for path {}", path.display()));
crates.push(crate_name.to_string());
}
crates

View file

@ -29,6 +29,7 @@ use crate::core::config::TargetSelection;
use crate::utils::exec::{BootstrapCommand, command};
use crate::{Build, CLang, GitRepo};
/// Finds archiver tool for the given target if possible.
/// FIXME(onur-ozkan): This logic should be replaced by calling into the `cc` crate.
fn cc2ar(cc: &Path, target: TargetSelection, default_ar: PathBuf) -> Option<PathBuf> {
if let Some(ar) = env::var_os(format!("AR_{}", target.triple.replace('-', "_"))) {
@ -58,6 +59,7 @@ fn cc2ar(cc: &Path, target: TargetSelection, default_ar: PathBuf) -> Option<Path
}
}
/// Creates and configures a new [`cc::Build`] instance for the given target.
fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build {
let mut cfg = cc::Build::new();
cfg.cargo_metadata(false)
@ -84,6 +86,12 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build {
cfg
}
/// Probes for C and C++ compilers and configures the corresponding entries in the [`Build`]
/// structure.
///
/// This function determines which targets need a C compiler (and, if needed, a C++ compiler)
/// by combining the primary build target, host targets, and any additional targets. For
/// each target, it calls [`find_target`] to configure the necessary compiler tools.
pub fn find(build: &Build) {
let targets: HashSet<_> = match build.config.cmd {
// We don't need to check cross targets for these commands.
@ -112,6 +120,11 @@ pub fn find(build: &Build) {
}
}
/// Probes and configures the C and C++ compilers for a single target.
///
/// This function uses both user-specified configuration (from `config.toml`) and auto-detection
/// logic to determine the correct C/C++ compilers for the target. It also determines the appropriate
/// archiver (`ar`) and sets up additional compilation flags (both handled and unhandled).
pub fn find_target(build: &Build, target: TargetSelection) {
let mut cfg = new_cc_build(build, target);
let config = build.config.target_config.get(&target);
@ -172,6 +185,8 @@ pub fn find_target(build: &Build, target: TargetSelection) {
}
}
/// Determines the default compiler for a given target and language when not explicitly
/// configured in `config.toml`.
fn default_compiler(
cfg: &mut cc::Build,
compiler: Language,
@ -248,6 +263,12 @@ fn default_compiler(
}
}
/// Constructs the path to the Android NDK compiler for the given target triple and language.
///
/// This helper function transform the target triple by converting certain architecture names
/// (for example, translating "arm" to "arm7a"), appends the minimum API level (hardcoded as "21"
/// for NDK r26d), and then constructs the full path based on the provided NDK directory and host
/// platform.
pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> PathBuf {
let mut triple_iter = triple.split('-');
let triple_translated = if let Some(arch) = triple_iter.next() {
@ -277,7 +298,11 @@ pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> Path
ndk.join("toolchains").join("llvm").join("prebuilt").join(host_tag).join("bin").join(compiler)
}
/// The target programming language for a native compiler.
/// Representing the target programming language for a native compiler.
///
/// This enum is used to indicate whether a particular compiler is intended for C or C++.
/// It also provides helper methods for obtaining the standard executable names for GCC and
/// clang-based compilers.
#[derive(PartialEq)]
pub(crate) enum Language {
/// The compiler is targeting C.
@ -287,7 +312,7 @@ pub(crate) enum Language {
}
impl Language {
/// Obtains the name of a compiler in the GCC collection.
/// Returns the executable name for a GCC compiler corresponding to this language.
fn gcc(self) -> &'static str {
match self {
Language::C => "gcc",
@ -295,7 +320,7 @@ impl Language {
}
}
/// Obtains the name of a compiler in the clang suite.
/// Returns the executable name for a clang-based compiler corresponding to this language.
fn clang(self) -> &'static str {
match self {
Language::C => "clang",
@ -303,3 +328,6 @@ impl Language {
}
}
}
#[cfg(test)]
mod tests;

View file

@ -0,0 +1,254 @@
use std::path::{Path, PathBuf};
use std::{env, iter};
use super::*;
use crate::core::config::{Target, TargetSelection};
use crate::{Build, Config, Flags};
#[test]
fn test_cc2ar_env_specific() {
let triple = "x86_64-unknown-linux-gnu";
let key = "AR_x86_64_unknown_linux_gnu";
env::set_var(key, "custom-ar");
let target = TargetSelection::from_user(triple);
let cc = Path::new("/usr/bin/clang");
let default_ar = PathBuf::from("default-ar");
let result = cc2ar(cc, target, default_ar);
env::remove_var(key);
assert_eq!(result, Some(PathBuf::from("custom-ar")));
}
#[test]
fn test_cc2ar_musl() {
let triple = "x86_64-unknown-linux-musl";
env::remove_var("AR_x86_64_unknown_linux_musl");
env::remove_var("AR");
let target = TargetSelection::from_user(triple);
let cc = Path::new("/usr/bin/clang");
let default_ar = PathBuf::from("default-ar");
let result = cc2ar(cc, target, default_ar);
assert_eq!(result, Some(PathBuf::from("ar")));
}
#[test]
fn test_cc2ar_openbsd() {
let triple = "x86_64-unknown-openbsd";
env::remove_var("AR_x86_64_unknown_openbsd");
env::remove_var("AR");
let target = TargetSelection::from_user(triple);
let cc = Path::new("/usr/bin/cc");
let default_ar = PathBuf::from("default-ar");
let result = cc2ar(cc, target, default_ar);
assert_eq!(result, Some(PathBuf::from("ar")));
}
#[test]
fn test_cc2ar_vxworks() {
let triple = "armv7-wrs-vxworks";
env::remove_var("AR_armv7_wrs_vxworks");
env::remove_var("AR");
let target = TargetSelection::from_user(triple);
let cc = Path::new("/usr/bin/clang");
let default_ar = PathBuf::from("default-ar");
let result = cc2ar(cc, target, default_ar);
assert_eq!(result, Some(PathBuf::from("wr-ar")));
}
#[test]
fn test_cc2ar_nto_i586() {
let triple = "i586-unknown-nto-something";
env::remove_var("AR_i586_unknown_nto_something");
env::remove_var("AR");
let target = TargetSelection::from_user(triple);
let cc = Path::new("/usr/bin/clang");
let default_ar = PathBuf::from("default-ar");
let result = cc2ar(cc, target, default_ar);
assert_eq!(result, Some(PathBuf::from("ntox86-ar")));
}
#[test]
fn test_cc2ar_nto_aarch64() {
let triple = "aarch64-unknown-nto-something";
env::remove_var("AR_aarch64_unknown_nto_something");
env::remove_var("AR");
let target = TargetSelection::from_user(triple);
let cc = Path::new("/usr/bin/clang");
let default_ar = PathBuf::from("default-ar");
let result = cc2ar(cc, target, default_ar);
assert_eq!(result, Some(PathBuf::from("ntoaarch64-ar")));
}
#[test]
fn test_cc2ar_nto_x86_64() {
let triple = "x86_64-unknown-nto-something";
env::remove_var("AR_x86_64_unknown_nto_something");
env::remove_var("AR");
let target = TargetSelection::from_user(triple);
let cc = Path::new("/usr/bin/clang");
let default_ar = PathBuf::from("default-ar");
let result = cc2ar(cc, target, default_ar);
assert_eq!(result, Some(PathBuf::from("ntox86_64-ar")));
}
#[test]
#[should_panic(expected = "Unknown architecture, cannot determine archiver for Neutrino QNX")]
fn test_cc2ar_nto_unknown() {
let triple = "powerpc-unknown-nto-something";
env::remove_var("AR_powerpc_unknown_nto_something");
env::remove_var("AR");
let target = TargetSelection::from_user(triple);
let cc = Path::new("/usr/bin/clang");
let default_ar = PathBuf::from("default-ar");
let _ = cc2ar(cc, target, default_ar);
}
#[test]
fn test_ndk_compiler_c() {
let ndk_path = PathBuf::from("/ndk");
let target_triple = "arm-unknown-linux-android";
let expected_triple_translated = "armv7a-unknown-linux-android";
let expected_compiler = format!("{}21-{}", expected_triple_translated, Language::C.clang());
let host_tag = if cfg!(target_os = "macos") {
"darwin-x86_64"
} else if cfg!(target_os = "windows") {
"windows-x86_64"
} else {
"linux-x86_64"
};
let expected_path = ndk_path
.join("toolchains")
.join("llvm")
.join("prebuilt")
.join(host_tag)
.join("bin")
.join(&expected_compiler);
let result = ndk_compiler(Language::C, target_triple, &ndk_path);
assert_eq!(result, expected_path);
}
#[test]
fn test_ndk_compiler_cpp() {
let ndk_path = PathBuf::from("/ndk");
let target_triple = "arm-unknown-linux-android";
let expected_triple_translated = "armv7a-unknown-linux-android";
let expected_compiler =
format!("{}21-{}", expected_triple_translated, Language::CPlusPlus.clang());
let host_tag = if cfg!(target_os = "macos") {
"darwin-x86_64"
} else if cfg!(target_os = "windows") {
"windows-x86_64"
} else {
"linux-x86_64"
};
let expected_path = ndk_path
.join("toolchains")
.join("llvm")
.join("prebuilt")
.join(host_tag)
.join("bin")
.join(&expected_compiler);
let result = ndk_compiler(Language::CPlusPlus, target_triple, &ndk_path);
assert_eq!(result, expected_path);
}
#[test]
fn test_language_gcc() {
assert_eq!(Language::C.gcc(), "gcc");
assert_eq!(Language::CPlusPlus.gcc(), "g++");
}
#[test]
fn test_language_clang() {
assert_eq!(Language::C.clang(), "clang");
assert_eq!(Language::CPlusPlus.clang(), "clang++");
}
#[test]
fn test_new_cc_build() {
let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
let cfg = new_cc_build(&build, target.clone());
let compiler = cfg.get_compiler();
assert!(!compiler.path().to_str().unwrap().is_empty(), "Compiler path should not be empty");
}
#[test]
fn test_default_compiler_wasi() {
let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
let target = TargetSelection::from_user("wasm32-wasi");
let wasi_sdk = PathBuf::from("/wasi-sdk");
env::set_var("WASI_SDK_PATH", &wasi_sdk);
let mut cfg = cc::Build::new();
if let Some(result) = default_compiler(&mut cfg, Language::C, target.clone(), &build) {
let expected = {
let compiler = format!("{}-clang", target.triple);
wasi_sdk.join("bin").join(compiler)
};
assert_eq!(result, expected);
} else {
panic!(
"default_compiler should return a compiler path for wasi target when WASI_SDK_PATH is set"
);
}
env::remove_var("WASI_SDK_PATH");
}
#[test]
fn test_default_compiler_fallback() {
let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
let mut cfg = cc::Build::new();
let result = default_compiler(&mut cfg, Language::C, target, &build);
assert!(result.is_none(), "default_compiler should return None for generic targets");
}
#[test]
fn test_find_target_with_config() {
let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
let mut target_config = Target::default();
target_config.cc = Some(PathBuf::from("dummy-cc"));
target_config.cxx = Some(PathBuf::from("dummy-cxx"));
target_config.ar = Some(PathBuf::from("dummy-ar"));
target_config.ranlib = Some(PathBuf::from("dummy-ranlib"));
build.config.target_config.insert(target.clone(), target_config);
find_target(&build, target.clone());
let binding = build.cc.borrow();
let cc_tool = binding.get(&target).unwrap();
assert_eq!(cc_tool.path(), &PathBuf::from("dummy-cc"));
let binding = build.cxx.borrow();
let cxx_tool = binding.get(&target).unwrap();
assert_eq!(cxx_tool.path(), &PathBuf::from("dummy-cxx"));
let binding = build.ar.borrow();
let ar = binding.get(&target).unwrap();
assert_eq!(ar, &PathBuf::from("dummy-ar"));
let binding = build.ranlib.borrow();
let ranlib = binding.get(&target).unwrap();
assert_eq!(ranlib, &PathBuf::from("dummy-ranlib"));
}
#[test]
fn test_find_target_without_config() {
let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
build.config.target_config.clear();
find_target(&build, target.clone());
assert!(build.cc.borrow().contains_key(&target));
if !target.triple.contains("vxworks") {
assert!(build.cxx.borrow().contains_key(&target));
}
assert!(build.ar.borrow().contains_key(&target));
}
#[test]
fn test_find() {
let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
let target1 = TargetSelection::from_user("x86_64-unknown-linux-gnu");
let target2 = TargetSelection::from_user("arm-linux-androideabi");
build.targets.push(target1.clone());
build.hosts.push(target2.clone());
find(&build);
for t in build.hosts.iter().chain(build.targets.iter()).chain(iter::once(&build.build)) {
assert!(build.cc.borrow().contains_key(t), "CC not set for target {}", t.triple);
}
}

View file

@ -30,6 +30,47 @@ MUSL=musl-1.2.3
# may have been downloaded in a previous run
if [ ! -d $MUSL ]; then
curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
# Apply patches for CVE-2025-26519. At the time of adding these patches no release containing them
# has been published by the musl project, so we just apply them directly on top of the version we
# were distributing already. The patches should be removed once we upgrade to musl >= 1.2.6.
#
# Advisory: https://www.openwall.com/lists/musl/2025/02/13/1
#
# Patches applied:
# - https://www.openwall.com/lists/musl/2025/02/13/1/1
# - https://www.openwall.com/lists/musl/2025/02/13/1/2
#
# ignore-tidy-tab
# ignore-tidy-linelength
patch -p1 -d $MUSL <<EOF
--- a/src/locale/iconv.c
+++ b/src/locale/iconv.c
@@ -502,7 +502,7 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
if (c >= 93 || d >= 94) {
c += (0xa1-0x81);
d += 0xa1;
- if (c >= 93 || c>=0xc6-0x81 && d>0x52)
+ if (c > 0xc6-0x81 || c==0xc6-0x81 && d>0x52)
goto ilseq;
if (d-'A'<26) d = d-'A';
else if (d-'a'<26) d = d-'a'+26;
EOF
patch -p1 -d $MUSL <<EOF
--- a/src/locale/iconv.c
+++ b/src/locale/iconv.c
@@ -545,6 +545,10 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
if (*outb < k) goto toobig;
memcpy(*out, tmp, k);
} else k = wctomb_utf8(*out, c);
+ /* This failure condition should be unreachable, but
+ * is included to prevent decoder bugs from translating
+ * into advancement outside the output buffer range. */
+ if (k>4) goto ilseq;
*out += k;
*outb -= k;
break;
EOF
fi
cd $MUSL

View file

@ -50,7 +50,7 @@ runners:
- &job-aarch64-linux
# Free some disk space to avoid running out of space during the build.
free_disk: true
os: ubuntu-22.04-arm
os: ubuntu-24.04-arm
- &job-aarch64-linux-8c
os: ubuntu-22.04-arm64-8core-32gb

View file

@ -38,7 +38,7 @@ use std::sync::{Arc, Weak};
use pulldown_cmark::{
BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag, TagEnd, html,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::{Diag, DiagMessage};
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::TyCtxt;
@ -1763,6 +1763,46 @@ pub(crate) fn markdown_links<'md, R>(
}
};
let span_for_refdef = |link: &CowStr<'_>, span: Range<usize>| {
// We want to underline the link's definition, but `span` will point at the entire refdef.
// Skip the label, then try to find the entire URL.
let mut square_brace_count = 0;
let mut iter = md.as_bytes()[span.start..span.end].iter().copied().enumerate();
for (_i, c) in &mut iter {
match c {
b':' if square_brace_count == 0 => break,
b'[' => square_brace_count += 1,
b']' => square_brace_count -= 1,
_ => {}
}
}
while let Some((i, c)) = iter.next() {
if c == b'<' {
while let Some((j, c)) = iter.next() {
match c {
b'\\' => {
let _ = iter.next();
}
b'>' => {
return MarkdownLinkRange::Destination(
i + 1 + span.start..j + span.start,
);
}
_ => {}
}
}
} else if !c.is_ascii_whitespace() {
while let Some((j, c)) = iter.next() {
if c.is_ascii_whitespace() {
return MarkdownLinkRange::Destination(i + span.start..j + span.start);
}
}
return MarkdownLinkRange::Destination(i + span.start..span.end);
}
}
span_for_link(link, span)
};
let span_for_offset_backward = |span: Range<usize>, open: u8, close: u8| {
let mut open_brace = !0;
let mut close_brace = !0;
@ -1844,9 +1884,16 @@ pub(crate) fn markdown_links<'md, R>(
.into_offset_iter();
let mut links = Vec::new();
let mut refdefs = FxIndexMap::default();
for (label, refdef) in event_iter.reference_definitions().iter() {
refdefs.insert(label.to_string(), (false, refdef.dest.to_string(), refdef.span.clone()));
}
for (event, span) in event_iter {
match event {
Event::Start(Tag::Link { link_type, dest_url, .. }) if may_be_doc_link(link_type) => {
Event::Start(Tag::Link { link_type, dest_url, id, .. })
if may_be_doc_link(link_type) =>
{
let range = match link_type {
// Link is pulled from the link itself.
LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => {
@ -1856,7 +1903,12 @@ pub(crate) fn markdown_links<'md, R>(
LinkType::Inline => span_for_offset_backward(span, b'(', b')'),
// Link is pulled from elsewhere in the document.
LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => {
span_for_link(&dest_url, span)
if let Some((is_used, dest_url, span)) = refdefs.get_mut(&id[..]) {
*is_used = true;
span_for_refdef(&CowStr::from(&dest_url[..]), span.clone())
} else {
span_for_link(&dest_url, span)
}
}
LinkType::Autolink | LinkType::Email => unreachable!(),
};
@ -1873,6 +1925,18 @@ pub(crate) fn markdown_links<'md, R>(
}
}
for (_label, (is_used, dest_url, span)) in refdefs.into_iter() {
if !is_used
&& let Some(link) = preprocess_link(MarkdownLink {
kind: LinkType::Reference,
range: span_for_refdef(&CowStr::from(&dest_url[..]), span),
link: dest_url,
})
{
links.push(link);
}
}
links
}

View file

@ -1,6 +1,6 @@
//@error-in-other-file: the program aborted execution
//@normalize-stderr-test: "\| +\^+" -> "| ^"
//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();"
//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();"
//@compile-flags: -C panic=abort
fn main() {

View file

@ -1,6 +1,6 @@
//@error-in-other-file: the program aborted execution
//@normalize-stderr-test: "\| +\^+" -> "| ^"
//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();"
//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();"
//@compile-flags: -C panic=abort
fn main() {

View file

@ -1,6 +1,6 @@
//@error-in-other-file: the program aborted execution
//@normalize-stderr-test: "\| +\^+" -> "| ^"
//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();"
//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();"
//@compile-flags: -C panic=abort
fn main() {

View file

@ -1,6 +1,6 @@
//@error-in-other-file: the program aborted execution
//@normalize-stderr-test: "\| +\^+" -> "| ^"
//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();"
//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();"
//@compile-flags: -C panic=abort
fn main() {

View file

@ -12,6 +12,7 @@
let mut _7: std::boxed::Box<S>;
+ let mut _8: &mut std::boxed::Box<S>;
+ let mut _9: ();
+ let mut _10: *const S;
scope 1 {
debug x => _1;
}
@ -68,7 +69,7 @@
bb8 (cleanup): {
- drop(_5) -> [return: bb9, unwind terminate(cleanup)];
+ goto -> bb11;
+ goto -> bb12;
}
bb9 (cleanup): {
@ -82,6 +83,11 @@
+
+ bb11 (cleanup): {
+ goto -> bb10;
+ }
+
+ bb12 (cleanup): {
+ _10 = copy ((_5.0: std::ptr::Unique<S>).0: std::ptr::NonNull<S>) as *const S (Transmute);
+ goto -> bb11;
}
}

View file

@ -0,0 +1,94 @@
- // MIR for `maybe_move` before ElaborateDrops
+ // MIR for `maybe_move` after ElaborateDrops
fn maybe_move(_1: bool, _2: Box<String>) -> Option<String> {
debug cond => _1;
debug thing => _2;
let mut _0: std::option::Option<std::string::String>;
let mut _3: bool;
let mut _4: std::string::String;
+ let mut _5: bool;
+ let mut _6: &mut std::boxed::Box<std::string::String>;
+ let mut _7: ();
+ let mut _8: &mut std::boxed::Box<std::string::String>;
+ let mut _9: ();
+ let mut _10: *const std::string::String;
bb0: {
+ _5 = const false;
+ _5 = const true;
StorageLive(_3);
_3 = copy _1;
switchInt(move _3) -> [0: bb3, otherwise: bb1];
}
bb1: {
StorageLive(_4);
+ _5 = const false;
_4 = move (*_2);
_0 = Option::<String>::Some(move _4);
- drop(_4) -> [return: bb2, unwind: bb6];
+ goto -> bb2;
}
bb2: {
StorageDead(_4);
goto -> bb4;
}
bb3: {
_0 = Option::<String>::None;
goto -> bb4;
}
bb4: {
StorageDead(_3);
- drop(_2) -> [return: bb5, unwind continue];
+ goto -> bb14;
}
bb5: {
return;
}
bb6 (cleanup): {
- drop(_2) -> [return: bb7, unwind terminate(cleanup)];
+ goto -> bb7;
}
bb7 (cleanup): {
resume;
+ }
+
+ bb8: {
+ goto -> bb5;
+ }
+
+ bb9: {
+ _6 = &mut _2;
+ _7 = <Box<String> as Drop>::drop(move _6) -> [return: bb8, unwind: bb7];
+ }
+
+ bb10 (cleanup): {
+ _8 = &mut _2;
+ _9 = <Box<String> as Drop>::drop(move _8) -> [return: bb7, unwind terminate(cleanup)];
+ }
+
+ bb11: {
+ goto -> bb13;
+ }
+
+ bb12: {
+ drop((*_10)) -> [return: bb9, unwind: bb10];
+ }
+
+ bb13: {
+ switchInt(copy _5) -> [0: bb9, otherwise: bb12];
+ }
+
+ bb14: {
+ _10 = copy ((_2.0: std::ptr::Unique<std::string::String>).0: std::ptr::NonNull<std::string::String>) as *const std::string::String (Transmute);
+ goto -> bb11;
}
}

View file

@ -0,0 +1,17 @@
//@ test-mir-pass: ElaborateDrops
//@ needs-unwind
#![feature(rustc_attrs, liballoc_internals)]
// EMIT_MIR box_partial_move.maybe_move.ElaborateDrops.diff
fn maybe_move(cond: bool, thing: Box<String>) -> Option<String> {
// CHECK-LABEL: fn maybe_move(
// CHECK: let mut [[PTR:_[0-9]+]]: *const std::string::String;
// CHECK: [[PTR]] = copy ((_2.0: std::ptr::Unique<std::string::String>).0: std::ptr::NonNull<std::string::String>) as *const std::string::String (Transmute);
// CHECK: drop((*[[PTR]]))
if cond { Some(*thing) } else { None }
}
fn main() {
maybe_move(false, Box::new("hello".to_string()));
}

View file

@ -117,24 +117,49 @@ pub struct WLinkToCloneWithUnmatchedEscapedCloseParenAndDoubleSpace;
// References
/// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected //~ERROR link
/// in Markdown for not being URL-shaped enough.
///
/// [cln]: Clone() //~ERROR link
/// The [cln][] link here is going to be unresolved, because `Clone()` gets
//~^ ERROR link
/// rejected in Markdown for not being URL-shaped enough.
/// [cln]: Clone()
//~^ ERROR link
pub struct LinkToCloneWithParensInReference;
/// The [cln][] link here is going to be unresolved, because `struct@Clone` gets //~ERROR link
/// rejected in Markdown for not being URL-shaped enough.
/// The [cln][] link here is going to produce a good inline suggestion
///
/// [cln]: struct@Clone //~ERROR link
/// [cln]: struct@Clone
//~^ ERROR link
pub struct LinkToCloneWithWrongPrefix;
/// The [cln][] link here will produce a plain text suggestion //~ERROR link
/// The [cln][] link here will produce a good inline suggestion
///
/// [cln]: Clone\(\)
//~^ ERROR link
pub struct LinkToCloneWithEscapedParensInReference;
/// The [cln][] link here will produce a plain text suggestion //~ERROR link
/// The [cln][] link here will produce a good inline suggestion
///
/// [cln]: struct\@Clone
//~^ ERROR link
pub struct LinkToCloneWithEscapedAtsInReference;
/// This link reference definition isn't used, but since it is still parsed,
/// it should still produce a warning.
///
/// [cln]: struct\@Clone
//~^ ERROR link
pub struct UnusedLinkToCloneReferenceDefinition;
/// <https://github.com/rust-lang/rust/issues/133150>
///
/// - [`SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER`]: the
//~^ ERROR link
/// `(__unsafe_unretained)` NSWindow associated with the window, if you want
/// to wrap an existing window.
/// - [`SDL_PROP_WINDOW_CREATE_COCOA_VIEW_POINTER`]: the `(__unsafe_unretained)`
/// NSView associated with the window, defaults to `[window contentView]`
pub fn a() {}
#[allow(nonstandard_style)]
pub struct SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER;
#[allow(nonstandard_style)]
pub struct SDL_PROP_WINDOW_CREATE_COCOA_VIEW_POINTER;

View file

@ -230,7 +230,7 @@ LL | /// [w](Clone \))
error: unresolved link to `cln`
--> $DIR/weird-syntax.rs:120:10
|
LL | /// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected
LL | /// The [cln][] link here is going to be unresolved, because `Clone()` gets
| ^^^ no item named `cln` in scope
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -243,37 +243,61 @@ LL | /// [cln]: Clone()
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: unresolved link to `cln`
--> $DIR/weird-syntax.rs:126:10
|
LL | /// The [cln][] link here is going to be unresolved, because `struct@Clone` gets
| ^^^ no item named `cln` in scope
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: unresolved link to `cln`
--> $DIR/weird-syntax.rs:129:6
error: incompatible link kind for `Clone`
--> $DIR/weird-syntax.rs:129:12
|
LL | /// [cln]: struct@Clone
| ^^^ no item named `cln` in scope
| ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
|
help: to link to the trait, prefix with `trait@`
|
LL - /// [cln]: struct@Clone
LL + /// [cln]: trait@Clone
|
error: unresolved link to `Clone`
--> $DIR/weird-syntax.rs:135:12
|
LL | /// [cln]: Clone\(\)
| ^^^^^^^^^ this link resolves to the trait `Clone`, which is not a function
|
help: to link to the trait, prefix with `trait@`
|
LL - /// [cln]: Clone\(\)
LL + /// [cln]: trait@Clone
|
error: incompatible link kind for `Clone`
--> $DIR/weird-syntax.rs:141:12
|
LL | /// [cln]: struct\@Clone
| ^^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
|
help: to link to the trait, prefix with `trait@`
|
LL - /// [cln]: struct\@Clone
LL + /// [cln]: trait@struct
|
error: incompatible link kind for `Clone`
--> $DIR/weird-syntax.rs:149:12
|
LL | /// [cln]: struct\@Clone
| ^^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
|
help: to link to the trait, prefix with `trait@`
|
LL - /// [cln]: struct\@Clone
LL + /// [cln]: trait@struct
|
error: unresolved link to `the`
--> $DIR/weird-syntax.rs:155:56
|
LL | /// - [`SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER`]: the
| ^^^ no item named `the` in scope
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: unresolved link to `Clone`
--> $DIR/weird-syntax.rs:132:9
|
LL | /// The [cln][] link here will produce a plain text suggestion
| ^^^^^ this link resolves to the trait `Clone`, which is not a function
|
= help: to link to the trait, prefix with `trait@`: trait@Clone
error: incompatible link kind for `Clone`
--> $DIR/weird-syntax.rs:137:9
|
LL | /// The [cln][] link here will produce a plain text suggestion
| ^^^^^ this link resolved to a trait, which is not a struct
|
= help: to link to the trait, prefix with `trait@`: trait@Clone
error: aborting due to 26 previous errors
error: aborting due to 27 previous errors

View file

@ -0,0 +1,13 @@
// Make sure we don't ICE when trying to name the regions that appear in the alias
// of the type test error.
trait AnotherTrait {
type Ty2<'a>;
}
fn test_alias<T: AnotherTrait>(_: &'static T::Ty2<'_>) {
let _: &'static T::Ty2<'_>;
//~^ ERROR the associated type `<T as AnotherTrait>::Ty2<'_>` may not live long enough
}
fn main() {}

View file

@ -0,0 +1,14 @@
error[E0310]: the associated type `<T as AnotherTrait>::Ty2<'_>` may not live long enough
--> $DIR/name-region.rs:9:12
|
LL | let _: &'static T::Ty2<'_>;
| ^^^^^^^^^^^^^^^^^^^
| |
| the associated type `<T as AnotherTrait>::Ty2<'_>` must be valid for the static lifetime...
| ...so that the type `<T as AnotherTrait>::Ty2<'_>` will meet its required lifetime bounds
|
= help: consider adding an explicit lifetime bound `<T as AnotherTrait>::Ty2<'_>: 'static`...
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0310`.

View file

@ -9,3 +9,10 @@ macro_rules! mixed_edition_pat {
Some(mut $foo)
};
}
#[macro_export]
macro_rules! bind_ref {
($foo:ident) => {
ref $foo
};
}

View file

@ -239,4 +239,9 @@ fn main() {
assert_type_eq(b, &0u32);
assert_type_eq(c, &[0u32]);
assert_type_eq(d, 0u32);
// Test that we use the correct message and suggestion style when pointing inside expansions.
let &[migration_lint_macros::bind_ref!(a)] = &[0];
//~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
assert_type_eq(a, &0u32);
}

View file

@ -239,4 +239,9 @@ fn main() {
assert_type_eq(b, &0u32);
assert_type_eq(c, &[0u32]);
assert_type_eq(d, 0u32);
// Test that we use the correct message and suggestion style when pointing inside expansions.
let [migration_lint_macros::bind_ref!(a)] = &[0];
//~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
assert_type_eq(a, &0u32);
}

View file

@ -562,5 +562,23 @@ help: make the implied reference patterns explicit
LL | let [&Foo(&ref a @ [ref b]), &Foo(&ref c @ [d])] = [&Foo(&[0]); 2];
| + +
error: aborting due to 29 previous errors
error: binding modifiers may only be written when the default binding mode is `move`
--> $DIR/migration_lint.rs:244:10
|
LL | let [migration_lint_macros::bind_ref!(a)] = &[0];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ occurs within macro expansion
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
note: matching on a reference type with a non-reference pattern changes the default binding mode
--> $DIR/migration_lint.rs:244:9
|
LL | let [migration_lint_macros::bind_ref!(a)] = &[0];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
= note: this error originates in the macro `migration_lint_macros::bind_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
help: make the implied reference pattern explicit
|
LL | let &[migration_lint_macros::bind_ref!(a)] = &[0];
| +
error: aborting due to 30 previous errors

View file

@ -2,8 +2,8 @@
// ICE: tcx.resolutions(()) is not supported for local crate -Zunpretty=mir
// on invalid module path with staged_api
//@ compile-flags: -Zunpretty=mir
//@ normalize-stderr: "The system cannot find the file specified." -> "No such file or directory"
//@ normalize-stderr: "lol`: .*\(" -> "lol`: $$FILE_NOT_FOUND_MSG ("
#![feature(staged_api)]
#[path = "lol"]
mod foo;
//~^ ERROR couldn't read
//~^ ERROR couldn't read `$DIR/lol`

View file

@ -1,4 +1,4 @@
error: couldn't read `$DIR/lol`: No such file or directory (os error 2)
error: couldn't read `$DIR/lol`: $FILE_NOT_FOUND_MSG (os error 2)
--> $DIR/staged-api-invalid-path-108697.rs:8:1
|
LL | mod foo;