Merge from rustc
This commit is contained in:
commit
9743852f3b
63 changed files with 1016 additions and 251 deletions
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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>>,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
/// }
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
/// }
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
/// }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() -> ! {
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
/// }
|
||||
/// }
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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")))]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<'_>) {
|
||||
|
|
|
|||
|
|
@ -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<'_>) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
254
src/bootstrap/src/utils/cc_detect/tests.rs
Normal file
254
src/bootstrap/src/utils/cc_detect/tests.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
17
tests/mir-opt/box_partial_move.rs
Normal file
17
tests/mir-opt/box_partial_move.rs
Normal 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()));
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
13
tests/ui/borrowck/alias-liveness/name-region.rs
Normal file
13
tests/ui/borrowck/alias-liveness/name-region.rs
Normal 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() {}
|
||||
14
tests/ui/borrowck/alias-liveness/name-region.stderr
Normal file
14
tests/ui/borrowck/alias-liveness/name-region.stderr
Normal 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`.
|
||||
|
|
@ -9,3 +9,10 @@ macro_rules! mixed_edition_pat {
|
|||
Some(mut $foo)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! bind_ref {
|
||||
($foo:ident) => {
|
||||
ref $foo
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue