Auto merge of #129143 - workingjubilee:rollup-h0hzumu, r=workingjubilee
Rollup of 9 pull requests Successful merges: - #128064 (Improve docs for Waker::noop and LocalWaker::noop) - #128922 (rust-analyzer: use in-tree `pattern_analysis` crate) - #128965 (Remove `print::Pat` from the printing of `WitnessPat`) - #129018 (Migrate `rlib-format-packed-bundled-libs` and `native-link-modifier-bundle` `run-make` tests to rmake) - #129037 (Port `run-make/libtest-json` and `run-make/libtest-junit` to rmake) - #129078 (`ParamEnvAnd::fully_perform`: we have an `ocx`, use it) - #129110 (Add a comment explaining the return type of `Ty::kind`.) - #129111 (Port the `sysroot-crates-are-unstable` Python script to rmake) - #129135 (crashes: more tests) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
69e36d65f9
@ -970,6 +970,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
|
||||
|
||||
/// Type utilities
|
||||
impl<'tcx> Ty<'tcx> {
|
||||
// It would be nicer if this returned the value instead of a reference,
|
||||
// like how `Predicate::kind` and `Region::kind` do. (It would result in
|
||||
// many fewer subsequent dereferences.) But that gives a small but
|
||||
// noticeable performance hit. See #126069 for details.
|
||||
#[inline(always)]
|
||||
pub fn kind(self) -> &'tcx TyKind<'tcx> {
|
||||
self.0.0
|
||||
|
@ -774,17 +774,16 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert to a [`print::Pat`] for diagnostic purposes.
|
||||
fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> print::Pat<'tcx> {
|
||||
use print::{Pat, PatKind};
|
||||
/// Prints an [`IntRange`] to a string for diagnostic purposes.
|
||||
fn print_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> String {
|
||||
use MaybeInfiniteInt::*;
|
||||
let cx = self;
|
||||
let kind = if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) {
|
||||
PatKind::Wild
|
||||
if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) {
|
||||
"_".to_string()
|
||||
} else if range.is_singleton() {
|
||||
let lo = cx.hoist_pat_range_bdy(range.lo, ty);
|
||||
let value = lo.as_finite().unwrap();
|
||||
PatKind::Constant { value }
|
||||
value.to_string()
|
||||
} else {
|
||||
// We convert to an inclusive range for diagnostics.
|
||||
let mut end = rustc_hir::RangeEnd::Included;
|
||||
@ -807,32 +806,24 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
||||
range.hi
|
||||
};
|
||||
let hi = cx.hoist_pat_range_bdy(hi, ty);
|
||||
PatKind::Range(Box::new(PatRange { lo, hi, end, ty: ty.inner() }))
|
||||
};
|
||||
|
||||
Pat { ty: ty.inner(), kind }
|
||||
PatRange { lo, hi, end, ty: ty.inner() }.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints a [`WitnessPat`] to an owned string, for diagnostic purposes.
|
||||
///
|
||||
/// This panics for patterns that don't appear in diagnostics, like float ranges.
|
||||
pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String {
|
||||
// This works by converting the witness pattern to a `print::Pat`
|
||||
// and then printing that, but callers don't need to know that.
|
||||
self.hoist_witness_pat(pat).to_string()
|
||||
}
|
||||
|
||||
/// Convert to a [`print::Pat`] for diagnostic purposes. This panics for patterns that don't
|
||||
/// appear in diagnostics, like float ranges.
|
||||
fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> print::Pat<'tcx> {
|
||||
use print::{FieldPat, Pat, PatKind};
|
||||
let cx = self;
|
||||
let hoist = |p| Box::new(cx.hoist_witness_pat(p));
|
||||
let kind = match pat.ctor() {
|
||||
Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) },
|
||||
IntRange(range) => return self.hoist_pat_range(range, *pat.ty()),
|
||||
let print = |p| cx.print_witness_pat(p);
|
||||
match pat.ctor() {
|
||||
Bool(b) => b.to_string(),
|
||||
Str(s) => s.to_string(),
|
||||
IntRange(range) => return self.print_pat_range(range, *pat.ty()),
|
||||
Struct if pat.ty().is_box() => {
|
||||
// Outside of the `alloc` crate, the only way to create a struct pattern
|
||||
// of type `Box` is to use a `box` pattern via #[feature(box_patterns)].
|
||||
PatKind::Box { subpattern: hoist(&pat.fields[0]) }
|
||||
format!("box {}", print(&pat.fields[0]))
|
||||
}
|
||||
Struct | Variant(_) | UnionField => {
|
||||
let enum_info = match *pat.ty().kind() {
|
||||
@ -847,12 +838,29 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
||||
let subpatterns = pat
|
||||
.iter_fields()
|
||||
.enumerate()
|
||||
.map(|(i, pat)| FieldPat { field: FieldIdx::new(i), pattern: hoist(pat) })
|
||||
.map(|(i, pat)| print::FieldPat {
|
||||
field: FieldIdx::new(i),
|
||||
pattern: print(pat),
|
||||
is_wildcard: would_print_as_wildcard(cx.tcx, pat),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
PatKind::StructLike { enum_info, subpatterns }
|
||||
let mut s = String::new();
|
||||
print::write_struct_like(
|
||||
&mut s,
|
||||
self.tcx,
|
||||
pat.ty().inner(),
|
||||
&enum_info,
|
||||
&subpatterns,
|
||||
)
|
||||
.unwrap();
|
||||
s
|
||||
}
|
||||
Ref => {
|
||||
let mut s = String::new();
|
||||
print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap();
|
||||
s
|
||||
}
|
||||
Ref => PatKind::Deref { subpattern: hoist(&pat.fields[0]) },
|
||||
Slice(slice) => {
|
||||
let (prefix_len, has_dot_dot) = match slice.kind {
|
||||
SliceKind::FixedLen(len) => (len, false),
|
||||
@ -879,14 +887,15 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let prefix = prefix.iter().map(hoist).collect();
|
||||
let suffix = suffix.iter().map(hoist).collect();
|
||||
let prefix = prefix.iter().map(print).collect::<Vec<_>>();
|
||||
let suffix = suffix.iter().map(print).collect::<Vec<_>>();
|
||||
|
||||
PatKind::Slice { prefix, has_dot_dot, suffix }
|
||||
let mut s = String::new();
|
||||
print::write_slice_like(&mut s, &prefix, has_dot_dot, &suffix).unwrap();
|
||||
s
|
||||
}
|
||||
&Str(value) => PatKind::Constant { value },
|
||||
Never if self.tcx.features().never_patterns => PatKind::Never,
|
||||
Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild,
|
||||
Never if self.tcx.features().never_patterns => "!".to_string(),
|
||||
Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => "_".to_string(),
|
||||
Missing { .. } => bug!(
|
||||
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
|
||||
`Missing` should have been processed in `apply_constructors`"
|
||||
@ -894,9 +903,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
||||
F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Opaque(..) | Or => {
|
||||
bug!("can't convert to pattern: {:?}", pat)
|
||||
}
|
||||
};
|
||||
|
||||
Pat { ty: pat.ty().inner(), kind }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -972,7 +979,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
|
||||
overlaps_on: IntRange,
|
||||
overlaps_with: &[&crate::pat::DeconstructedPat<Self>],
|
||||
) {
|
||||
let overlap_as_pat = self.hoist_pat_range(&overlaps_on, *pat.ty());
|
||||
let overlap_as_pat = self.print_pat_range(&overlaps_on, *pat.ty());
|
||||
let overlaps: Vec<_> = overlaps_with
|
||||
.iter()
|
||||
.map(|pat| pat.data().span)
|
||||
@ -1012,7 +1019,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
|
||||
suggested_range.end = rustc_hir::RangeEnd::Included;
|
||||
suggested_range.to_string()
|
||||
};
|
||||
let gap_as_pat = self.hoist_pat_range(&gap, *pat.ty());
|
||||
let gap_as_pat = self.print_pat_range(&gap, *pat.ty());
|
||||
if gapped_with.is_empty() {
|
||||
// If `gapped_with` is empty, `gap == T::MAX`.
|
||||
self.tcx.emit_node_span_lint(
|
||||
|
@ -11,75 +11,16 @@
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use rustc_middle::thir::PatRange;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, mir};
|
||||
use rustc_span::sym;
|
||||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct FieldPat<'tcx> {
|
||||
pub(crate) struct FieldPat {
|
||||
pub(crate) field: FieldIdx,
|
||||
pub(crate) pattern: Box<Pat<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Pat<'tcx> {
|
||||
pub(crate) ty: Ty<'tcx>,
|
||||
pub(crate) kind: PatKind<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum PatKind<'tcx> {
|
||||
Wild,
|
||||
|
||||
StructLike {
|
||||
enum_info: EnumInfo<'tcx>,
|
||||
subpatterns: Vec<FieldPat<'tcx>>,
|
||||
},
|
||||
|
||||
Box {
|
||||
subpattern: Box<Pat<'tcx>>,
|
||||
},
|
||||
|
||||
Deref {
|
||||
subpattern: Box<Pat<'tcx>>,
|
||||
},
|
||||
|
||||
Constant {
|
||||
value: mir::Const<'tcx>,
|
||||
},
|
||||
|
||||
Range(Box<PatRange<'tcx>>),
|
||||
|
||||
Slice {
|
||||
prefix: Box<[Box<Pat<'tcx>>]>,
|
||||
/// True if this slice-like pattern should include a `..` between the
|
||||
/// prefix and suffix.
|
||||
has_dot_dot: bool,
|
||||
suffix: Box<[Box<Pat<'tcx>>]>,
|
||||
},
|
||||
|
||||
Never,
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for Pat<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.kind {
|
||||
PatKind::Wild => write!(f, "_"),
|
||||
PatKind::Never => write!(f, "!"),
|
||||
PatKind::Box { ref subpattern } => write!(f, "box {subpattern}"),
|
||||
PatKind::StructLike { ref enum_info, ref subpatterns } => {
|
||||
ty::tls::with(|tcx| write_struct_like(f, tcx, self.ty, enum_info, subpatterns))
|
||||
}
|
||||
PatKind::Deref { ref subpattern } => write_ref_like(f, self.ty, subpattern),
|
||||
PatKind::Constant { value } => write!(f, "{value}"),
|
||||
PatKind::Range(ref range) => write!(f, "{range}"),
|
||||
PatKind::Slice { ref prefix, has_dot_dot, ref suffix } => {
|
||||
write_slice_like(f, prefix, has_dot_dot, suffix)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) pattern: String,
|
||||
pub(crate) is_wildcard: bool,
|
||||
}
|
||||
|
||||
/// Returns a closure that will return `""` when called the first time,
|
||||
@ -103,12 +44,12 @@ pub(crate) enum EnumInfo<'tcx> {
|
||||
NotEnum,
|
||||
}
|
||||
|
||||
fn write_struct_like<'tcx>(
|
||||
pub(crate) fn write_struct_like<'tcx>(
|
||||
f: &mut impl fmt::Write,
|
||||
tcx: TyCtxt<'_>,
|
||||
ty: Ty<'tcx>,
|
||||
enum_info: &EnumInfo<'tcx>,
|
||||
subpatterns: &[FieldPat<'tcx>],
|
||||
subpatterns: &[FieldPat],
|
||||
) -> fmt::Result {
|
||||
let variant_and_name = match *enum_info {
|
||||
EnumInfo::Enum { adt_def, variant_index } => {
|
||||
@ -139,12 +80,12 @@ fn write_struct_like<'tcx>(
|
||||
write!(f, " {{ ")?;
|
||||
|
||||
let mut printed = 0;
|
||||
for p in subpatterns {
|
||||
if let PatKind::Wild = p.pattern.kind {
|
||||
for &FieldPat { field, ref pattern, is_wildcard } in subpatterns {
|
||||
if is_wildcard {
|
||||
continue;
|
||||
}
|
||||
let name = variant.fields[p.field].name;
|
||||
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
|
||||
let field_name = variant.fields[field].name;
|
||||
write!(f, "{}{field_name}: {pattern}", start_or_comma())?;
|
||||
printed += 1;
|
||||
}
|
||||
|
||||
@ -184,10 +125,10 @@ fn write_struct_like<'tcx>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_ref_like<'tcx>(
|
||||
pub(crate) fn write_ref_like<'tcx>(
|
||||
f: &mut impl fmt::Write,
|
||||
ty: Ty<'tcx>,
|
||||
subpattern: &Pat<'tcx>,
|
||||
subpattern: &str,
|
||||
) -> fmt::Result {
|
||||
match ty.kind() {
|
||||
ty::Ref(_, _, mutbl) => {
|
||||
@ -198,11 +139,11 @@ fn write_ref_like<'tcx>(
|
||||
write!(f, "{subpattern}")
|
||||
}
|
||||
|
||||
fn write_slice_like<'tcx>(
|
||||
pub(crate) fn write_slice_like(
|
||||
f: &mut impl fmt::Write,
|
||||
prefix: &[Box<Pat<'tcx>>],
|
||||
prefix: &[String],
|
||||
has_dot_dot: bool,
|
||||
suffix: &[Box<Pat<'tcx>>],
|
||||
suffix: &[String],
|
||||
) -> fmt::Result {
|
||||
let mut start_or_comma = start_or_comma();
|
||||
write!(f, "[")?;
|
||||
|
@ -168,44 +168,12 @@ where
|
||||
// collecting region constraints via `region_constraints`.
|
||||
let (mut output, _) = scrape_region_constraints(
|
||||
infcx,
|
||||
|_ocx| {
|
||||
let (output, ei, mut obligations, _) =
|
||||
|ocx| {
|
||||
let (output, ei, obligations, _) =
|
||||
Q::fully_perform_into(self, infcx, &mut region_constraints, span)?;
|
||||
error_info = ei;
|
||||
|
||||
// Typically, instantiating NLL query results does not
|
||||
// create obligations. However, in some cases there
|
||||
// are unresolved type variables, and unify them *can*
|
||||
// create obligations. In that case, we have to go
|
||||
// fulfill them. We do this via a (recursive) query.
|
||||
while !obligations.is_empty() {
|
||||
trace!("{:#?}", obligations);
|
||||
let mut progress = false;
|
||||
for obligation in std::mem::take(&mut obligations) {
|
||||
let obligation = infcx.resolve_vars_if_possible(obligation);
|
||||
match ProvePredicate::fully_perform_into(
|
||||
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
|
||||
infcx,
|
||||
&mut region_constraints,
|
||||
span,
|
||||
) {
|
||||
Ok(((), _, new, certainty)) => {
|
||||
obligations.extend(new);
|
||||
progress = true;
|
||||
if let Certainty::Ambiguous = certainty {
|
||||
obligations.push(obligation);
|
||||
}
|
||||
}
|
||||
Err(_) => obligations.push(obligation),
|
||||
}
|
||||
}
|
||||
if !progress {
|
||||
infcx.dcx().span_bug(
|
||||
span,
|
||||
format!("ambiguity processing {obligations:?} from {self:?}"),
|
||||
);
|
||||
}
|
||||
}
|
||||
ocx.register_obligations(obligations);
|
||||
Ok(output)
|
||||
},
|
||||
"fully_perform",
|
||||
|
@ -530,10 +530,18 @@ impl Waker {
|
||||
|
||||
/// Returns a reference to a `Waker` that does nothing when used.
|
||||
///
|
||||
// Note! Much of the documentation for this method is duplicated
|
||||
// in the docs for `LocalWaker::noop`.
|
||||
// If you edit it, consider editing the other copy too.
|
||||
//
|
||||
/// This is mostly useful for writing tests that need a [`Context`] to poll
|
||||
/// some futures, but are not expecting those futures to wake the waker or
|
||||
/// do not need to do anything specific if it happens.
|
||||
///
|
||||
/// More generally, using `Waker::noop()` to poll a future
|
||||
/// means discarding the notification of when the future should be polled again.
|
||||
/// So it should only be used when such a notification will not be needed to make progress.
|
||||
///
|
||||
/// If an owned `Waker` is needed, `clone()` this one.
|
||||
///
|
||||
/// # Examples
|
||||
@ -783,12 +791,22 @@ impl LocalWaker {
|
||||
Self { waker }
|
||||
}
|
||||
|
||||
/// Creates a new `LocalWaker` that does nothing when `wake` is called.
|
||||
/// Returns a reference to a `LocalWaker` that does nothing when used.
|
||||
///
|
||||
// Note! Much of the documentation for this method is duplicated
|
||||
// in the docs for `Waker::noop`.
|
||||
// If you edit it, consider editing the other copy too.
|
||||
//
|
||||
/// This is mostly useful for writing tests that need a [`Context`] to poll
|
||||
/// some futures, but are not expecting those futures to wake the waker or
|
||||
/// do not need to do anything specific if it happens.
|
||||
///
|
||||
/// More generally, using `LocalWaker::noop()` to poll a future
|
||||
/// means discarding the notification of when the future should be polled again,
|
||||
/// So it should only be used when such a notification will not be needed to make progress.
|
||||
///
|
||||
/// If an owned `LocalWaker` is needed, `clone()` this one.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
@ -297,6 +297,12 @@ impl LlvmAr {
|
||||
self
|
||||
}
|
||||
|
||||
/// Print the table of contents.
|
||||
pub fn table_of_contents(&mut self) -> &mut Self {
|
||||
self.cmd.arg("t");
|
||||
self
|
||||
}
|
||||
|
||||
/// Provide an output, then an input file. Bundled in one function, as llvm-ar has
|
||||
/// no "--output"-style flag.
|
||||
pub fn output_input(&mut self, out: impl AsRef<Path>, input: impl AsRef<Path>) -> &mut Self {
|
||||
|
@ -15,8 +15,10 @@ extern crate rustc_abi;
|
||||
#[cfg(not(feature = "in-rust-tree"))]
|
||||
extern crate ra_ap_rustc_abi as rustc_abi;
|
||||
|
||||
// Use the crates.io version unconditionally until the API settles enough that we can switch to
|
||||
// using the in-tree one.
|
||||
#[cfg(feature = "in-rust-tree")]
|
||||
extern crate rustc_pattern_analysis;
|
||||
|
||||
#[cfg(not(feature = "in-rust-tree"))]
|
||||
extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis;
|
||||
|
||||
mod builder;
|
||||
|
@ -6,13 +6,9 @@ run-make/incr-add-rust-src-component/Makefile
|
||||
run-make/issue-84395-lto-embed-bitcode/Makefile
|
||||
run-make/jobserver-error/Makefile
|
||||
run-make/libs-through-symlinks/Makefile
|
||||
run-make/libtest-json/Makefile
|
||||
run-make/libtest-junit/Makefile
|
||||
run-make/libtest-thread-limit/Makefile
|
||||
run-make/macos-deployment-target/Makefile
|
||||
run-make/native-link-modifier-bundle/Makefile
|
||||
run-make/reproducible-build/Makefile
|
||||
run-make/rlib-format-packed-bundled-libs/Makefile
|
||||
run-make/split-debuginfo/Makefile
|
||||
run-make/symbol-mangling-hashed/Makefile
|
||||
run-make/translation/Makefile
|
||||
|
11
tests/crashes/128695.rs
Normal file
11
tests/crashes/128695.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//@ known-bug: rust-lang/rust#128695
|
||||
//@ edition: 2021
|
||||
|
||||
use core::pin::{pin, Pin};
|
||||
|
||||
fn main() {
|
||||
let fut = pin!(async {
|
||||
let async_drop_fut = pin!(core::future::async_drop(async {}));
|
||||
(async_drop_fut).await;
|
||||
});
|
||||
}
|
25
tests/crashes/128810.rs
Normal file
25
tests/crashes/128810.rs
Normal file
@ -0,0 +1,25 @@
|
||||
//@ known-bug: rust-lang/rust#128810
|
||||
|
||||
#![feature(fn_delegation)]
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
|
||||
|
||||
impl<'a> InvariantRef<'a, ()> {
|
||||
pub const NEW: Self = InvariantRef::new(&());
|
||||
}
|
||||
|
||||
trait Trait {
|
||||
fn foo(&self) -> u8 { 0 }
|
||||
fn bar(&self) -> u8 { 1 }
|
||||
fn meh(&self) -> u8 { 2 }
|
||||
}
|
||||
|
||||
struct Z(u8);
|
||||
|
||||
impl Trait for Z {
|
||||
reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
|
||||
}
|
||||
|
||||
fn main() { }
|
5
tests/crashes/128848.rs
Normal file
5
tests/crashes/128848.rs
Normal file
@ -0,0 +1,5 @@
|
||||
//@ known-bug: rust-lang/rust#128848
|
||||
|
||||
fn f<T>(a: T, b: T, c: T) {
|
||||
f.call_once()
|
||||
}
|
18
tests/crashes/128870.rs
Normal file
18
tests/crashes/128870.rs
Normal file
@ -0,0 +1,18 @@
|
||||
//@ known-bug: rust-lang/rust#128870
|
||||
//@ compile-flags: -Zvalidate-mir
|
||||
|
||||
#[repr(packed)]
|
||||
#[repr(u32)]
|
||||
enum E {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
union InvalidTag {
|
||||
int: u32,
|
||||
e: E,
|
||||
}
|
||||
let _invalid_tag = InvalidTag { int: 4 };
|
||||
}
|
16
tests/crashes/129075.rs
Normal file
16
tests/crashes/129075.rs
Normal file
@ -0,0 +1,16 @@
|
||||
//@ known-bug: rust-lang/rust#129075
|
||||
//@ compile-flags: -Zvalidate-mir -Zinline-mir=yes
|
||||
|
||||
struct Foo<T>([T; 2]);
|
||||
|
||||
impl<T: Default + Copy> Default for Foo<T> {
|
||||
fn default(&mut self) -> Self {
|
||||
Foo([Default::default(); 2])
|
||||
}
|
||||
}
|
||||
|
||||
fn field_array() {
|
||||
let a: i32;
|
||||
let b;
|
||||
Foo([a, b]) = Default::default();
|
||||
}
|
10
tests/crashes/129095.rs
Normal file
10
tests/crashes/129095.rs
Normal file
@ -0,0 +1,10 @@
|
||||
//@ known-bug: rust-lang/rust#129095
|
||||
//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir
|
||||
|
||||
pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
|
||||
BYTES
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(function_with_bytes::<b"AAAAb">(), &[0x41, 0x41, 0x41, 0x41]);
|
||||
}
|
15
tests/crashes/129099.rs
Normal file
15
tests/crashes/129099.rs
Normal file
@ -0,0 +1,15 @@
|
||||
//@ known-bug: rust-lang/rust#129099
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
type Opaque = impl Sized;
|
||||
fn define() -> Opaque {
|
||||
let x: Opaque = dyn_hoops::<()>(0);
|
||||
x
|
||||
}
|
||||
}
|
10
tests/crashes/129109.rs
Normal file
10
tests/crashes/129109.rs
Normal file
@ -0,0 +1,10 @@
|
||||
//@ known-bug: rust-lang/rust#129109
|
||||
//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir
|
||||
|
||||
extern "C" {
|
||||
pub static mut symbol: [i8];
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("C", unsafe { &symbol });
|
||||
}
|
21
tests/crashes/129127.rs
Normal file
21
tests/crashes/129127.rs
Normal file
@ -0,0 +1,21 @@
|
||||
//@ known-bug: rust-lang/rust#129127
|
||||
//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir -Zcross-crate-inline-threshold=always
|
||||
|
||||
|
||||
|
||||
|
||||
pub struct Rows<'a>();
|
||||
|
||||
impl<'a> Iterator for Rows<'a> {
|
||||
type Item = ();
|
||||
|
||||
fn next() -> Option<Self::Item> {
|
||||
let mut rows = Rows();
|
||||
rows.map(|row| row).next()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut rows = Rows();
|
||||
rows.next();
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
# ignore-cross-compile
|
||||
# needs-unwind
|
||||
include ../tools.mk
|
||||
|
||||
# Test expected libtest's JSON output
|
||||
|
||||
OUTPUT_FILE_DEFAULT := $(TMPDIR)/libtest-json-output-default.json
|
||||
OUTPUT_FILE_STDOUT_SUCCESS := $(TMPDIR)/libtest-json-output-stdout-success.json
|
||||
|
||||
all: f.rs validate_json.py output-default.json output-stdout-success.json
|
||||
$(RUSTC) --test f.rs
|
||||
RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE_DEFAULT) || true
|
||||
RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json --show-output > $(OUTPUT_FILE_STDOUT_SUCCESS) || true
|
||||
|
||||
cat $(OUTPUT_FILE_DEFAULT) | "$(PYTHON)" validate_json.py
|
||||
cat $(OUTPUT_FILE_STDOUT_SUCCESS) | "$(PYTHON)" validate_json.py
|
||||
|
||||
# Normalize the actual output and compare to expected output file
|
||||
cat $(OUTPUT_FILE_DEFAULT) | sed 's/"exec_time": [0-9.]*/"exec_time": $$TIME/' | diff output-default.json -
|
||||
cat $(OUTPUT_FILE_STDOUT_SUCCESS) | sed 's/"exec_time": [0-9.]*/"exec_time": $$TIME/' | diff output-stdout-success.json -
|
@ -7,4 +7,4 @@
|
||||
{ "type": "test", "name": "c", "event": "ok" }
|
||||
{ "type": "test", "event": "started", "name": "d" }
|
||||
{ "type": "test", "name": "d", "event": "ignored", "message": "msg" }
|
||||
{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
|
||||
{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": "$EXEC_TIME" }
|
||||
|
@ -7,4 +7,4 @@
|
||||
{ "type": "test", "name": "c", "event": "ok", "stdout": "thread 'c' panicked at f.rs:15:5:\nassertion failed: false\n" }
|
||||
{ "type": "test", "event": "started", "name": "d" }
|
||||
{ "type": "test", "name": "d", "event": "ignored", "message": "msg" }
|
||||
{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
|
||||
{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": "$EXEC_TIME" }
|
||||
|
31
tests/run-make/libtest-json/rmake.rs
Normal file
31
tests/run-make/libtest-json/rmake.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Check libtest's JSON output against snapshots.
|
||||
|
||||
//@ ignore-cross-compile
|
||||
//@ needs-unwind (test file contains #[should_panic] test)
|
||||
|
||||
use run_make_support::{cmd, diff, python_command, rustc};
|
||||
|
||||
fn main() {
|
||||
rustc().arg("--test").input("f.rs").run();
|
||||
|
||||
run_tests(&[], "output-default.json");
|
||||
run_tests(&["--show-output"], "output-stdout-success.json");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn run_tests(extra_args: &[&str], expected_file: &str) {
|
||||
let cmd_out = cmd("./f")
|
||||
.env("RUST_BACKTRACE", "0")
|
||||
.args(&["-Zunstable-options", "--test-threads=1", "--format=json"])
|
||||
.args(extra_args)
|
||||
.run_fail();
|
||||
let test_stdout = &cmd_out.stdout_utf8();
|
||||
|
||||
python_command().arg("validate_json.py").stdin(test_stdout).run();
|
||||
|
||||
diff()
|
||||
.expected_file(expected_file)
|
||||
.actual_text("stdout", test_stdout)
|
||||
.normalize(r#"(?<prefix>"exec_time": )[0-9.]+"#, r#"${prefix}"$$EXEC_TIME""#)
|
||||
.run();
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
# ignore-cross-compile
|
||||
# needs-unwind contains should_panic test
|
||||
include ../tools.mk
|
||||
|
||||
# Test expected libtest's junit output
|
||||
|
||||
OUTPUT_FILE_DEFAULT := $(TMPDIR)/libtest-junit-output-default.xml
|
||||
OUTPUT_FILE_STDOUT_SUCCESS := $(TMPDIR)/libtest-junit-output-stdout-success.xml
|
||||
|
||||
all: f.rs validate_junit.py output-default.xml output-stdout-success.xml
|
||||
$(RUSTC) --test f.rs
|
||||
RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=junit > $(OUTPUT_FILE_DEFAULT) || true
|
||||
RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=junit --show-output > $(OUTPUT_FILE_STDOUT_SUCCESS) || true
|
||||
|
||||
cat $(OUTPUT_FILE_DEFAULT) | "$(PYTHON)" validate_junit.py
|
||||
cat $(OUTPUT_FILE_STDOUT_SUCCESS) | "$(PYTHON)" validate_junit.py
|
||||
|
||||
# Normalize the actual output and compare to expected output file
|
||||
cat $(OUTPUT_FILE_DEFAULT) | sed 's/time="[0-9.]*"/time="$$TIME"/g' | diff output-default.xml -
|
||||
cat $(OUTPUT_FILE_STDOUT_SUCCESS) | sed 's/time="[0-9.]*"/time="$$TIME"/g' | diff output-stdout-success.xml -
|
31
tests/run-make/libtest-junit/rmake.rs
Normal file
31
tests/run-make/libtest-junit/rmake.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Check libtest's JUnit (XML) output against snapshots.
|
||||
|
||||
//@ ignore-cross-compile
|
||||
//@ needs-unwind (test file contains #[should_panic] test)
|
||||
|
||||
use run_make_support::{cmd, diff, python_command, rustc};
|
||||
|
||||
fn main() {
|
||||
rustc().arg("--test").input("f.rs").run();
|
||||
|
||||
run_tests(&[], "output-default.xml");
|
||||
run_tests(&["--show-output"], "output-stdout-success.xml");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn run_tests(extra_args: &[&str], expected_file: &str) {
|
||||
let cmd_out = cmd("./f")
|
||||
.env("RUST_BACKTRACE", "0")
|
||||
.args(&["-Zunstable-options", "--test-threads=1", "--format=junit"])
|
||||
.args(extra_args)
|
||||
.run_fail();
|
||||
let test_stdout = &cmd_out.stdout_utf8();
|
||||
|
||||
python_command().arg("validate_junit.py").stdin(test_stdout).run();
|
||||
|
||||
diff()
|
||||
.expected_file(expected_file)
|
||||
.actual_text("stdout", test_stdout)
|
||||
.normalize(r#"\btime="[0-9.]+""#, r#"time="$$TIME""#)
|
||||
.run();
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
# ignore-cross-compile
|
||||
# ignore-windows-msvc
|
||||
|
||||
include ../tools.mk
|
||||
|
||||
# We're using the llvm-nm instead of the system nm to ensure it is compatible
|
||||
# with the LLVM bitcode generated by rustc.
|
||||
# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
|
||||
ifndef IS_WINDOWS
|
||||
NM = "$(LLVM_BIN_DIR)"/llvm-nm
|
||||
else
|
||||
NM = nm
|
||||
endif
|
||||
|
||||
all: $(call NATIVE_STATICLIB,native-staticlib)
|
||||
# Build a staticlib and a rlib, the `native_func` symbol will be bundled into them
|
||||
$(RUSTC) bundled.rs --crate-type=staticlib --crate-type=rlib
|
||||
$(NM) $(TMPDIR)/libbundled.a | $(CGREP) -e "T _*native_func"
|
||||
$(NM) $(TMPDIR)/libbundled.a | $(CGREP) -e "U _*native_func"
|
||||
$(NM) $(TMPDIR)/libbundled.rlib | $(CGREP) -e "T _*native_func"
|
||||
$(NM) $(TMPDIR)/libbundled.rlib | $(CGREP) -e "U _*native_func"
|
||||
|
||||
# Build a staticlib and a rlib, the `native_func` symbol will not be bundled into it
|
||||
$(RUSTC) non-bundled.rs --crate-type=staticlib --crate-type=rlib
|
||||
$(NM) $(TMPDIR)/libnon_bundled.a | $(CGREP) -ve "T _*native_func"
|
||||
$(NM) $(TMPDIR)/libnon_bundled.a | $(CGREP) -e "U _*native_func"
|
||||
$(NM) $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -ve "T _*native_func"
|
||||
$(NM) $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -e "U _*native_func"
|
||||
|
||||
# Build a cdylib, `native-staticlib` will not appear on the linker line because it was bundled previously
|
||||
# The cdylib will contain the `native_func` symbol in the end
|
||||
$(RUSTC) cdylib-bundled.rs --crate-type=cdylib --print link-args | $(CGREP) -ve '-l[" ]*native-staticlib'
|
||||
$(NM) $(call DYLIB,cdylib_bundled) | $(CGREP) -e "[Tt] _*native_func"
|
||||
|
||||
# Build a cdylib, `native-staticlib` will appear on the linker line because it was not bundled previously
|
||||
# The cdylib will contain the `native_func` symbol in the end
|
||||
$(RUSTC) cdylib-non-bundled.rs --crate-type=cdylib --print link-args | $(CGREP) -e '-l[" ]*native-staticlib'
|
||||
$(NM) $(call DYLIB,cdylib_non_bundled) | $(CGREP) -e "[Tt] _*native_func"
|
90
tests/run-make/native-link-modifier-bundle/rmake.rs
Normal file
90
tests/run-make/native-link-modifier-bundle/rmake.rs
Normal file
@ -0,0 +1,90 @@
|
||||
// This test exercises the `bundle` link argument, which can be turned on or off.
|
||||
|
||||
// When building a rlib or staticlib, +bundle means that all object files from the native static
|
||||
// library will be added to the rlib or staticlib archive, and then used from it during linking of
|
||||
// the final binary.
|
||||
|
||||
// When building a rlib -bundle means that the native static library is registered as a dependency
|
||||
// of that rlib "by name", and object files from it are included only during linking of the final
|
||||
// binary, the file search by that name is also performed during final linking.
|
||||
// When building a staticlib -bundle means that the native static library is simply not included
|
||||
// into the archive and some higher level build system will need to add it later during linking of
|
||||
// the final binary.
|
||||
|
||||
// This modifier has no effect when building other targets like executables or dynamic libraries.
|
||||
|
||||
// The default for this modifier is +bundle.
|
||||
// See https://github.com/rust-lang/rust/pull/95818
|
||||
|
||||
//@ ignore-cross-compile
|
||||
// Reason: cross-compilation fails to export native symbols
|
||||
|
||||
use run_make_support::{
|
||||
build_native_static_lib, dynamic_lib_name, is_msvc, llvm_nm, rust_lib_name, rustc,
|
||||
static_lib_name,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
build_native_static_lib("native-staticlib");
|
||||
// Build a staticlib and a rlib, the `native_func` symbol will be bundled into them
|
||||
rustc().input("bundled.rs").crate_type("staticlib").crate_type("rlib").run();
|
||||
llvm_nm()
|
||||
.input(static_lib_name("bundled"))
|
||||
.run()
|
||||
.assert_stdout_contains_regex("T _*native_func");
|
||||
llvm_nm()
|
||||
.input(static_lib_name("bundled"))
|
||||
.run()
|
||||
.assert_stdout_contains_regex("U _*native_func");
|
||||
llvm_nm().input(rust_lib_name("bundled")).run().assert_stdout_contains_regex("T _*native_func");
|
||||
llvm_nm().input(rust_lib_name("bundled")).run().assert_stdout_contains_regex("U _*native_func");
|
||||
|
||||
// Build a staticlib and a rlib, the `native_func` symbol will not be bundled into it
|
||||
build_native_static_lib("native-staticlib");
|
||||
rustc().input("non-bundled.rs").crate_type("staticlib").crate_type("rlib").run();
|
||||
llvm_nm()
|
||||
.input(static_lib_name("non_bundled"))
|
||||
.run()
|
||||
.assert_stdout_not_contains_regex("T _*native_func");
|
||||
llvm_nm()
|
||||
.input(static_lib_name("non_bundled"))
|
||||
.run()
|
||||
.assert_stdout_contains_regex("U _*native_func");
|
||||
llvm_nm()
|
||||
.input(rust_lib_name("non_bundled"))
|
||||
.run()
|
||||
.assert_stdout_not_contains_regex("T _*native_func");
|
||||
llvm_nm()
|
||||
.input(rust_lib_name("non_bundled"))
|
||||
.run()
|
||||
.assert_stdout_contains_regex("U _*native_func");
|
||||
|
||||
// This part of the test does not function on Windows MSVC - no symbols are printed.
|
||||
if !is_msvc() {
|
||||
// Build a cdylib, `native-staticlib` will not appear on the linker line because it was
|
||||
// bundled previously. The cdylib will contain the `native_func` symbol in the end.
|
||||
rustc()
|
||||
.input("cdylib-bundled.rs")
|
||||
.crate_type("cdylib")
|
||||
.print("link-args")
|
||||
.run()
|
||||
.assert_stdout_not_contains(r#"-l[" ]*native-staticlib"#);
|
||||
llvm_nm()
|
||||
.input(dynamic_lib_name("cdylib_bundled"))
|
||||
.run()
|
||||
.assert_stdout_contains_regex("[Tt] _*native_func");
|
||||
|
||||
// Build a cdylib, `native-staticlib` will appear on the linker line because it was not
|
||||
// bundled previously. The cdylib will contain the `native_func` symbol in the end
|
||||
rustc()
|
||||
.input("cdylib-non-bundled.rs")
|
||||
.crate_type("cdylib")
|
||||
.print("link-args")
|
||||
.run()
|
||||
.assert_stdout_contains_regex(r#"-l[" ]*native-staticlib"#);
|
||||
llvm_nm()
|
||||
.input(dynamic_lib_name("cdylib_non_bundled"))
|
||||
.run()
|
||||
.assert_stdout_contains_regex("[Tt] _*native_func");
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
include ../tools.mk
|
||||
|
||||
# ignore-cross-compile
|
||||
|
||||
# Make sure rlib format with -Zpacked_bundled_libs is correct.
|
||||
|
||||
# We're using the llvm-nm instead of the system nm to ensure it is compatible
|
||||
# with the LLVM bitcode generated by rustc.
|
||||
# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
|
||||
ifndef IS_WINDOWS
|
||||
NM = "$(LLVM_BIN_DIR)"/llvm-nm
|
||||
else
|
||||
NM = nm
|
||||
endif
|
||||
|
||||
all: $(call NATIVE_STATICLIB,native_dep_1) $(call NATIVE_STATICLIB,native_dep_2) $(call NATIVE_STATICLIB,native_dep_3)
|
||||
$(RUSTC) rust_dep_up.rs --crate-type=rlib -Zpacked_bundled_libs
|
||||
$(NM) $(TMPDIR)/librust_dep_up.rlib | $(CGREP) -e "U.*native_f2"
|
||||
$(NM) $(TMPDIR)/librust_dep_up.rlib | $(CGREP) -e "U.*native_f3"
|
||||
$(NM) $(TMPDIR)/librust_dep_up.rlib | $(CGREP) -e "T.*rust_dep_up"
|
||||
$(AR) t $(TMPDIR)/librust_dep_up.rlib | $(CGREP) "native_dep_2"
|
||||
$(AR) t $(TMPDIR)/librust_dep_up.rlib | $(CGREP) "native_dep_3"
|
||||
$(RUSTC) rust_dep_local.rs --extern rlib=$(TMPDIR)/librust_dep_up.rlib -Zpacked_bundled_libs --crate-type=rlib
|
||||
$(NM) $(TMPDIR)/librust_dep_local.rlib | $(CGREP) -e "U.*native_f1"
|
||||
$(NM) $(TMPDIR)/librust_dep_local.rlib | $(CGREP) -e "T.*rust_dep_local"
|
||||
$(AR) t $(TMPDIR)/librust_dep_local.rlib | $(CGREP) "native_dep_1"
|
||||
|
||||
# Make sure compiler doesn't use files, that it shouldn't know about.
|
||||
rm $(TMPDIR)/*native_dep_*
|
||||
|
||||
$(RUSTC) main.rs --extern lib=$(TMPDIR)/librust_dep_local.rlib -o $(TMPDIR)/main.exe -Zpacked_bundled_libs --print link-args | $(CGREP) -e "native_dep_1.*native_dep_2.*native_dep_3"
|
||||
|
||||
ifndef IS_MSVC
|
||||
$(NM) $(TMPDIR)/main.exe | $(CGREP) -e "T.*native_f1"
|
||||
$(NM) $(TMPDIR)/main.exe | $(CGREP) -e "T.*native_f2"
|
||||
$(NM) $(TMPDIR)/main.exe | $(CGREP) -e "T.*native_f3"
|
||||
$(NM) $(TMPDIR)/main.exe | $(CGREP) -e "T.*rust_dep_local"
|
||||
$(NM) $(TMPDIR)/main.exe | $(CGREP) -e "T.*rust_dep_up"
|
||||
endif
|
84
tests/run-make/rlib-format-packed-bundled-libs/rmake.rs
Normal file
84
tests/run-make/rlib-format-packed-bundled-libs/rmake.rs
Normal file
@ -0,0 +1,84 @@
|
||||
// `-Z packed_bundled_libs` is an unstable rustc flag that makes the compiler
|
||||
// only require a native library and no supplementary object files to compile.
|
||||
// Output files compiled with this flag should still contain all expected symbols -
|
||||
// that is what this test checks.
|
||||
// See https://github.com/rust-lang/rust/pull/100101
|
||||
|
||||
//@ ignore-cross-compile
|
||||
// Reason: cross-compilation fails to export native symbols
|
||||
|
||||
use run_make_support::{
|
||||
bin_name, build_native_static_lib, cwd, filename_contains, is_msvc, llvm_ar, llvm_nm, rfs,
|
||||
rust_lib_name, rustc, shallow_find_files,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
build_native_static_lib("native_dep_1");
|
||||
build_native_static_lib("native_dep_2");
|
||||
build_native_static_lib("native_dep_3");
|
||||
rustc().input("rust_dep_up.rs").crate_type("rlib").arg("-Zpacked_bundled_libs").run();
|
||||
llvm_nm()
|
||||
.input(rust_lib_name("rust_dep_up"))
|
||||
.run()
|
||||
.assert_stdout_contains_regex("U.*native_f2");
|
||||
llvm_nm()
|
||||
.input(rust_lib_name("rust_dep_up"))
|
||||
.run()
|
||||
.assert_stdout_contains_regex("U.*native_f3");
|
||||
llvm_nm()
|
||||
.input(rust_lib_name("rust_dep_up"))
|
||||
.run()
|
||||
.assert_stdout_contains_regex("T.*rust_dep_up");
|
||||
llvm_ar()
|
||||
.table_of_contents()
|
||||
.arg(rust_lib_name("rust_dep_up"))
|
||||
.run()
|
||||
.assert_stdout_contains("native_dep_2");
|
||||
llvm_ar()
|
||||
.table_of_contents()
|
||||
.arg(rust_lib_name("rust_dep_up"))
|
||||
.run()
|
||||
.assert_stdout_contains("native_dep_3");
|
||||
rustc()
|
||||
.input("rust_dep_local.rs")
|
||||
.extern_("rlib", rust_lib_name("rust_dep_up"))
|
||||
.arg("-Zpacked_bundled_libs")
|
||||
.crate_type("rlib")
|
||||
.run();
|
||||
llvm_nm()
|
||||
.input(rust_lib_name("rust_dep_local"))
|
||||
.run()
|
||||
.assert_stdout_contains_regex("U.*native_f1");
|
||||
llvm_nm()
|
||||
.input(rust_lib_name("rust_dep_local"))
|
||||
.run()
|
||||
.assert_stdout_contains_regex("T.*rust_dep_local");
|
||||
llvm_ar()
|
||||
.table_of_contents()
|
||||
.arg(rust_lib_name("rust_dep_local"))
|
||||
.run()
|
||||
.assert_stdout_contains("native_dep_1");
|
||||
|
||||
// Ensure the compiler will not use files it should not know about.
|
||||
for file in shallow_find_files(cwd(), |path| filename_contains(path, "native_dep_")) {
|
||||
rfs::remove_file(file);
|
||||
}
|
||||
|
||||
rustc()
|
||||
.input("main.rs")
|
||||
.extern_("lib", rust_lib_name("rust_dep_local"))
|
||||
.output(bin_name("main"))
|
||||
.arg("-Zpacked_bundled_libs")
|
||||
.print("link-args")
|
||||
.run()
|
||||
.assert_stdout_contains_regex("native_dep_1.*native_dep_2.*native_dep_3");
|
||||
|
||||
// The binary "main" will not contain any symbols on MSVC.
|
||||
if !is_msvc() {
|
||||
llvm_nm().input(bin_name("main")).run().assert_stdout_contains_regex("T.*native_f1");
|
||||
llvm_nm().input(bin_name("main")).run().assert_stdout_contains_regex("T.*native_f2");
|
||||
llvm_nm().input(bin_name("main")).run().assert_stdout_contains_regex("T.*native_f3");
|
||||
llvm_nm().input(bin_name("main")).run().assert_stdout_contains_regex("T.*rust_dep_local");
|
||||
llvm_nm().input(bin_name("main")).run().assert_stdout_contains_regex("T.*rust_dep_up");
|
||||
}
|
||||
}
|
@ -1,5 +1,102 @@
|
||||
use run_make_support::python_command;
|
||||
// Check that crates in the sysroot are treated as unstable, unless they are
|
||||
// on a list of known-stable sysroot crates.
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str;
|
||||
|
||||
use run_make_support::{rfs, rustc, target};
|
||||
|
||||
fn is_stable_crate(name: &str) -> bool {
|
||||
matches!(name, "std" | "alloc" | "core" | "proc_macro")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
python_command().arg("test.py").run();
|
||||
for cr in get_unstable_sysroot_crates() {
|
||||
check_crate_is_unstable(&cr);
|
||||
}
|
||||
println!("Done");
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Crate {
|
||||
name: String,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
fn check_crate_is_unstable(cr: &Crate) {
|
||||
let Crate { name, path } = cr;
|
||||
|
||||
print!("- Verifying that sysroot crate '{name}' is an unstable crate ...");
|
||||
|
||||
// Trying to use this crate from a user program should fail.
|
||||
let output = rustc()
|
||||
.crate_type("rlib")
|
||||
.target(target())
|
||||
.extern_(name, path)
|
||||
.input("-")
|
||||
.stdin(format!("extern crate {name};"))
|
||||
.run_fail();
|
||||
|
||||
// Make sure it failed for the intended reason, not some other reason.
|
||||
// (The actual feature required varies between crates.)
|
||||
output.assert_stderr_contains("use of unstable library feature");
|
||||
|
||||
println!(" OK");
|
||||
}
|
||||
|
||||
fn get_unstable_sysroot_crates() -> Vec<Crate> {
|
||||
let sysroot = PathBuf::from(rustc().print("sysroot").run().stdout_utf8().trim());
|
||||
let sysroot_libs_dir = sysroot.join("lib").join("rustlib").join(target()).join("lib");
|
||||
println!("Sysroot libs dir: {sysroot_libs_dir:?}");
|
||||
|
||||
// Generate a list of all library crates in the sysroot.
|
||||
let sysroot_crates = get_all_crates_in_dir(&sysroot_libs_dir);
|
||||
println!(
|
||||
"Found {} sysroot crates: {:?}",
|
||||
sysroot_crates.len(),
|
||||
sysroot_crates.iter().map(|cr| &cr.name).collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
// Self-check: If we didn't find `core`, we probably checked the wrong directory.
|
||||
assert!(
|
||||
sysroot_crates.iter().any(|cr| cr.name == "core"),
|
||||
"Couldn't find `core` in {sysroot_libs_dir:?}"
|
||||
);
|
||||
|
||||
let unstable_sysroot_crates =
|
||||
sysroot_crates.into_iter().filter(|cr| !is_stable_crate(&cr.name)).collect::<Vec<_>>();
|
||||
// Self-check: There should be at least one unstable crate in the directory.
|
||||
assert!(
|
||||
!unstable_sysroot_crates.is_empty(),
|
||||
"Couldn't find any unstable crates in {sysroot_libs_dir:?}"
|
||||
);
|
||||
unstable_sysroot_crates
|
||||
}
|
||||
|
||||
fn get_all_crates_in_dir(libs_dir: &Path) -> Vec<Crate> {
|
||||
let mut libs = vec![];
|
||||
rfs::read_dir_entries(libs_dir, |path| {
|
||||
if !path.is_file() {
|
||||
return;
|
||||
}
|
||||
if let Some(name) = crate_name_from_path(path) {
|
||||
libs.push(Crate { name, path: path.to_owned() });
|
||||
}
|
||||
});
|
||||
libs.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
libs
|
||||
}
|
||||
|
||||
/// Treat a file as a crate if its name begins with `lib` and ends with `.rlib`.
|
||||
/// The crate name is the part before the first hyphen (if any).
|
||||
fn crate_name_from_path(path: &Path) -> Option<String> {
|
||||
let name = path
|
||||
.file_name()?
|
||||
.to_str()?
|
||||
.strip_prefix("lib")?
|
||||
.strip_suffix(".rlib")?
|
||||
.split('-')
|
||||
.next()
|
||||
.expect("split always yields at least one string");
|
||||
Some(name.to_owned())
|
||||
}
|
||||
|
@ -1,75 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
from subprocess import PIPE, Popen
|
||||
|
||||
|
||||
# This is n list of files which are stable crates or simply are not crates,
|
||||
# we don't check for the instability of these crates as they're all stable!
|
||||
STABLE_CRATES = ['std', 'alloc', 'core', 'proc_macro',
|
||||
'rsbegin.o', 'rsend.o', 'dllcrt2.o', 'crt2.o', 'clang_rt']
|
||||
|
||||
|
||||
def convert_to_string(s):
|
||||
if s.__class__.__name__ == 'bytes':
|
||||
return s.decode('utf-8')
|
||||
return s
|
||||
|
||||
|
||||
def set_ld_lib_path():
|
||||
var = os.environ.get("LD_LIB_PATH_ENVVAR")
|
||||
rpath = os.environ.get("HOST_RPATH_DIR")
|
||||
if var and rpath:
|
||||
path = os.environ.get(var)
|
||||
if path:
|
||||
os.environ[var] = rpath + os.pathsep + path
|
||||
else:
|
||||
os.environ[var] = rpath
|
||||
|
||||
|
||||
def exec_command(command, to_input=None):
|
||||
child = None
|
||||
if to_input is None:
|
||||
child = Popen(command, stdout=PIPE, stderr=PIPE)
|
||||
else:
|
||||
child = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
|
||||
stdout, stderr = child.communicate(input=to_input)
|
||||
return (convert_to_string(stdout), convert_to_string(stderr))
|
||||
|
||||
|
||||
def check_lib(lib):
|
||||
if lib['name'] in STABLE_CRATES:
|
||||
return True
|
||||
print('verifying if {} is an unstable crate'.format(lib['name']))
|
||||
stdout, stderr = exec_command([os.environ['RUSTC'], '-', '--crate-type', 'rlib',
|
||||
'--target', os.environ['TARGET'],
|
||||
'--extern', '{}={}'.format(lib['name'], lib['path'])],
|
||||
to_input=('extern crate {};'.format(lib['name'])).encode('utf-8'))
|
||||
if 'use of unstable library feature' not in '{}{}'.format(stdout, stderr):
|
||||
print('crate {} "{}" is not unstable'.format(lib['name'], lib['path']))
|
||||
print('{}{}'.format(stdout, stderr))
|
||||
print('')
|
||||
return False
|
||||
return True
|
||||
|
||||
# Generate a list of all crates in the sysroot. To do this we list all files in
|
||||
# rustc's sysroot, look at the filename, strip everything after the `-`, and
|
||||
# strip the leading `lib` (if present)
|
||||
def get_all_libs(dir_path):
|
||||
return [{ 'path': join(dir_path, f), 'name': f[3:].split('-')[0] }
|
||||
for f in listdir(dir_path)
|
||||
if isfile(join(dir_path, f)) and f.endswith('.rlib') and f not in STABLE_CRATES]
|
||||
|
||||
|
||||
set_ld_lib_path()
|
||||
sysroot = exec_command([os.environ['RUSTC'], '--print', 'sysroot'])[0].replace('\n', '')
|
||||
assert sysroot, "Could not read the rustc sysroot!"
|
||||
libs = get_all_libs(join(sysroot, 'lib/rustlib/{}/lib'.format(os.environ['TARGET'])))
|
||||
|
||||
ret = 0
|
||||
for lib in libs:
|
||||
if not check_lib(lib):
|
||||
# We continue so users can see all the not unstable crates.
|
||||
ret = 1
|
||||
sys.exit(ret)
|
Loading…
x
Reference in New Issue
Block a user