Auto merge of #128673 - matthiaskrgr:rollup-gtvpkm7, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #128026 (std:🧵 available_parallelism implementation for vxWorks proposal.)
 - #128471 (rustdoc: Fix handling of `Self` type in search index and refactor its representation)
 - #128607 (Use `object` in `run-make/symbols-visibility`)
 - #128609 (Remove unnecessary constants from flt2dec dragon)
 - #128611 (run-make: Remove cygpath)
 - #128619 (Correct the const stabilization of `<[T]>::last_chunk`)
 - #128630 (docs(resolve): more explain about `target`)
 - #128660 (tests: more crashes)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-08-05 06:55:50 +00:00
commit 4d48a6be74
27 changed files with 495 additions and 428 deletions

View File

@ -48,6 +48,7 @@ pub(crate) enum ImportKind<'a> {
/// `source` in `use prefix::source as target`. /// `source` in `use prefix::source as target`.
source: Ident, source: Ident,
/// `target` in `use prefix::source as target`. /// `target` in `use prefix::source as target`.
/// It will directly use `source` when the format is `use prefix::source`.
target: Ident, target: Ident,
/// Bindings to which `source` refers to. /// Bindings to which `source` refers to.
source_bindings: PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>, source_bindings: PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>,

View File

@ -12,48 +12,51 @@ use crate::num::flt2dec::{round_up, Decoded, MAX_SIG_DIGITS};
static POW10: [Digit; 10] = static POW10: [Digit; 10] =
[1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000]; [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000];
static TWOPOW10: [Digit; 10] = // precalculated arrays of `Digit`s for 5^(2^n).
[2, 20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000]; static POW5TO16: [Digit; 2] = [0x86f26fc1, 0x23];
static POW5TO32: [Digit; 3] = [0x85acef81, 0x2d6d415b, 0x4ee];
// precalculated arrays of `Digit`s for 10^(2^n) static POW5TO64: [Digit; 5] = [0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03];
static POW10TO16: [Digit; 2] = [0x6fc10000, 0x2386f2]; static POW5TO128: [Digit; 10] = [
static POW10TO32: [Digit; 4] = [0, 0x85acef81, 0x2d6d415b, 0x4ee]; 0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da, 0xa6337f19,
static POW10TO64: [Digit; 7] = [0, 0, 0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03]; 0xe91f2603, 0x24e,
static POW10TO128: [Digit; 14] = [
0, 0, 0, 0, 0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da,
0xa6337f19, 0xe91f2603, 0x24e,
]; ];
static POW10TO256: [Digit; 27] = [ static POW5TO256: [Digit; 19] = [
0, 0, 0, 0, 0, 0, 0, 0, 0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70, 0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70, 0xd595d80f, 0x26b2716e,
0xd595d80f, 0x26b2716e, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17, 0x55bc28f2, 0x80dcc7f7,
0x55bc28f2, 0x80dcc7f7, 0xf46eeddc, 0x5fdcefce, 0x553f7, 0xf46eeddc, 0x5fdcefce, 0x553f7,
]; ];
#[doc(hidden)] #[doc(hidden)]
pub fn mul_pow10(x: &mut Big, n: usize) -> &mut Big { pub fn mul_pow10(x: &mut Big, n: usize) -> &mut Big {
debug_assert!(n < 512); debug_assert!(n < 512);
// Save ourself the left shift for the smallest cases.
if n < 8 {
return x.mul_small(POW10[n & 7]);
}
// Multiply by the powers of 5 and shift the 2s in at the end.
// This keeps the intermediate products smaller and faster.
if n & 7 != 0 { if n & 7 != 0 {
x.mul_small(POW10[n & 7]); x.mul_small(POW10[n & 7] >> (n & 7));
} }
if n & 8 != 0 { if n & 8 != 0 {
x.mul_small(POW10[8]); x.mul_small(POW10[8] >> 8);
} }
if n & 16 != 0 { if n & 16 != 0 {
x.mul_digits(&POW10TO16); x.mul_digits(&POW5TO16);
} }
if n & 32 != 0 { if n & 32 != 0 {
x.mul_digits(&POW10TO32); x.mul_digits(&POW5TO32);
} }
if n & 64 != 0 { if n & 64 != 0 {
x.mul_digits(&POW10TO64); x.mul_digits(&POW5TO64);
} }
if n & 128 != 0 { if n & 128 != 0 {
x.mul_digits(&POW10TO128); x.mul_digits(&POW5TO128);
} }
if n & 256 != 0 { if n & 256 != 0 {
x.mul_digits(&POW10TO256); x.mul_digits(&POW5TO256);
} }
x x.mul_pow2(n)
} }
fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big { fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big {
@ -62,7 +65,7 @@ fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big {
x.div_rem_small(POW10[largest]); x.div_rem_small(POW10[largest]);
n -= largest; n -= largest;
} }
x.div_rem_small(TWOPOW10[n]); x.div_rem_small(POW10[n] << 1);
x x
} }

View File

