Auto merge of #126038 - matthiaskrgr:rollup-h4rm3x2, r=matthiaskrgr

Rollup of 9 pull requests

Successful merges:

 - #124840 (resolve: mark it undetermined if single import is not has any bindings)
 - #125622 (Winnow private method candidates instead of assuming any candidate of the right name will apply)
 - #125648 (Remove unused(?) `~/rustsrc` folder from docker script)
 - #125672 (Add more ABI test cases to miri (RFC 3391))
 - #125800 (Fix `mut` static task queue in SGX target)
 - #125871 (Orphanck[old solver]: Consider opaque types to never cover type parameters)
 - #125893 (Handle all GVN binops in a single place.)
 - #126008 (Port `tests/run-make-fulldeps/issue-19371` to ui-fulldeps)
 - #126032 (Update description of the `IsTerminal` example)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-06-05 20:53:32 +00:00
commit 72fdf913c5
37 changed files with 456 additions and 191 deletions

View file

@ -294,17 +294,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Unwrap types that are guaranteed a null-pointer-optimization /// Unwrap types that are guaranteed a null-pointer-optimization
fn unfold_npo(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { fn unfold_npo(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
// Check if this is `Option` wrapping some type. // Check if this is `Option` wrapping some type or if this is `Result` wrapping a 1-ZST and
let inner = match layout.ty.kind() { // another type.
ty::Adt(def, args) if self.tcx.is_diagnostic_item(sym::Option, def.did()) => { let ty::Adt(def, args) = layout.ty.kind() else {
args[0].as_type().unwrap() // Not an ADT, so definitely no NPO.
} return Ok(layout);
_ => {
// Not an `Option`.
return Ok(layout);
}
}; };
let inner = self.layout_of(inner)?; let inner = if self.tcx.is_diagnostic_item(sym::Option, def.did()) {
// The wrapped type is the only arg.
self.layout_of(args[0].as_type().unwrap())?
} else if self.tcx.is_diagnostic_item(sym::Result, def.did()) {
// We want to extract which (if any) of the args is not a 1-ZST.
let lhs = self.layout_of(args[0].as_type().unwrap())?;
let rhs = self.layout_of(args[1].as_type().unwrap())?;
if lhs.is_1zst() {
rhs
} else if rhs.is_1zst() {
lhs
} else {
return Ok(layout); // no NPO
}
} else {
return Ok(layout); // no NPO
};
// Check if the inner type is one of the NPO-guaranteed ones. // Check if the inner type is one of the NPO-guaranteed ones.
// For that we first unpeel transparent *structs* (but not unions). // For that we first unpeel transparent *structs* (but not unions).
let is_npo = |def: AdtDef<'tcx>| { let is_npo = |def: AdtDef<'tcx>| {

View file

@ -1066,7 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::ImplContainer => { ty::ImplContainer => {
if segments.len() == 1 { if segments.len() == 1 {
// `<T>::assoc` will end up here, and so // `<T>::assoc` will end up here, and so
// can `T::assoc`. It this came from an // can `T::assoc`. If this came from an
// inherent impl, we need to record the // inherent impl, we need to record the
// `T` for posterity (see `UserSelfTy` for // `T` for posterity (see `UserSelfTy` for
// details). // details).
@ -1416,11 +1416,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) { ) {
Ok(ok) => self.register_infer_ok_obligations(ok), Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => { Err(_) => {
self.dcx().span_delayed_bug( self.dcx().span_bug(
span, span,
format!( format!(
"instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?", "instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?",
), ),
); );
} }
} }

View file

@ -41,6 +41,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
use rustc_trait_selection::traits::query::CanonicalTyGoal; use rustc_trait_selection::traits::query::CanonicalTyGoal;
use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCause}; use rustc_trait_selection::traits::{self, ObligationCause};
use std::cell::Cell;
use std::cell::RefCell; use std::cell::RefCell;
use std::cmp::max; use std::cmp::max;
use std::iter; use std::iter;
@ -76,8 +77,12 @@ pub(crate) struct ProbeContext<'a, 'tcx> {
/// requested name (by edit distance) /// requested name (by edit distance)
allow_similar_names: bool, allow_similar_names: bool,
/// List of potential private candidates. Will be trimmed to ones that
/// actually apply and then the result inserted into `private_candidate`
private_candidates: Vec<Candidate<'tcx>>,
/// Some(candidate) if there is a private candidate /// Some(candidate) if there is a private candidate
private_candidate: Option<(DefKind, DefId)>, private_candidate: Cell<Option<(DefKind, DefId)>>,
/// Collects near misses when the candidate functions are missing a `self` keyword and is only /// Collects near misses when the candidate functions are missing a `self` keyword and is only
/// used for error reporting /// used for error reporting
@ -581,7 +586,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
orig_steps_var_values, orig_steps_var_values,
steps, steps,
allow_similar_names: false, allow_similar_names: false,
private_candidate: None, private_candidates: Vec::new(),
private_candidate: Cell::new(None),
static_candidates: RefCell::new(Vec::new()), static_candidates: RefCell::new(Vec::new()),
unsatisfied_predicates: RefCell::new(Vec::new()), unsatisfied_predicates: RefCell::new(Vec::new()),
scope_expr_id, scope_expr_id,
@ -593,7 +599,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.inherent_candidates.clear(); self.inherent_candidates.clear();
self.extension_candidates.clear(); self.extension_candidates.clear();
self.impl_dups.clear(); self.impl_dups.clear();
self.private_candidate = None; self.private_candidates.clear();
self.private_candidate.set(None);
self.static_candidates.borrow_mut().clear(); self.static_candidates.borrow_mut().clear();
self.unsatisfied_predicates.borrow_mut().clear(); self.unsatisfied_predicates.borrow_mut().clear();
} }
@ -617,9 +624,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
} else { } else {
self.extension_candidates.push(candidate); self.extension_candidates.push(candidate);
} }
} else if self.private_candidate.is_none() { } else {
self.private_candidate = self.private_candidates.push(candidate);
Some((candidate.item.kind.as_def_kind(), candidate.item.def_id));
} }
} }
@ -1171,7 +1177,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let mut possibly_unsatisfied_predicates = Vec::new(); let mut possibly_unsatisfied_predicates = Vec::new();
for (kind, candidates) in for (kind, candidates) in
&[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] [("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
{ {
debug!("searching {} candidates", kind); debug!("searching {} candidates", kind);
let res = self.consider_candidates( let res = self.consider_candidates(
@ -1185,6 +1191,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
} }
} }
if self.private_candidate.get().is_none() {
if let Some(Ok(pick)) =
self.consider_candidates(self_ty, &self.private_candidates, &mut vec![], None)
{
self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id)));
}
}
// `pick_method` may be called twice for the same self_ty if no stable methods // `pick_method` may be called twice for the same self_ty if no stable methods
// match. Only extend once. // match. Only extend once.
if unstable_candidates.is_some() { if unstable_candidates.is_some() {

View file

@ -223,7 +223,6 @@ enum Value<'tcx> {
NullaryOp(NullOp<'tcx>, Ty<'tcx>), NullaryOp(NullOp<'tcx>, Ty<'tcx>),
UnaryOp(UnOp, VnIndex), UnaryOp(UnOp, VnIndex),
BinaryOp(BinOp, VnIndex, VnIndex), BinaryOp(BinOp, VnIndex, VnIndex),
CheckedBinaryOp(BinOp, VnIndex, VnIndex), // FIXME get rid of this, work like MIR instead
Cast { Cast {
kind: CastKind, kind: CastKind,
value: VnIndex, value: VnIndex,
@ -508,17 +507,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
let val = self.ecx.binary_op(bin_op, &lhs, &rhs).ok()?; let val = self.ecx.binary_op(bin_op, &lhs, &rhs).ok()?;
val.into() val.into()
} }
CheckedBinaryOp(bin_op, lhs, rhs) => {
let lhs = self.evaluated[lhs].as_ref()?;
let lhs = self.ecx.read_immediate(lhs).ok()?;
let rhs = self.evaluated[rhs].as_ref()?;
let rhs = self.ecx.read_immediate(rhs).ok()?;
let val = self
.ecx
.binary_op(bin_op.wrapping_to_overflowing().unwrap(), &lhs, &rhs)
.ok()?;
val.into()
}
Cast { kind, value, from: _, to } => match kind { Cast { kind, value, from: _, to } => match kind {
CastKind::IntToInt | CastKind::IntToFloat => { CastKind::IntToInt | CastKind::IntToFloat => {
let value = self.evaluated[value].as_ref()?; let value = self.evaluated[value].as_ref()?;
@ -829,17 +817,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
let lhs = lhs?; let lhs = lhs?;
let rhs = rhs?; let rhs = rhs?;
if let Some(op) = op.overflowing_to_wrapping() { if let Some(value) = self.simplify_binary(op, ty, lhs, rhs) {
if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) { return Some(value);
return Some(value);
}
Value::CheckedBinaryOp(op, lhs, rhs)
} else {
if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) {
return Some(value);
}
Value::BinaryOp(op, lhs, rhs)
} }
Value::BinaryOp(op, lhs, rhs)
} }
Rvalue::UnaryOp(op, ref mut arg) => { Rvalue::UnaryOp(op, ref mut arg) => {
let arg = self.simplify_operand(arg, location)?; let arg = self.simplify_operand(arg, location)?;
@ -970,7 +951,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
fn simplify_binary( fn simplify_binary(
&mut self, &mut self,
op: BinOp, op: BinOp,
checked: bool,
lhs_ty: Ty<'tcx>, lhs_ty: Ty<'tcx>,
lhs: VnIndex, lhs: VnIndex,
rhs: VnIndex, rhs: VnIndex,
@ -999,22 +979,39 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
use Either::{Left, Right}; use Either::{Left, Right};
let a = as_bits(lhs).map_or(Right(lhs), Left); let a = as_bits(lhs).map_or(Right(lhs), Left);
let b = as_bits(rhs).map_or(Right(rhs), Left); let b = as_bits(rhs).map_or(Right(rhs), Left);
let result = match (op, a, b) { let result = match (op, a, b) {
// Neutral elements. // Neutral elements.
(BinOp::Add | BinOp::BitOr | BinOp::BitXor, Left(0), Right(p)) (
BinOp::Add
| BinOp::AddWithOverflow
| BinOp::AddUnchecked
| BinOp::BitOr
| BinOp::BitXor,
Left(0),
Right(p),
)
| ( | (
BinOp::Add BinOp::Add
| BinOp::AddWithOverflow
| BinOp::AddUnchecked
| BinOp::BitOr | BinOp::BitOr
| BinOp::BitXor | BinOp::BitXor
| BinOp::Sub | BinOp::Sub
| BinOp::SubWithOverflow
| BinOp::SubUnchecked
| BinOp::Offset | BinOp::Offset
| BinOp::Shl | BinOp::Shl
| BinOp::Shr, | BinOp::Shr,
Right(p), Right(p),
Left(0), Left(0),
) )
| (BinOp::Mul, Left(1), Right(p)) | (BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked, Left(1), Right(p))
| (BinOp::Mul | BinOp::Div, Right(p), Left(1)) => p, | (
BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked | BinOp::Div,
Right(p),
Left(1),
) => p,
// Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size. // Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size.
(BinOp::BitAnd, Right(p), Left(ones)) | (BinOp::BitAnd, Left(ones), Right(p)) (BinOp::BitAnd, Right(p), Left(ones)) | (BinOp::BitAnd, Left(ones), Right(p))
if ones == layout.size.truncate(u128::MAX) if ones == layout.size.truncate(u128::MAX)
@ -1023,10 +1020,21 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
p p
} }
// Absorbing elements. // Absorbing elements.
(BinOp::Mul | BinOp::BitAnd, _, Left(0)) (
BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked | BinOp::BitAnd,
_,
Left(0),
)
| (BinOp::Rem, _, Left(1)) | (BinOp::Rem, _, Left(1))
| ( | (
BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::BitAnd | BinOp::Shl | BinOp::Shr, BinOp::Mul
| BinOp::MulWithOverflow
| BinOp::MulUnchecked
| BinOp::Div
| BinOp::Rem
| BinOp::BitAnd
| BinOp::Shl
| BinOp::Shr,
Left(0), Left(0),
_, _,
) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty), ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty),
@ -1038,7 +1046,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty) self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty)
} }
// Sub/Xor with itself. // Sub/Xor with itself.
(BinOp::Sub | BinOp::BitXor, a, b) if a == b => { (BinOp::Sub | BinOp::SubWithOverflow | BinOp::SubUnchecked | BinOp::BitXor, a, b)
if a == b =>
{
self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty) self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty)
} }
// Comparison: // Comparison:
@ -1052,7 +1062,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
_ => return None, _ => return None,
}; };
if checked { if op.is_overflowing() {
let false_val = self.insert_bool(false); let false_val = self.insert_bool(false);
Some(self.insert_tuple(vec![result, false_val])) Some(self.insert_tuple(vec![result, false_val]))
} else { } else {

View file

@ -965,6 +965,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// if it can then our result is not determined and can be invalidated. // if it can then our result is not determined and can be invalidated.
for single_import in &resolution.single_imports { for single_import in &resolution.single_imports {
let Some(import_vis) = single_import.vis.get() else { let Some(import_vis) = single_import.vis.get() else {
// This branch handles a cycle in single imports, which occurs
// when we've previously captured the `vis` value during an import
// process.
//
// For example:
// ```
// use a::b;
// use b as a;
// ```
// 1. Steal the `vis` in `use a::b` and attempt to locate `a` in the
// current module.
// 2. Encounter the import `use b as a`, which is a `single_import` for `a`,
// and try to find `b` in the current module.
// 3. Re-encounter the `use a::b` import since it's a `single_import` of `b`.
// This leads to entering this branch.
continue; continue;
}; };
if !self.is_accessible_from(import_vis, parent_scope.module) { if !self.is_accessible_from(import_vis, parent_scope.module) {
@ -979,15 +994,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// named imports. // named imports.
continue; continue;
} }
let Some(module) = single_import.imported_module.get() else { let Some(module) = single_import.imported_module.get() else {
return Err((Undetermined, Weak::No)); return Err((Undetermined, Weak::No));
}; };
let ImportKind::Single { source: ident, .. } = single_import.kind else { let ImportKind::Single { source: ident, source_bindings, .. } = &single_import.kind
else {
unreachable!(); unreachable!();
}; };
if binding.map_or(false, |binding| binding.module().is_some())
&& source_bindings.iter().all(|binding| matches!(binding.get(), Err(Undetermined)))
{
// This branch allows the binding to be defined or updated later,
// avoiding module inconsistency between the resolve process and the finalize process.
// See more details in #124840
return Err((Undetermined, Weak::No));
}
match self.resolve_ident_in_module( match self.resolve_ident_in_module(
module, module,
ident, *ident,
ns, ns,
&single_import.parent_scope, &single_import.parent_scope,
None, None,

View file

@ -352,9 +352,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
(old_glob @ true, false) | (old_glob @ false, true) => { (old_glob @ true, false) | (old_glob @ false, true) => {
let (glob_binding, nonglob_binding) = let (glob_binding, nonglob_binding) =
if old_glob { (old_binding, binding) } else { (binding, old_binding) }; if old_glob { (old_binding, binding) } else { (binding, old_binding) };
if glob_binding.res() != nonglob_binding.res() if key.ns == MacroNS
&& key.ns == MacroNS
&& nonglob_binding.expansion != LocalExpnId::ROOT && nonglob_binding.expansion != LocalExpnId::ROOT
&& glob_binding.res() != nonglob_binding.res()
{ {
resolution.binding = Some(this.ambiguity( resolution.binding = Some(this.ambiguity(
AmbiguityKind::GlobVsExpanded, AmbiguityKind::GlobVsExpanded,

View file

@ -924,11 +924,12 @@ where
} }
} }
ty::Alias(kind @ (ty::Projection | ty::Inherent | ty::Weak), ..) => { // A rigid alias may normalize to anything.
if ty.has_type_flags(ty::TypeFlags::HAS_TY_PARAM) { // * If it references an infer var, placeholder or bound ty, it may
bug!("unexpected ty param in alias ty"); // normalize to that, so we have to treat it as an uncovered ty param.
} // * Otherwise it may normalize to any non-type-generic type
// be it local or non-local.
ty::Alias(kind, _) => {
if ty.has_type_flags( if ty.has_type_flags(
ty::TypeFlags::HAS_TY_PLACEHOLDER ty::TypeFlags::HAS_TY_PLACEHOLDER
| ty::TypeFlags::HAS_TY_BOUND | ty::TypeFlags::HAS_TY_BOUND
@ -948,7 +949,24 @@ where
} }
} }
} else { } else {
ControlFlow::Continue(()) // Regarding *opaque types* specifically, we choose to treat them as non-local,
// even those that appear within the same crate. This seems somewhat surprising
// at first, but makes sense when you consider that opaque types are supposed
// to hide the underlying type *within the same crate*. When an opaque type is
// used from outside the module where it is declared, it should be impossible to
// observe anything about it other than the traits that it implements.
//
// The alternative would be to look at the underlying type to determine whether
// or not the opaque type itself should be considered local.
//
// However, this could make it a breaking change to switch the underlying hidden
// type from a local type to a remote type. This would violate the rule that
// opaque types should be completely opaque apart from the traits that they
// implement, so we don't use this behavior.
// Addendum: Moreover, revealing the underlying type is likely to cause cycle
// errors as we rely on coherence / the specialization graph during typeck.
self.found_non_local_ty(ty)
} }
} }
@ -990,35 +1008,6 @@ where
// auto trait impl applies. There will never be multiple impls, so we can just // auto trait impl applies. There will never be multiple impls, so we can just
// act as if it were a local type here. // act as if it were a local type here.
ty::CoroutineWitness(..) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), ty::CoroutineWitness(..) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
ty::Alias(ty::Opaque, ..) => {
// This merits some explanation.
// Normally, opaque types are not involved when performing
// coherence checking, since it is illegal to directly
// implement a trait on an opaque type. However, we might
// end up looking at an opaque type during coherence checking
// if an opaque type gets used within another type (e.g. as
// the type of a field) when checking for auto trait or `Sized`
// impls. This requires us to decide whether or not an opaque
// type should be considered 'local' or not.
//
// We choose to treat all opaque types as non-local, even
// those that appear within the same crate. This seems
// somewhat surprising at first, but makes sense when
// you consider that opaque types are supposed to hide
// the underlying type *within the same crate*. When an
// opaque type is used from outside the module
// where it is declared, it should be impossible to observe
// anything about it other than the traits that it implements.
//
// The alternative would be to look at the underlying type
// to determine whether or not the opaque type itself should
// be considered local. However, this could make it a breaking change
// to switch the underlying ('defining') type from a local type
// to a remote type. This would violate the rule that opaque
// types should be completely opaque apart from the traits
// that they implement, so we don't use this behavior.
self.found_non_local_ty(ty)
}
}; };
// A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so
// the first type we visit is always the self type. // the first type we visit is always the self type.

View file

@ -1190,9 +1190,8 @@ pub trait IsTerminal: crate::sealed::Sealed {
/// ///
/// - If you run this example by piping some text to it, e.g. `echo "foo" | path/to/executable` /// - If you run this example by piping some text to it, e.g. `echo "foo" | path/to/executable`
/// it will print: `Hello foo`. /// it will print: `Hello foo`.
/// - If you instead run the example interactively by running the executable directly, it will /// - If you instead run the example interactively by running `path/to/executable` directly, it will
/// panic with the message "Expected input to be piped to the process". /// prompt for input.
///
/// ///
/// [changes]: io#platform-specific-behavior /// [changes]: io#platform-specific-behavior
/// [`Stdin`]: crate::io::Stdin /// [`Stdin`]: crate::io::Stdin

View file

@ -15,7 +15,7 @@ pub use self::task_queue::JoinNotifier;
mod task_queue { mod task_queue {
use super::wait_notify; use super::wait_notify;
use crate::sync::{Mutex, MutexGuard, Once}; use crate::sync::{Mutex, MutexGuard};
pub type JoinHandle = wait_notify::Waiter; pub type JoinHandle = wait_notify::Waiter;
@ -28,12 +28,12 @@ mod task_queue {
} }
pub(super) struct Task { pub(super) struct Task {
p: Box<dyn FnOnce()>, p: Box<dyn FnOnce() + Send>,
done: JoinNotifier, done: JoinNotifier,
} }
impl Task { impl Task {
pub(super) fn new(p: Box<dyn FnOnce()>) -> (Task, JoinHandle) { pub(super) fn new(p: Box<dyn FnOnce() + Send>) -> (Task, JoinHandle) {
let (done, recv) = wait_notify::new(); let (done, recv) = wait_notify::new();
let done = JoinNotifier(Some(done)); let done = JoinNotifier(Some(done));
(Task { p, done }, recv) (Task { p, done }, recv)
@ -45,18 +45,12 @@ mod task_queue {
} }
} }
#[cfg_attr(test, linkage = "available_externally")]
#[export_name = "_ZN16__rust_internals3std3sys3sgx6thread15TASK_QUEUE_INITE"]
static TASK_QUEUE_INIT: Once = Once::new();
#[cfg_attr(test, linkage = "available_externally")] #[cfg_attr(test, linkage = "available_externally")]
#[export_name = "_ZN16__rust_internals3std3sys3sgx6thread10TASK_QUEUEE"] #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread10TASK_QUEUEE"]
static mut TASK_QUEUE: Option<Mutex<Vec<Task>>> = None; static TASK_QUEUE: Mutex<Vec<Task>> = Mutex::new(Vec::new());
pub(super) fn lock() -> MutexGuard<'static, Vec<Task>> { pub(super) fn lock() -> MutexGuard<'static, Vec<Task>> {
unsafe { TASK_QUEUE.lock().unwrap()
TASK_QUEUE_INIT.call_once(|| TASK_QUEUE = Some(Default::default()));
TASK_QUEUE.as_ref().unwrap().lock().unwrap()
}
} }
} }
@ -101,7 +95,7 @@ pub mod wait_notify {
impl Thread { impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements // unsafe: see thread::Builder::spawn_unchecked for safety requirements
pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce() + Send>) -> io::Result<Thread> {
let mut queue_lock = task_queue::lock(); let mut queue_lock = task_queue::lock();
unsafe { usercalls::launch_thread()? }; unsafe { usercalls::launch_thread()? };
let (task, handle) = task_queue::Task::new(p); let (task, handle) = task_queue::Task::new(p);

View file

@ -561,7 +561,8 @@ impl Builder {
let main = Box::new(main); let main = Box::new(main);
// SAFETY: dynamic size and alignment of the Box remain the same. See below for why the // SAFETY: dynamic size and alignment of the Box remain the same. See below for why the
// lifetime change is justified. // lifetime change is justified.
let main = unsafe { Box::from_raw(Box::into_raw(main) as *mut (dyn FnOnce() + 'static)) }; let main =
unsafe { Box::from_raw(Box::into_raw(main) as *mut (dyn FnOnce() + Send + 'static)) };
Ok(JoinInner { Ok(JoinInner {
// SAFETY: // SAFETY:
@ -1544,7 +1545,7 @@ struct Packet<'scope, T> {
// The type `T` should already always be Send (otherwise the thread could not // The type `T` should already always be Send (otherwise the thread could not
// have been created) and the Packet is Sync because all access to the // have been created) and the Packet is Sync because all access to the
// `UnsafeCell` synchronized (by the `join()` boundary), and `ScopeData` is Sync. // `UnsafeCell` synchronized (by the `join()` boundary), and `ScopeData` is Sync.
unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {} unsafe impl<'scope, T: Send> Sync for Packet<'scope, T> {}
impl<'scope, T> Drop for Packet<'scope, T> { impl<'scope, T> Drop for Packet<'scope, T> {
fn drop(&mut self) { fn drop(&mut self) {

View file

@ -270,7 +270,6 @@ else
args="$args --volume $root_dir:/checkout$SRC_MOUNT_OPTION" args="$args --volume $root_dir:/checkout$SRC_MOUNT_OPTION"
args="$args --volume $objdir:/checkout/obj" args="$args --volume $objdir:/checkout/obj"
args="$args --volume $HOME/.cargo:/cargo" args="$args --volume $HOME/.cargo:/cargo"
args="$args --volume $HOME/rustsrc:$HOME/rustsrc"
args="$args --volume /tmp/toolstate:/tmp/toolstate" args="$args --volume /tmp/toolstate:/tmp/toolstate"
id=$(id -u) id=$(id -u)

View file

@ -61,6 +61,12 @@ envs:
try: try:
<<: *production <<: *production
# The following env var activates faster `try` builds in `opt-dist` by, e.g.
# - building only the more commonly useful components (we rarely need e.g. rust-docs in try
# builds)
# - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain
#
# If you *want* these to happen however, temporarily uncomment it before triggering a try build.
DIST_TRY_BUILD: 1 DIST_TRY_BUILD: 1
auto: auto:

View file

@ -1268,6 +1268,8 @@ fn expand_variables(mut value: String, config: &Config) -> String {
const CWD: &str = "{{cwd}}"; const CWD: &str = "{{cwd}}";
const SRC_BASE: &str = "{{src-base}}"; const SRC_BASE: &str = "{{src-base}}";
const BUILD_BASE: &str = "{{build-base}}"; const BUILD_BASE: &str = "{{build-base}}";
const SYSROOT_BASE: &str = "{{sysroot-base}}";
const TARGET_LINKER: &str = "{{target-linker}}";
if value.contains(CWD) { if value.contains(CWD) {
let cwd = env::current_dir().unwrap(); let cwd = env::current_dir().unwrap();
@ -1282,6 +1284,14 @@ fn expand_variables(mut value: String, config: &Config) -> String {
value = value.replace(BUILD_BASE, &config.build_base.to_string_lossy()); value = value.replace(BUILD_BASE, &config.build_base.to_string_lossy());
} }
if value.contains(SYSROOT_BASE) {
value = value.replace(SYSROOT_BASE, &config.sysroot_base.to_string_lossy());
}
if value.contains(TARGET_LINKER) {
value = value.replace(TARGET_LINKER, config.target_linker.as_deref().unwrap_or(""));
}
value value
} }

View file

@ -83,12 +83,24 @@ fn main() {
test_abi_compat(main as fn(), id::<i32> as fn(i32) -> i32); test_abi_compat(main as fn(), id::<i32> as fn(i32) -> i32);
// - 1-ZST // - 1-ZST
test_abi_compat((), [0u8; 0]); test_abi_compat((), [0u8; 0]);
// - Guaranteed null-pointer-optimizations (RFC 3391). // - Guaranteed Option<X> null-pointer-optimizations (RFC 3391).
test_abi_compat(&0u32 as *const u32, Some(&0u32)); test_abi_compat(&0u32 as *const u32, Some(&0u32));
test_abi_compat(main as fn(), Some(main as fn())); test_abi_compat(main as fn(), Some(main as fn()));
test_abi_compat(0u32, Some(num::NonZero::new(1u32).unwrap())); test_abi_compat(0u32, Some(num::NonZero::new(1u32).unwrap()));
test_abi_compat(&0u32 as *const u32, Some(Wrapper(&0u32))); test_abi_compat(&0u32 as *const u32, Some(Wrapper(&0u32)));
test_abi_compat(0u32, Some(Wrapper(num::NonZero::new(1u32).unwrap()))); test_abi_compat(0u32, Some(Wrapper(num::NonZeroU32::new(1u32).unwrap())));
// - Guaranteed Result<X, ZST1> does the same as Option<X> (RFC 3391)
test_abi_compat(&0u32 as *const u32, Result::<_, ()>::Ok(&0u32));
test_abi_compat(main as fn(), Result::<_, ()>::Ok(main as fn()));
test_abi_compat(0u32, Result::<_, ()>::Ok(num::NonZeroU32::new(1).unwrap()));
test_abi_compat(&0u32 as *const u32, Result::<_, ()>::Ok(Wrapper(&0u32)));
test_abi_compat(0u32, Result::<_, ()>::Ok(Wrapper(num::NonZeroU32::new(1).unwrap())));
// - Guaranteed Result<ZST1, X> also does the same as Option<X> (RFC 3391)
test_abi_compat(&0u32 as *const u32, Result::<(), _>::Err(&0u32));
test_abi_compat(main as fn(), Result::<(), _>::Err(main as fn()));
test_abi_compat(0u32, Result::<(), _>::Err(num::NonZeroU32::new(1).unwrap()));
test_abi_compat(&0u32 as *const u32, Result::<(), _>::Err(Wrapper(&0u32)));
test_abi_compat(0u32, Result::<(), _>::Err(Wrapper(num::NonZeroU32::new(1).unwrap())));
// These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible // These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible
// with the wrapped field. // with the wrapped field.

View file

@ -2445,7 +2445,6 @@ ui/issues/issue-53300.rs
ui/issues/issue-53333.rs ui/issues/issue-53333.rs
ui/issues/issue-53348.rs ui/issues/issue-53348.rs
ui/issues/issue-53419.rs ui/issues/issue-53419.rs
ui/issues/issue-53498.rs
ui/issues/issue-53568.rs ui/issues/issue-53568.rs
ui/issues/issue-5358-1.rs ui/issues/issue-5358-1.rs
ui/issues/issue-53728.rs ui/issues/issue-53728.rs

View file

@ -15,7 +15,7 @@ use std::path::{Path, PathBuf};
const ENTRY_LIMIT: u32 = 900; const ENTRY_LIMIT: u32 = 900;
// FIXME: The following limits should be reduced eventually. // FIXME: The following limits should be reduced eventually.
const ISSUES_ENTRY_LIMIT: u32 = 1674; const ISSUES_ENTRY_LIMIT: u32 = 1672;
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
"rs", // test source files "rs", // test source files

View file

@ -1,16 +0,0 @@
//@ known-bug: rust-lang/rust#124490
use io::{self as std};
use std::collections::{self as io};
mod a {
pub mod b {
pub mod c {}
}
}
use a::*;
use b::c;
use c as b;
fn main() {}

View file

@ -1,5 +0,0 @@
//@ known-bug: rust-lang/rust#125013
//@ edition:2021
use io::{self as std};
use std::ops::Deref::{self as io};
pub fn main() {}

View file

@ -1,16 +0,0 @@
//@ known-bug: rust-lang/rust#125013
//@ edition:2021
mod a {
pub mod b {
pub mod c {
pub trait D {}
}
}
}
use a::*;
use e as b;
use b::c::D as e;
fn main() { }

View file

@ -1,9 +0,0 @@
include ../../run-make/tools.mk
# This test ensures that rustc compile_input can be called twice in one task
# without causing a panic.
# The program needs the path to rustc to get sysroot.
all:
$(RUSTC) foo.rs
$(call RUN,foo $(TMPDIR) $(RUSTC))

View file

@ -1,3 +1,13 @@
//@ edition: 2021
//@ run-pass
//@ run-flags: {{sysroot-base}} {{target-linker}}
//@ ignore-stage1 (requires matching sysroot built with in-tree compiler)
// Regression test for <https://github.com/rust-lang/rust/issues/19371>.
//
// This test ensures that `compile_input` can be called twice in one task
// without causing a panic.
#![feature(rustc_private)] #![feature(rustc_private)]
extern crate rustc_driver; extern crate rustc_driver;
@ -5,12 +15,12 @@ extern crate rustc_interface;
extern crate rustc_session; extern crate rustc_session;
extern crate rustc_span; extern crate rustc_span;
use std::path::{Path, PathBuf};
use rustc_interface::interface; use rustc_interface::interface;
use rustc_session::config::{Input, Options, OutFileName, OutputType, OutputTypes}; use rustc_session::config::{Input, Options, OutFileName, OutputType, OutputTypes};
use rustc_span::FileName; use rustc_span::FileName;
use std::path::PathBuf;
fn main() { fn main() {
let src = r#" let src = r#"
fn main() {} fn main() {}
@ -18,28 +28,28 @@ fn main() {
let args: Vec<String> = std::env::args().collect(); let args: Vec<String> = std::env::args().collect();
if args.len() < 4 { if args.len() < 2 {
panic!("expected rustc path"); panic!("expected sysroot (and optional linker)");
} }
let tmpdir = PathBuf::from(&args[1]); let sysroot = PathBuf::from(&args[1]);
let linker = args.get(2).map(PathBuf::from);
let mut sysroot = PathBuf::from(&args[3]); // compiletest sets the current dir to `output_base_dir` when running.
sysroot.pop(); let tmpdir = std::env::current_dir().unwrap().join("tmp");
sysroot.pop(); std::fs::create_dir_all(&tmpdir).unwrap();
compile(src.to_string(), tmpdir.join("out"), sysroot.clone()); compile(src.to_string(), tmpdir.join("out"), sysroot.clone(), linker.as_deref());
compile(src.to_string(), tmpdir.join("out"), sysroot.clone(), linker.as_deref());
compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
} }
fn compile(code: String, output: PathBuf, sysroot: PathBuf) { fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path>) {
let mut opts = Options::default(); let mut opts = Options::default();
opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
opts.maybe_sysroot = Some(sysroot); opts.maybe_sysroot = Some(sysroot);
if let Ok(linker) = std::env::var("RUSTC_LINKER") { if let Some(linker) = linker {
opts.cg.linker = Some(linker.into()); opts.cg.linker = Some(linker.to_owned());
} }
let name = FileName::anon_source_code(&code); let name = FileName::anon_source_code(&code);

View file

@ -0,0 +1,21 @@
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
--> $DIR/orphan-check-opaque-types-not-covering.rs:17:6
|
LL | impl<T> foreign::Trait0<Local, T, ()> for Identity<T> {}
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
--> $DIR/orphan-check-opaque-types-not-covering.rs:26:6
|
LL | impl<T> foreign::Trait1<Local, T> for Opaque<T> {}
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0210`.

View file

@ -0,0 +1,21 @@
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
--> $DIR/orphan-check-opaque-types-not-covering.rs:17:6
|
LL | impl<T> foreign::Trait0<Local, T, ()> for Identity<T> {}
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
--> $DIR/orphan-check-opaque-types-not-covering.rs:26:6
|
LL | impl<T> foreign::Trait1<Local, T> for Opaque<T> {}
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0210`.

View file

@ -0,0 +1,31 @@
// Opaque types never cover type parameters.
//@ revisions: classic next
//@[next] compile-flags: -Znext-solver
//@ aux-crate:foreign=parametrized-trait.rs
//@ edition:2021
#![feature(type_alias_impl_trait)]
type Identity<T> = impl Sized;
fn define_identity<T>(x: T) -> Identity<T> {
x
}
impl<T> foreign::Trait0<Local, T, ()> for Identity<T> {}
//~^ ERROR type parameter `T` must be covered by another type
type Opaque<T> = impl Sized;
fn define_local<T>() -> Opaque<T> {
Local
}
impl<T> foreign::Trait1<Local, T> for Opaque<T> {}
//~^ ERROR type parameter `T` must be covered by another type
struct Local;
fn main() {}

View file

@ -0,0 +1,14 @@
//@ check-pass
// https://github.com/rust-lang/rust/pull/124840#issuecomment-2098148587
mod a {
pub(crate) use crate::S;
}
mod b {
pub struct S;
}
use self::a::S;
use self::b::*;
fn main() {}

View file

@ -0,0 +1,14 @@
//@ check-pass
// similar `cycle-import-in-diff-module-0.rs`
mod a {
pub(crate) use crate::s;
}
mod b {
pub mod s {}
}
use self::b::*;
use self::a::s;
fn main() {}

View file

@ -0,0 +1,17 @@
// https://github.com/rust-lang/rust/issues/124490
mod a {
pub mod b {
pub mod c {}
}
}
use a::*;
use b::c;
//~^ ERROR: cannot determine resolution for the import
//~| ERROR: cannot determine resolution for the import
//~| ERROR: unresolved import `b::c`
use c as b;
fn main() {}

View file

@ -0,0 +1,23 @@
error: cannot determine resolution for the import
--> $DIR/shadow-glob-module-resolution-1.rs:11:5
|
LL | use b::c;
| ^^^^
error: cannot determine resolution for the import
--> $DIR/shadow-glob-module-resolution-1.rs:11:5
|
LL | use b::c;
| ^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0432]: unresolved import `b::c`
--> $DIR/shadow-glob-module-resolution-1.rs:11:5
|
LL | use b::c;
| ^^^^
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0432`.

View file

@ -0,0 +1,19 @@
// https://github.com/rust-lang/rust/issues/125013
mod a {
pub mod b {
pub mod c {
pub trait D {}
}
}
}
use a::*;
use e as b;
//~^ ERROR: unresolved import `e`
use b::c::D as e;
//~^ ERROR: cannot determine resolution for the import
//~| ERROR: cannot determine resolution for the import
fn main() { }

View file

@ -0,0 +1,26 @@
error: cannot determine resolution for the import
--> $DIR/shadow-glob-module-resolution-2.rs:15:5
|
LL | use b::c::D as e;
| ^^^^^^^^^^^^
error: cannot determine resolution for the import
--> $DIR/shadow-glob-module-resolution-2.rs:15:5
|
LL | use b::c::D as e;
| ^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0432]: unresolved import `e`
--> $DIR/shadow-glob-module-resolution-2.rs:13:5
|
LL | use e as b;
| -^^^^^
| |
| no `e` in the root
| help: a similar name exists in the module: `a`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0432`.

View file

@ -1,17 +0,0 @@
pub mod test {
pub struct A;
pub struct B;
pub struct Foo<T>(T);
impl Foo<A> {
fn foo() {}
}
impl Foo<B> {
fn foo() {}
}
}
fn main() {
test::Foo::<test::B>::foo(); //~ ERROR associated function `foo` is private
}

View file

@ -0,0 +1,15 @@
error[E0599]: no function or associated item named `foo` found for struct `Foo<B>` in the current scope
--> $DIR/ufc-method-call.rs:27:27
|
LL | pub struct Foo<T>(T);
| ----------------- function or associated item `foo` not found for this struct
...
LL | test::Foo::<test::B>::foo();
| ^^^ function or associated item not found in `Foo<B>`
|
= note: the function or associated item was found for
- `Foo<A>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.

View file

@ -0,0 +1,30 @@
//! This test used to report that the method call cannot
//! call the private method `Foo<A>::foo`, even though the user
//! explicitly selected `Foo<B>::foo`. This is because we only
//! looked for methods of the right name, without properly checking
//! the `Self` type
//@ revisions: same_name different_name
pub mod test {
pub struct A;
pub struct B;
pub struct Foo<T>(T);
impl Foo<A> {
fn foo() {}
}
impl Foo<B> {
#[cfg(same_name)]
fn foo() {}
#[cfg(different_name)]
fn bar() {}
}
}
fn main() {
test::Foo::<test::B>::foo();
//[same_name]~^ ERROR associated function `foo` is private
//[different_name]~^^ ERROR no function or associated item named `foo` found for struct `Foo<B>`
}

View file

@ -1,5 +1,5 @@
error[E0624]: associated function `foo` is private error[E0624]: associated function `foo` is private
--> $DIR/issue-53498.rs:16:27 --> $DIR/ufc-method-call.rs:27:27
| |
LL | fn foo() {} LL | fn foo() {}
| -------- private associated function defined here | -------- private associated function defined here

View file

@ -1,5 +1,5 @@
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence.rs:14:1 --> $DIR/coherence.rs:16:1
| |
LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {} LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------

View file

@ -0,0 +1,14 @@
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence.rs:16:1
|
LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------
| | |
| | `AliasOfForeignType<()>` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0117`.

View file

@ -1,4 +1,6 @@
//@ aux-build:foreign-crate.rs //@ aux-build:foreign-crate.rs
//@ revisions: classic next
//@[next] compile-flags: -Znext-solver
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
extern crate foreign_crate; extern crate foreign_crate;