@ -522,7 +522,7 @@ impl<T> [T] {
/// ``` /// ```
#[inline] #[inline]
#[stable(feature = "slice_first_last_chunk", since = "1.77.0")] #[stable(feature = "slice_first_last_chunk", since = "1.77.0")]
#[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] #[rustc_const_stable(feature = "const_slice_last_chunk", since = "1.80.0")]
pub const fn last_chunk<const N: usize>(&self) -> Option<&[T; N]> { pub const fn last_chunk<const N: usize>(&self) -> Option<&[T; N]> {
if self.len() < N { if self.len() < N {
None None

View File

@ -455,8 +455,18 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
Ok(NonZero::new_unchecked(sinfo.cpu_count as usize)) Ok(NonZero::new_unchecked(sinfo.cpu_count as usize))
} }
} else if #[cfg(target_os = "vxworks")] {
// Note: there is also `vxCpuConfiguredGet`, closer to _SC_NPROCESSORS_CONF
// expectations than the actual cores availability.
extern "C" {
fn vxCpuEnabledGet() -> libc::cpuset_t;
}
// always fetches a valid bitmask
let set = unsafe { vxCpuEnabledGet() };
Ok(NonZero::new_unchecked(set.count_ones() as usize))
} else { } else {
// FIXME: implement on vxWorks, Redox, l4re // FIXME: implement on Redox, l4re
Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform")) Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform"))
} }
} }

View File

@ -12,7 +12,7 @@ use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::LOCAL_CRATE; use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::hygiene::MacroKind; use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::symbol::{sym, Symbol};
use thin_vec::{thin_vec, ThinVec}; use thin_vec::{thin_vec, ThinVec};
use {rustc_ast as ast, rustc_hir as hir}; use {rustc_ast as ast, rustc_hir as hir};
@ -792,11 +792,7 @@ fn build_macro(
fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics { fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
for pred in &mut g.where_predicates { for pred in &mut g.where_predicates {
match *pred { match *pred {
clean::WherePredicate::BoundPredicate { clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref mut bounds, .. } => {
ty: clean::Generic(ref s),
ref mut bounds,
..
} if *s == kw::SelfUpper => {
bounds.retain(|bound| match bound { bounds.retain(|bound| match bound {
clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => { clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => {
trait_.def_id() != trait_did trait_.def_id() != trait_did
@ -812,13 +808,13 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
clean::WherePredicate::BoundPredicate { clean::WherePredicate::BoundPredicate {
ty: ty:
clean::QPath(box clean::QPathData { clean::QPath(box clean::QPathData {
self_type: clean::Generic(ref s), self_type: clean::Generic(_),
trait_: Some(trait_), trait_: Some(trait_),
.. ..
}), }),
bounds, bounds,
.. ..
} => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did), } => !bounds.is_empty() && trait_.def_id() != trait_did,
_ => true, _ => true,
}); });
g g
@ -832,9 +828,7 @@ fn separate_supertrait_bounds(
) -> (clean::Generics, Vec<clean::GenericBound>) { ) -> (clean::Generics, Vec<clean::GenericBound>) {
let mut ty_bounds = Vec::new(); let mut ty_bounds = Vec::new();
g.where_predicates.retain(|pred| match *pred { g.where_predicates.retain(|pred| match *pred {
clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds, .. } clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref bounds, .. } => {
if *s == kw::SelfUpper =>
{
ty_bounds.extend(bounds.iter().cloned()); ty_bounds.extend(bounds.iter().cloned());
false false
} }

View File

@ -1351,11 +1351,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
let self_arg_ty = let self_arg_ty =
tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder(); tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
if self_arg_ty == self_ty { if self_arg_ty == self_ty {
item.decl.inputs.values[0].type_ = Generic(kw::SelfUpper); item.decl.inputs.values[0].type_ = SelfTy;
} else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() { } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
if ty == self_ty { if ty == self_ty {
match item.decl.inputs.values[0].type_ { match item.decl.inputs.values[0].type_ {
BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper), BorrowedRef { ref mut type_, .. } => **type_ = SelfTy,
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -1439,9 +1439,8 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
if trait_.def_id() != assoc_item.container_id(tcx) { if trait_.def_id() != assoc_item.container_id(tcx) {
return true; return true;
} }
match *self_type { if *self_type != SelfTy {
Generic(ref s) if *s == kw::SelfUpper => {} return true;
_ => return true,
} }
match &assoc.args { match &assoc.args {
GenericArgs::AngleBracketed { args, constraints } => { GenericArgs::AngleBracketed { args, constraints } => {
@ -2228,6 +2227,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
ty::Param(ref p) => { ty::Param(ref p) => {
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) { if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
ImplTrait(bounds) ImplTrait(bounds)
} else if p.name == kw::SelfUpper {
SelfTy
} else { } else {
Generic(p.name) Generic(p.name)
} }

View File

@ -145,7 +145,6 @@ pub(crate) fn sized_bounds(cx: &mut DocContext<'_>, generics: &mut clean::Generi
// should be handled when cleaning associated types. // should be handled when cleaning associated types.
generics.where_predicates.retain(|pred| { generics.where_predicates.retain(|pred| {
if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred
&& *param != rustc_span::symbol::kw::SelfUpper
&& bounds.iter().any(|b| b.is_sized_bound(cx)) && bounds.iter().any(|b| b.is_sized_bound(cx))
{ {
sized_params.insert(*param); sized_params.insert(*param);

View File

@ -34,10 +34,9 @@ use thin_vec::ThinVec;
use {rustc_ast as ast, rustc_hir as hir}; use {rustc_ast as ast, rustc_hir as hir};
pub(crate) use self::ItemKind::*; pub(crate) use self::ItemKind::*;
pub(crate) use self::SelfTy::*;
pub(crate) use self::Type::{ pub(crate) use self::Type::{
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath, Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
RawPointer, Slice, Tuple, RawPointer, SelfTy, Slice, Tuple,
}; };
use crate::clean::cfg::Cfg; use crate::clean::cfg::Cfg;
use crate::clean::clean_middle_path; use crate::clean::clean_middle_path;
@ -1384,8 +1383,8 @@ pub(crate) struct FnDecl {
} }
impl FnDecl { impl FnDecl {
pub(crate) fn self_type(&self) -> Option<SelfTy> { pub(crate) fn receiver_type(&self) -> Option<&Type> {
self.inputs.values.get(0).and_then(|v| v.to_self()) self.inputs.values.get(0).and_then(|v| v.to_receiver())
} }
} }
@ -1403,27 +1402,9 @@ pub(crate) struct Argument {
pub(crate) is_const: bool, pub(crate) is_const: bool,
} }
#[derive(Clone, PartialEq, Debug)]
pub(crate) enum SelfTy {
SelfValue,
SelfBorrowed(Option<Lifetime>, Mutability),
SelfExplicit(Type),
}
impl Argument { impl Argument {
pub(crate) fn to_self(&self) -> Option<SelfTy> { pub(crate) fn to_receiver(&self) -> Option<&Type> {
if self.name != kw::SelfLower { if self.name == kw::SelfLower { Some(&self.type_) } else { None }
return None;
}
if self.type_.is_self_type() {
return Some(SelfValue);
}
match self.type_ {
BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => {
Some(SelfBorrowed(lifetime.clone(), mutability))
}
_ => Some(SelfExplicit(self.type_.clone())),
}
} }
} }
@ -1477,6 +1458,8 @@ pub(crate) enum Type {
DynTrait(Vec<PolyTrait>, Option<Lifetime>), DynTrait(Vec<PolyTrait>, Option<Lifetime>),
/// A type parameter. /// A type parameter.
Generic(Symbol), Generic(Symbol),
/// The `Self` type.
SelfTy,
/// A primitive (aka, builtin) type. /// A primitive (aka, builtin) type.
Primitive(PrimitiveType), Primitive(PrimitiveType),
/// A function pointer: `extern "ABI" fn(...) -> ...` /// A function pointer: `extern "ABI" fn(...) -> ...`
@ -1571,6 +1554,8 @@ impl Type {
// If both sides are generic, this returns true. // If both sides are generic, this returns true.
(_, Type::Generic(_)) => true, (_, Type::Generic(_)) => true,
(Type::Generic(_), _) => false, (Type::Generic(_), _) => false,
// `Self` only matches itself.
(Type::SelfTy, Type::SelfTy) => true,
// Paths account for both the path itself and its generics. // Paths account for both the path itself and its generics.
(Type::Path { path: a }, Type::Path { path: b }) => { (Type::Path { path: a }, Type::Path { path: b }) => {
a.def_id() == b.def_id() a.def_id() == b.def_id()
@ -1642,7 +1627,7 @@ impl Type {
pub(crate) fn is_self_type(&self) -> bool { pub(crate) fn is_self_type(&self) -> bool {
match *self { match *self {
Generic(name) => name == kw::SelfUpper, SelfTy => true,
_ => false, _ => false,
} }
} }
@ -1700,7 +1685,7 @@ impl Type {
Type::Pat(..) => PrimitiveType::Pat, Type::Pat(..) => PrimitiveType::Pat,
RawPointer(..) => PrimitiveType::RawPointer, RawPointer(..) => PrimitiveType::RawPointer,
QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache), QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
Generic(_) | Infer | ImplTrait(_) => return None, Generic(_) | SelfTy | Infer | ImplTrait(_) => return None,
}; };
Primitive(t).def_id(cache) Primitive(t).def_id(cache)
} }

View File

@ -468,7 +468,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
match path.res { match path.res {
Res::PrimTy(p) => Primitive(PrimitiveType::from(p)), Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } if path.segments.len() == 1 => { Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } if path.segments.len() == 1 => {
Generic(kw::SelfUpper) Type::SelfTy
} }
Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name), Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
_ => { _ => {

View File

@ -1006,6 +1006,7 @@ fn fmt_type<'cx>(
match *t { match *t {
clean::Generic(name) => f.write_str(name.as_str()), clean::Generic(name) => f.write_str(name.as_str()),
clean::SelfTy => f.write_str("Self"),
clean::Type::Path { ref path } => { clean::Type::Path { ref path } => {
// Paths like `T::Output` and `Self::Output` should be rendered with all segments. // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
let did = path.def_id(); let did = path.def_id();
@ -1452,29 +1453,22 @@ impl clean::FnDecl {
let last_input_index = self.inputs.values.len().checked_sub(1); let last_input_index = self.inputs.values.len().checked_sub(1);
for (i, input) in self.inputs.values.iter().enumerate() { for (i, input) in self.inputs.values.iter().enumerate() {
if let Some(selfty) = input.to_self() { if let Some(selfty) = input.to_receiver() {
match selfty { match selfty {
clean::SelfValue => { clean::SelfTy => {
write!(f, "self")?; write!(f, "self")?;
} }
clean::SelfBorrowed(Some(ref lt), mutability) => { clean::BorrowedRef { lifetime, mutability, type_: box clean::SelfTy } => {
write!( write!(f, "{amp}")?;
f, match lifetime {
"{amp}{lifetime} {mutability}self", Some(lt) => write!(f, "{lt} ", lt = lt.print())?,
lifetime = lt.print(), None => {}
mutability = mutability.print_with_space(), }
)?; write!(f, "{mutability}self", mutability = mutability.print_with_space())?;
} }
clean::SelfBorrowed(None, mutability) => { _ => {
write!(
f,
"{amp}{mutability}self",
mutability = mutability.print_with_space(),
)?;
}
clean::SelfExplicit(ref typ) => {
write!(f, "self: ")?; write!(f, "self: ")?;
typ.print(cx).fmt(f)?; selfty.print(cx).fmt(f)?;
} }
} }
} else { } else {

View File

@ -58,7 +58,7 @@ use serde::{Serialize, Serializer};
pub(crate) use self::context::*; pub(crate) use self::context::*;
pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc}; pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
use crate::clean::{self, ItemId, RenderedLink, SelfTy}; use crate::clean::{self, ItemId, RenderedLink};
use crate::error::Error; use crate::error::Error;
use crate::formats::cache::Cache; use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType; use crate::formats::item_type::ItemType;
@ -1372,21 +1372,20 @@ fn render_deref_methods(
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool { fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
let self_type_opt = match *item.kind { let self_type_opt = match *item.kind {
clean::MethodItem(ref method, _) => method.decl.self_type(), clean::MethodItem(ref method, _) => method.decl.receiver_type(),
clean::TyMethodItem(ref method) => method.decl.self_type(), clean::TyMethodItem(ref method) => method.decl.receiver_type(),
_ => None, _ => None,
}; };
if let Some(self_ty) = self_type_opt { if let Some(self_ty) = self_type_opt {
let (by_mut_ref, by_box, by_value) = match self_ty { let (by_mut_ref, by_box, by_value) = match *self_ty {
SelfTy::SelfBorrowed(_, mutability) clean::Type::BorrowedRef { mutability, .. } => {
| SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
(mutability == Mutability::Mut, false, false) (mutability == Mutability::Mut, false, false)
} }
SelfTy::SelfExplicit(clean::Type::Path { path }) => { clean::Type::Path { ref path } => {
(false, Some(path.def_id()) == tcx.lang_items().owned_box(), false) (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
} }
SelfTy::SelfValue => (false, false, true), clean::Type::SelfTy => (false, false, true),
_ => (false, false, false), _ => (false, false, false),
}; };

View File

@ -797,7 +797,11 @@ fn get_index_type_id(
} }
} }
// Not supported yet // Not supported yet
clean::Type::Pat(..) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None, clean::Type::Pat(..)
| clean::Generic(_)
| clean::SelfTy
| clean::ImplTrait(_)
| clean::Infer => None,
} }
} }
@ -850,15 +854,70 @@ fn simplify_fn_type<'tcx, 'a>(
// If this argument is a type parameter and not a trait bound or a type, we need to look // If this argument is a type parameter and not a trait bound or a type, we need to look
// for its bounds. // for its bounds.
if let Type::Generic(arg_s) = *arg { match *arg {
// First we check if the bounds are in a `where` predicate... Type::Generic(arg_s) => {
let mut type_bounds = Vec::new(); // First we check if the bounds are in a `where` predicate...
for where_pred in generics.where_predicates.iter().filter(|g| match g { let mut type_bounds = Vec::new();
WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s, for where_pred in generics.where_predicates.iter().filter(|g| match g {
_ => false, WherePredicate::BoundPredicate { ty, .. } => *ty == *arg,
}) { _ => false,
let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]); }) {
for bound in bounds.iter() { let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
for bound in bounds.iter() {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut type_bounds,
rgen,
is_return,
cache,
);
}
}
}
// Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
for bound in bound.get_bounds().unwrap_or(&[]) {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut type_bounds,
rgen,
is_return,
cache,
);
}
}
}
if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
res.push(RenderType {
id: Some(RenderTypeId::Index(*idx)),
generics: None,
bindings: None,
});
} else {
let idx = -isize::try_from(rgen.len() + 1).unwrap();
rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
res.push(RenderType {
id: Some(RenderTypeId::Index(idx)),
generics: None,
bindings: None,
});
}
}
Type::ImplTrait(ref bounds) => {
let mut type_bounds = Vec::new();
for bound in bounds {
if let Some(path) = bound.get_trait_path() { if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path }; let ty = Type::Path { path };
simplify_fn_type( simplify_fn_type(
@ -874,103 +933,22 @@ fn simplify_fn_type<'tcx, 'a>(
); );
} }
} }
} if is_return && !type_bounds.is_empty() {
// Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`... // In return position, `impl Trait` is a unique thing.
if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
for bound in bound.get_bounds().unwrap_or(&[]) { } else {
if let Some(path) = bound.get_trait_path() { // In parameter position, `impl Trait` is the same as an unnamed generic parameter.
let ty = Type::Path { path }; let idx = -isize::try_from(rgen.len() + 1).unwrap();
simplify_fn_type( rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
self_, res.push(RenderType {
generics, id: Some(RenderTypeId::Index(idx)),
&ty, generics: None,
tcx, bindings: None,
recurse + 1, });
&mut type_bounds,
rgen,
is_return,
cache,
);
}
} }
} }
if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) { Type::Slice(ref ty) => {
res.push(RenderType { let mut ty_generics = Vec::new();
id: Some(RenderTypeId::Index(*idx)),
generics: None,
bindings: None,
});
} else {
let idx = -isize::try_from(rgen.len() + 1).unwrap();
rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
res.push(RenderType {
id: Some(RenderTypeId::Index(idx)),
generics: None,
bindings: None,
});
}
} else if let Type::ImplTrait(ref bounds) = *arg {
let mut type_bounds = Vec::new();
for bound in bounds {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut type_bounds,
rgen,
is_return,
cache,
);
}
}
if is_return && !type_bounds.is_empty() {
// In parameter position, `impl Trait` is a unique thing.
res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
} else {
// In parameter position, `impl Trait` is the same as an unnamed generic parameter.
let idx = -isize::try_from(rgen.len() + 1).unwrap();
rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
res.push(RenderType {
id: Some(RenderTypeId::Index(idx)),
generics: None,
bindings: None,
});
}
} else if let Type::Slice(ref ty) = *arg {
let mut ty_generics = Vec::new();
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut ty_generics,
rgen,
is_return,
cache,
);
res.push(get_index_type(arg, ty_generics, rgen));
} else if let Type::Array(ref ty, _) = *arg {
let mut ty_generics = Vec::new();
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut ty_generics,
rgen,
is_return,
cache,
);
res.push(get_index_type(arg, ty_generics, rgen));
} else if let Type::Tuple(ref tys) = *arg {
let mut ty_generics = Vec::new();
for ty in tys {
simplify_fn_type( simplify_fn_type(
self_, self_,
generics, generics,
@ -982,15 +960,14 @@ fn simplify_fn_type<'tcx, 'a>(
is_return, is_return,
cache, cache,
); );
res.push(get_index_type(arg, ty_generics, rgen));
} }
res.push(get_index_type(arg, ty_generics, rgen)); Type::Array(ref ty, _) => {
} else if let Type::BareFunction(ref bf) = *arg { let mut ty_generics = Vec::new();
let mut ty_generics = Vec::new();
for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
simplify_fn_type( simplify_fn_type(
self_, self_,
generics, generics,
ty, &ty,
tcx, tcx,
recurse + 1, recurse + 1,
&mut ty_generics, &mut ty_generics,
@ -998,62 +975,11 @@ fn simplify_fn_type<'tcx, 'a>(
is_return, is_return,
cache, cache,
); );
res.push(get_index_type(arg, ty_generics, rgen));
} }
// The search index, for simplicity's sake, represents fn pointers and closures Type::Tuple(ref tys) => {
// the same way: as a tuple for the parameters, and an associated type for the let mut ty_generics = Vec::new();
// return type. for ty in tys {
let mut ty_output = Vec::new();
simplify_fn_type(
self_,
generics,
&bf.decl.output,
tcx,
recurse + 1,
&mut ty_output,
rgen,
is_return,
cache,
);
let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
res.push(RenderType {
id: get_index_type_id(&arg, rgen),
bindings: Some(ty_bindings),
generics: Some(ty_generics),
});
} else if let Type::BorrowedRef { lifetime: _, mutability, ref type_ } = *arg {
let mut ty_generics = Vec::new();
if mutability.is_mut() {
ty_generics.push(RenderType {
id: Some(RenderTypeId::Mut),
generics: None,
bindings: None,
});
}
simplify_fn_type(
self_,
generics,
&type_,
tcx,
recurse + 1,
&mut ty_generics,
rgen,
is_return,
cache,
);
res.push(get_index_type(arg, ty_generics, rgen));
} else {
// This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
// looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
//
// So in here, we can add it directly and look for its own type parameters (so for `Option`,
// we will look for them but not for `T`).
let mut ty_generics = Vec::new();
let mut ty_constraints = Vec::new();
if let Some(arg_generics) = arg.generic_args() {
for ty in arg_generics.into_iter().filter_map(|param| match param {
clean::GenericArg::Type(ty) => Some(ty),
_ => None,
}) {
simplify_fn_type( simplify_fn_type(
self_, self_,
generics, generics,
@ -1066,94 +992,181 @@ fn simplify_fn_type<'tcx, 'a>(
cache, cache,
); );
} }
for constraint in arg_generics.constraints() { res.push(get_index_type(arg, ty_generics, rgen));
simplify_fn_constraint( }
Type::BareFunction(ref bf) => {
let mut ty_generics = Vec::new();
for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
simplify_fn_type(
self_, self_,
generics, generics,
&constraint, ty,
tcx, tcx,
recurse + 1, recurse + 1,
&mut ty_constraints, &mut ty_generics,
rgen, rgen,
is_return, is_return,
cache, cache,
); );
} }
// The search index, for simplicity's sake, represents fn pointers and closures
// the same way: as a tuple for the parameters, and an associated type for the
// return type.
let mut ty_output = Vec::new();
simplify_fn_type(
self_,
generics,
&bf.decl.output,
tcx,
recurse + 1,
&mut ty_output,
rgen,
is_return,
cache,
);
let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
res.push(RenderType {
id: get_index_type_id(&arg, rgen),
bindings: Some(ty_bindings),
generics: Some(ty_generics),
});
} }
// Every trait associated type on self gets assigned to a type parameter index Type::BorrowedRef { lifetime: _, mutability, ref type_ } => {
// this same one is used later for any appearances of these types let mut ty_generics = Vec::new();
// if mutability.is_mut() {
// for example, Iterator::next is: ty_generics.push(RenderType {
// id: Some(RenderTypeId::Mut),
// trait Iterator { generics: None,
// fn next(&mut self) -> Option<Self::Item> bindings: None,
// } });
// }
// Self is technically just Iterator, but we want to pretend it's more like this: simplify_fn_type(
// self_,
// fn next<T>(self: Iterator<Item=T>) -> Option<T> generics,
if is_self &type_,
&& let Type::Path { path } = arg tcx,
&& let def_id = path.def_id() recurse + 1,
&& let Some(trait_) = cache.traits.get(&def_id) &mut ty_generics,
&& trait_.items.iter().any(|at| at.is_ty_associated_type()) rgen,
{ is_return,
for assoc_ty in &trait_.items { cache,
if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind );
&& let Some(name) = assoc_ty.name res.push(get_index_type(arg, ty_generics, rgen));
{ }
let idx = -isize::try_from(rgen.len() + 1).unwrap(); _ => {
let (idx, stored_bounds) = rgen // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
.entry(SimplifiedParam::AssociatedType(def_id, name)) // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
.or_insert_with(|| (idx, Vec::new())); //
let idx = *idx; // So in here, we can add it directly and look for its own type parameters (so for `Option`,
if stored_bounds.is_empty() { // we will look for them but not for `T`).
// Can't just pass stored_bounds to simplify_fn_type, let mut ty_generics = Vec::new();
// because it also accepts rgen as a parameter. let mut ty_constraints = Vec::new();
// Instead, have it fill in this local, then copy it into the map afterward. if let Some(arg_generics) = arg.generic_args() {
let mut type_bounds = Vec::new(); for ty in arg_generics.into_iter().filter_map(|param| match param {
for bound in bounds { clean::GenericArg::Type(ty) => Some(ty),
if let Some(path) = bound.get_trait_path() { _ => None,
let ty = Type::Path { path }; }) {
simplify_fn_type( simplify_fn_type(
self_, self_,
generics, generics,
&ty, &ty,
tcx, tcx,
recurse + 1, recurse + 1,
&mut type_bounds, &mut ty_generics,
rgen, rgen,
is_return, is_return,
cache, cache,
); );
} }
} for constraint in arg_generics.constraints() {
let stored_bounds = &mut rgen simplify_fn_constraint(
.get_mut(&SimplifiedParam::AssociatedType(def_id, name)) self_,
.unwrap() generics,
.1; &constraint,
if stored_bounds.is_empty() { tcx,
*stored_bounds = type_bounds; recurse + 1,
} &mut ty_constraints,
} rgen,
ty_constraints.push(( is_return,
RenderTypeId::AssociatedType(name), cache,
vec![RenderType { );
id: Some(RenderTypeId::Index(idx)),
generics: None,
bindings: None,
}],
))
} }
} }
} // Every trait associated type on self gets assigned to a type parameter index
let id = get_index_type_id(&arg, rgen); // this same one is used later for any appearances of these types
if id.is_some() || !ty_generics.is_empty() { //
res.push(RenderType { // for example, Iterator::next is:
id, //
bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) }, // trait Iterator {
generics: if ty_generics.is_empty() { None } else { Some(ty_generics) }, // fn next(&mut self) -> Option<Self::Item>
}); // }
//
// Self is technically just Iterator, but we want to pretend it's more like this:
//
// fn next<T>(self: Iterator<Item=T>) -> Option<T>
if is_self
&& let Type::Path { path } = arg
&& let def_id = path.def_id()
&& let Some(trait_) = cache.traits.get(&def_id)
&& trait_.items.iter().any(|at| at.is_ty_associated_type())
{
for assoc_ty in &trait_.items {
if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind
&& let Some(name) = assoc_ty.name
{
let idx = -isize::try_from(rgen.len() + 1).unwrap();
let (idx, stored_bounds) = rgen
.entry(SimplifiedParam::AssociatedType(def_id, name))
.or_insert_with(|| (idx, Vec::new()));
let idx = *idx;
if stored_bounds.is_empty() {
// Can't just pass stored_bounds to simplify_fn_type,
// because it also accepts rgen as a parameter.
// Instead, have it fill in this local, then copy it into the map afterward.
let mut type_bounds = Vec::new();
for bound in bounds {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
simplify_fn_type(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut type_bounds,
rgen,
is_return,
cache,
);
}
}
let stored_bounds = &mut rgen
.get_mut(&SimplifiedParam::AssociatedType(def_id, name))
.unwrap()
.1;
if stored_bounds.is_empty() {
*stored_bounds = type_bounds;
}
}
ty_constraints.push((
RenderTypeId::AssociatedType(name),
vec![RenderType {
id: Some(RenderTypeId::Index(idx)),
generics: None,
bindings: None,
}],
))
}
}
}
let id = get_index_type_id(&arg, rgen);
if id.is_some() || !ty_generics.is_empty() {
res.push(RenderType {
id,
bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
});
}
} }
} }
} }

View File

@ -578,7 +578,7 @@ impl FromWithTcx<clean::Type> for Type {
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
use clean::Type::{ use clean::Type::{
Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath, Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
RawPointer, Slice, Tuple, RawPointer, SelfTy, Slice, Tuple,
}; };
match ty { match ty {
@ -588,6 +588,8 @@ impl FromWithTcx<clean::Type> for Type {
traits: bounds.into_tcx(tcx), traits: bounds.into_tcx(tcx),
}), }),
Generic(s) => Type::Generic(s.to_string()), Generic(s) => Type::Generic(s.to_string()),
// FIXME: add dedicated variant to json Type?
SelfTy => Type::Generic("Self".to_owned()),
Primitive(p) => Type::Primitive(p.as_sym().to_string()), Primitive(p) => Type::Primitive(p.as_sym().to_string()),
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))), BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
Tuple(t) => Type::Tuple(t.into_tcx(tcx)), Tuple(t) => Type::Tuple(t.into_tcx(tcx)),

View File

@ -1,6 +1,5 @@
use std::path::PathBuf; use std::path::PathBuf;
use super::cygpath::get_windows_path;
use crate::artifact_names::{dynamic_lib_name, static_lib_name}; use crate::artifact_names::{dynamic_lib_name, static_lib_name};
use crate::external_deps::cc::{cc, cxx}; use crate::external_deps::cc::{cc, cxx};
use crate::external_deps::llvm::llvm_ar; use crate::external_deps::llvm::llvm_ar;
@ -44,8 +43,7 @@ pub fn build_native_dynamic_lib(lib_name: &str) -> PathBuf {
}; };
let obj_file = if is_msvc() { format!("{lib_name}.obj") } else { format!("{lib_name}.o") }; let obj_file = if is_msvc() { format!("{lib_name}.obj") } else { format!("{lib_name}.o") };
if is_msvc() { if is_msvc() {
let mut out_arg = "-out:".to_owned(); let out_arg = format!("-out:{lib_path}");
out_arg.push_str(&get_windows_path(&lib_path));
cc().input(&obj_file).args(&["-link", "-dll", &out_arg]).run(); cc().input(&obj_file).args(&["-link", "-dll", &out_arg]).run();
} else if is_darwin() { } else if is_darwin() {
cc().out_exe(&lib_path).input(&obj_file).args(&["-dynamiclib", "-Wl,-dylib"]).run(); cc().out_exe(&lib_path).input(&obj_file).args(&["-dynamiclib", "-Wl,-dylib"]).run();

View File

@ -1,7 +1,5 @@
use std::path::Path; use std::path::Path;
// FIXME(jieyouxu): can we get rid of the `cygpath` external dependency?
use super::cygpath::get_windows_path;
use crate::command::Command; use crate::command::Command;
use crate::{env_var, is_msvc, is_windows, uname}; use crate::{env_var, is_msvc, is_windows, uname};
@ -97,12 +95,12 @@ impl Cc {
if is_msvc() { if is_msvc() {
path.set_extension("exe"); path.set_extension("exe");
let fe_path = get_windows_path(&path); let fe_path = path.clone();
path.set_extension(""); path.set_extension("");
path.set_extension("obj"); path.set_extension("obj");
let fo_path = get_windows_path(path); let fo_path = path;
self.cmd.arg(format!("-Fe:{fe_path}")); self.cmd.arg(format!("-Fe:{}", fe_path.to_str().unwrap()));
self.cmd.arg(format!("-Fo:{fo_path}")); self.cmd.arg(format!("-Fo:{}", fo_path.to_str().unwrap()));
} else { } else {
self.cmd.arg("-o"); self.cmd.arg("-o");
self.cmd.arg(name); self.cmd.arg(name);

View File

@ -1,35 +0,0 @@
use std::panic;
use std::path::Path;
use crate::command::Command;
use crate::util::handle_failed_output;
/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
/// available on the platform!
///
/// # FIXME
///
/// FIXME(jieyouxu): we should consider not depending on `cygpath`.
///
/// > The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style
/// > pathnames and vice versa.
/// >
/// > [irrelevant entries omitted...]
/// >
/// > `-w, --windows print Windows form of NAMEs (C:\WINNT)`
/// >
/// > -- *from [cygpath documentation](https://cygwin.com/cygwin-ug-net/cygpath.html)*.
#[track_caller]
#[must_use]
pub fn get_windows_path<P: AsRef<Path>>(path: P) -> String {
let caller = panic::Location::caller();
let mut cygpath = Command::new("cygpath");
cygpath.arg("-w");
cygpath.arg(path.as_ref());
let output = cygpath.run();
if !output.status().success() {
handle_failed_output(&cygpath, output, caller.line());
}
// cygpath -w can attach a newline
output.stdout_utf8().trim().to_string()
}

View File

@ -9,6 +9,3 @@ pub mod llvm;
pub mod python; pub mod python;
pub mod rustc; pub mod rustc;
pub mod rustdoc; pub mod rustdoc;
// Library-internal external dependency.
mod cygpath;

14
tests/crashes/128094.rs Normal file
View File

@ -0,0 +1,14 @@
//@ known-bug: rust-lang/rust#128094
//@ compile-flags: -Zmir-opt-level=5 --edition=2018
pub enum Request {
TestSome(T),
}
pub async fn handle_event(event: Request) {
async move {
static instance: Request = Request { bar: 17 };
&instance
}
.await;
}

13
tests/crashes/128176.rs Normal file
View File

@ -0,0 +1,13 @@
//@ known-bug: rust-lang/rust#128176
#![feature(generic_const_exprs)]
#![feature(object_safe_for_dispatch)]
trait X {
type Y<const N: i16>;
}
const _: () = {
fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
};
fn main() {}

7
tests/crashes/128190.rs Normal file
View File

@ -0,0 +1,7 @@
//@ known-bug: rust-lang/rust#128190
fn a(&self) {
15
}
reuse a as b { struct S; }

5
tests/crashes/128327.rs Normal file
View File

@ -0,0 +1,5 @@
//@ known-bug: rust-lang/rust#128327
use std::ops::Deref;
struct Apple((Apple, <&'static [f64] as Deref>::Target(Banana ? Citron)));
fn main(){}

13
tests/crashes/128346.rs Normal file
View File

@ -0,0 +1,13 @@
//@ known-bug: rust-lang/rust#128346
macro_rules! one_rep {
( $($a:ident)* ) => {
A(
const ${concat($a, Z)}: i32 = 3;
)*
};
}
fn main() {
one_rep!(A B C);
}

16
tests/crashes/128621-2.rs Normal file
View File

@ -0,0 +1,16 @@
//@ known-bug: rust-lang/rust#128621
#![feature(ptr_metadata)]
use std::{ops::FnMut, ptr::Pointee};
pub type EmplacerFn<'a, T> = dyn for<'b> FnMut(<T as Pointee>::Metadata) + 'a;
pub struct Emplacer<'a, T>(EmplacerFn<'a, T>);
impl<'a, T> Emplacer<'a, T> {
pub unsafe fn from_fn<'b>(emplacer_fn: &'b mut EmplacerFn<'a, T>) -> &'b mut Self {
unsafe { &mut *((emplacer_fn as *mut EmplacerFn<'a, T>) as *mut Self) }
}
}
pub fn main() {}

19
tests/crashes/128621.rs Normal file
View File

@ -0,0 +1,19 @@
//@ known-bug: rust-lang/rust#128621
trait Trait {
type Associated;
}
impl Trait for i32 {
type Associated = i64;
}
trait Generic<T> {}
type TraitObject = dyn Generic<<i32 as Trait>::Associated>;
struct Wrap(TraitObject);
fn cast(x: *mut TraitObject) {
x as *mut Wrap;
}

View File

@ -4,12 +4,8 @@
// are exported, and that generics are only shown if explicitely requested. // are exported, and that generics are only shown if explicitely requested.
// See https://github.com/rust-lang/rust/issues/37530 // See https://github.com/rust-lang/rust/issues/37530
//@ ignore-windows-msvc use run_make_support::object::read::Object;
use run_make_support::{bin_name, dynamic_lib_name, is_msvc, object, regex, rfs, rustc};
//FIXME(Oneirical): This currently uses llvm-nm for symbol detection. However,
// the custom Rust-based solution of #128314 may prove to be an interesting alternative.
use run_make_support::{bin_name, dynamic_lib_name, is_darwin, is_windows, llvm_nm, regex, rustc};
fn main() { fn main() {
let cdylib_name = dynamic_lib_name("a_cdylib"); let cdylib_name = dynamic_lib_name("a_cdylib");
@ -64,16 +60,15 @@ fn main() {
); );
// FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032 // FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
// if is_windows() { if is_msvc() {
// // Check that an executable does not export any dynamic symbols // Check that an executable does not export any dynamic symbols
// symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib") symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false);
//, false); symbols_check(
// symbols_check( &exe_name,
// &exe_name, SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
// SymbolCheckType::StrSymbol("public_rust_function_from_exe"), false,
// false, );
// ); }
// }
// Check the combined case, where we generate a cdylib and an rlib in the same // Check the combined case, where we generate a cdylib and an rlib in the same
// compilation session: // compilation session:
@ -131,44 +126,37 @@ fn main() {
); );
// FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032 // FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
// if is_windows() { if is_msvc() {
// // Check that an executable does not export any dynamic symbols // Check that an executable does not export any dynamic symbols
// symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib") symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false);
//, false); symbols_check(
// symbols_check( &exe_name,
// &exe_name, SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
// SymbolCheckType::StrSymbol("public_rust_function_from_exe"), false,
// false, );
// ); }
// }
} }
#[track_caller] #[track_caller]
fn symbols_check(path: &str, symbol_check_type: SymbolCheckType, exists_once: bool) { fn symbols_check(path: &str, symbol_check_type: SymbolCheckType, exists_once: bool) {
let mut nm = llvm_nm(); let binary_data = rfs::read(path);
if is_windows() { let file = object::File::parse(&*binary_data).unwrap();
nm.arg("--extern-only"); let mut found: u64 = 0;
} else if is_darwin() { for export in file.exports().unwrap() {
nm.arg("--extern-only").arg("--defined-only"); let name = std::str::from_utf8(export.name()).unwrap();
} else { if has_symbol(name, symbol_check_type) {
nm.arg("--dynamic"); found += 1;
}
} }
let out = nm.input(path).run().stdout_utf8(); assert_eq!(found, exists_once as u64);
assert_eq!(
out.lines()
.filter(|&line| !line.contains("__imp_") && has_symbol(line, symbol_check_type))
.count()
== 1,
exists_once
);
} }
fn has_symbol(line: &str, symbol_check_type: SymbolCheckType) -> bool { fn has_symbol(name: &str, symbol_check_type: SymbolCheckType) -> bool {
if let SymbolCheckType::StrSymbol(expected) = symbol_check_type { if let SymbolCheckType::StrSymbol(expected) = symbol_check_type {
line.contains(expected) name.contains(expected)
} else { } else {
let regex = regex::Regex::new(r#"_ZN.*h.*E\|_R[a-zA-Z0-9_]+"#).unwrap(); let regex = regex::Regex::new(r#"_ZN.*h.*E\|_R[a-zA-Z0-9_]+"#).unwrap();
regex.is_match(line) regex.is_match(name)
} }
} }

View File

@ -0,0 +1,22 @@
// exact-check
const EXPECTED = [
{
'query': 'A -> A',
'others': [
{ 'path': 'self_is_not_generic::Thing', 'name': 'from' }
],
},
{
'query': 'A -> B',
'others': [
{ 'path': 'self_is_not_generic::Thing', 'name': 'try_from' }
],
},
{
'query': 'Combine -> Combine',
'others': [
{ 'path': 'self_is_not_generic::Combine', 'name': 'combine' }
],
}
];

View File

@ -0,0 +1,11 @@
pub trait Combine {
fn combine(&self, other: &Self) -> Self;
}
pub struct Thing;
impl Combine for Thing {
fn combine(&self, other: &Self) -> Self {
Self
}
}