Auto merge of #147662 - Zalathar:rollup-j8ci0f2, r=Zalathar

Rollup of 12 pull requests

Successful merges:

 - rust-lang/rust#146277 (Enable `u64` limbs in `core::num::bignum`)
 - rust-lang/rust#146976 (constify basic Clone impls)
 - rust-lang/rust#147249 (Do two passes of `handle_opaque_type_uses_next`)
 - rust-lang/rust#147266 (fix 2 search graph bugs)
 - rust-lang/rust#147497 (`proc_macro` cleanups (3/N))
 - rust-lang/rust#147546 (Suppress unused_parens for labeled break)
 - rust-lang/rust#147548 (Fix ICE for never pattern as closure parameters)
 - rust-lang/rust#147594 (std: implement `pal::os::exit` for VEXos)
 - rust-lang/rust#147596 (Adjust the Arm targets in CI to reflect latest changes)
 - rust-lang/rust#147607 (GVN: Invalidate derefs at loop headers)
 - rust-lang/rust#147620 (Avoid redundant UB check in RangeFrom slice indexing)
 - rust-lang/rust#147647 (Hide vendoring and copyright in GHA group)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-10-14 12:32:31 +00:00
commit e100792918
37 changed files with 611 additions and 151 deletions

View file

@ -155,13 +155,6 @@ fn add_hidden_type<'tcx>(
}
}
fn get_hidden_type<'tcx>(
hidden_types: &DefinitionSiteHiddenTypes<'tcx>,
def_id: LocalDefId,
) -> Option<EarlyBinder<'tcx, OpaqueHiddenType<'tcx>>> {
hidden_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty))
}
#[derive(Debug)]
struct DefiningUse<'tcx> {
/// The opaque type using non NLL vars. This uses the actual
@ -508,7 +501,8 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
let tcx = infcx.tcx;
let mut errors = Vec::new();
for &(key, hidden_type) in opaque_types {
let Some(expected) = get_hidden_type(hidden_types, key.def_id) else {
let Some(expected) = hidden_types.0.get(&key.def_id).map(|ty| EarlyBinder::bind(*ty))
else {
if !tcx.use_typing_mode_borrowck() {
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
&& alias_ty.def_id == key.def_id.to_def_id()

View file

@ -1817,12 +1817,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let element_ty = if !args.is_empty() {
// This shouldn't happen unless there's another error
// (e.g., never patterns in inappropriate contexts).
if self.diverges.get() != Diverges::Maybe {
self.dcx()
.struct_span_err(expr.span, "unexpected divergence state in checking array")
.delay_as_bug();
}
let coerce_to = expected
.to_option(self)
.and_then(|uty| self.try_structurally_resolve_type(expr.span, uty).builtin_index())
.unwrap_or_else(|| self.next_ty_var(expr.span));
let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args);
assert_eq!(self.diverges.get(), Diverges::Maybe);
for e in args {
let e_ty = self.check_expr_with_hint(e, coerce_to);
let cause = self.misc(e.span);

View file

@ -104,8 +104,8 @@ pub(crate) struct FnCtxt<'a, 'tcx> {
/// the diverges flag is set to something other than `Maybe`.
pub(super) diverges: Cell<Diverges>,
/// If one of the function arguments is a never pattern, this counts as diverging code. This
/// affect typechecking of the function body.
/// If one of the function arguments is a never pattern, this counts as diverging code.
/// This affect typechecking of the function body.
pub(super) function_diverges_because_of_empty_arguments: Cell<Diverges>,
/// Whether the currently checked node is the whole body of the function.

View file

@ -219,6 +219,12 @@ fn typeck_with_inspect<'tcx>(
// the future.
fcx.check_repeat_exprs();
// We need to handle opaque types before emitting ambiguity errors as applying
// defining uses may guide type inference.
if fcx.next_trait_solver() {
fcx.try_handle_opaque_type_uses_next();
}
fcx.type_inference_fallback();
// Even though coercion casts provide type hints, we check casts after fallback for

View file

@ -22,35 +22,50 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
/// inference variables.
///
/// It then uses these defining uses to guide inference for all other uses.
///
/// Unlike `handle_opaque_type_uses_next`, this does not report errors.
#[instrument(level = "debug", skip(self))]
pub(super) fn try_handle_opaque_type_uses_next(&mut self) {
// We clone the opaques instead of stealing them here as we still need
// to use them after fallback.
let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
self.compute_definition_site_hidden_types(opaque_types, false);
}
/// This takes all the opaque type uses during HIR typeck. It first computes
/// the concrete hidden type by iterating over all defining uses.
///
/// A use during HIR typeck is defining if all non-lifetime arguments are
/// unique generic parameters and the hidden type does not reference any
/// inference variables.
///
/// It then uses these defining uses to guide inference for all other uses.
#[instrument(level = "debug", skip(self))]
pub(super) fn handle_opaque_type_uses_next(&mut self) {
// We clone the opaques instead of stealing them here as they are still used for
// normalization in the next generation trait solver.
let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types();
let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
let num_entries = self.inner.borrow_mut().opaque_types().num_entries();
let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries));
debug_assert_eq!(prev, None);
for entry in &mut opaque_types {
*entry = self.resolve_vars_if_possible(*entry);
}
debug!(?opaque_types);
self.compute_definition_site_hidden_types(&opaque_types);
self.apply_definition_site_hidden_types(&opaque_types);
self.compute_definition_site_hidden_types(opaque_types, true);
}
}
#[derive(Copy, Clone, Debug)]
enum UsageKind<'tcx> {
None,
NonDefiningUse(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>),
UnconstrainedHiddenType(OpaqueHiddenType<'tcx>),
HasDefiningUse,
HasDefiningUse(OpaqueHiddenType<'tcx>),
}
impl<'tcx> UsageKind<'tcx> {
fn merge(&mut self, other: UsageKind<'tcx>) {
match (&*self, &other) {
(UsageKind::HasDefiningUse, _) | (_, UsageKind::None) => unreachable!(),
(UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(),
(UsageKind::None, _) => *self = other,
// When mergining non-defining uses, prefer earlier ones. This means
// the error happens as early as possible.
@ -64,7 +79,7 @@ impl<'tcx> UsageKind<'tcx> {
// intended to be defining.
(
UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse,
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_),
) => *self = other,
}
}
@ -73,8 +88,14 @@ impl<'tcx> UsageKind<'tcx> {
impl<'tcx> FnCtxt<'_, 'tcx> {
fn compute_definition_site_hidden_types(
&mut self,
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
mut opaque_types: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>,
error_on_missing_defining_use: bool,
) {
for entry in opaque_types.iter_mut() {
*entry = self.resolve_vars_if_possible(*entry);
}
debug!(?opaque_types);
let tcx = self.tcx;
let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
else {
@ -88,19 +109,47 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
_ => unreachable!("not opaque or generator: {def_id:?}"),
}
// We do actually need to check this the second pass (we can't just
// store this), because we can go from `UnconstrainedHiddenType` to
// `HasDefiningUse` (because of fallback)
let mut usage_kind = UsageKind::None;
for &(opaque_type_key, hidden_type) in opaque_types {
for &(opaque_type_key, hidden_type) in &opaque_types {
if opaque_type_key.def_id != def_id {
continue;
}
usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
if let UsageKind::HasDefiningUse = usage_kind {
if let UsageKind::HasDefiningUse(..) = usage_kind {
break;
}
}
if let UsageKind::HasDefiningUse(ty) = usage_kind {
for &(opaque_type_key, hidden_type) in &opaque_types {
if opaque_type_key.def_id != def_id {
continue;
}
let expected = EarlyBinder::bind(ty.ty).instantiate(tcx, opaque_type_key.args);
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
}
// Being explicit here: it may be possible that we in a
// previous call to this function we did an insert, but this
// should be just fine, since they all get equated anyways and
// we shouldn't ever go from `HasDefiningUse` to anyway else.
let _ = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty);
}
// If we're in `fn try_handle_opaque_type_uses_next` then do not
// report any errors.
if !error_on_missing_defining_use {
continue;
}
let guar = match usage_kind {
UsageKind::HasDefiningUse(_) => continue,
UsageKind::None => {
if let Some(guar) = self.tainted_by_errors() {
guar
@ -137,7 +186,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
.emit()
}
}
UsageKind::HasDefiningUse => continue,
};
self.typeck_results
@ -148,8 +196,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
}
}
#[tracing::instrument(skip(self), ret)]
fn consider_opaque_type_use(
&mut self,
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
hidden_type: OpaqueHiddenType<'tcx>,
) -> UsageKind<'tcx> {
@ -161,11 +210,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
) {
match err {
NonDefiningUseReason::Tainted(guar) => {
self.typeck_results.borrow_mut().hidden_types.insert(
opaque_type_key.def_id,
OpaqueHiddenType::new_error(self.tcx, guar),
);
return UsageKind::HasDefiningUse;
return UsageKind::HasDefiningUse(OpaqueHiddenType::new_error(self.tcx, guar));
}
_ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
};
@ -193,27 +238,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
self.tcx,
DefiningScopeKind::HirTypeck,
);
let prev = self
.typeck_results
.borrow_mut()
.hidden_types
.insert(opaque_type_key.def_id, hidden_type);
assert!(prev.is_none());
UsageKind::HasDefiningUse
}
fn apply_definition_site_hidden_types(
&mut self,
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
) {
let tcx = self.tcx;
for &(key, hidden_type) in opaque_types {
let expected = *self.typeck_results.borrow_mut().hidden_types.get(&key.def_id).unwrap();
let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args);
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
}
UsageKind::HasDefiningUse(hidden_type)
}
/// We may in theory add further uses of an opaque after cloning the opaque

View file

@ -914,7 +914,16 @@ trait UnusedDelimLint {
(value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true)
}
Break(_, Some(ref value)) => {
Break(label, Some(ref value)) => {
// Don't lint on `break 'label ({...})` - the parens are necessary
// to disambiguate from `break 'label {...}` which would be a syntax error.
// This avoids conflicts with the `break_with_label_and_loop` lint.
if label.is_some()
&& matches!(value.kind, ast::ExprKind::Paren(ref inner)
if matches!(inner.kind, ast::ExprKind::Block(..)))
{
return;
}
(value, UnusedDelimsCtx::BreakValue, false, None, None, true)
}

View file

@ -0,0 +1,29 @@
use rustc_index::bit_set::DenseBitSet;
use super::*;
/// Compute the set of loop headers in the given body. A loop header is usually defined as a block
/// which dominates one of its predecessors. This definition is only correct for reducible CFGs.
/// However, computing dominators is expensive, so we approximate according to the post-order
/// traversal order. A loop header for us is a block which is visited after its predecessor in
/// post-order. This is ok as we mostly need a heuristic.
pub fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len());
let mut visited = DenseBitSet::new_empty(body.basic_blocks.len());
for (bb, bbdata) in traversal::postorder(body) {
// Post-order means we visit successors before the block for acyclic CFGs.
// If the successor is not visited yet, consider it a loop header.
for succ in bbdata.terminator().successors() {
if !visited.contains(succ) {
maybe_loop_headers.insert(succ);
}
}
// Only mark `bb` as visited after we checked the successors, in case we have a self-loop.
// bb1: goto -> bb1;
let _new = visited.insert(bb);
debug_assert!(_new);
}
maybe_loop_headers
}

View file

@ -51,6 +51,7 @@ mod statement;
mod syntax;
mod terminator;
pub mod loops;
pub mod traversal;
pub mod visit;

View file

@ -129,6 +129,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
let ssa = SsaLocals::new(tcx, body, typing_env);
// Clone dominators because we need them while mutating the body.
let dominators = body.basic_blocks.dominators().clone();
let maybe_loop_headers = loops::maybe_loop_headers(body);
let arena = DroplessArena::default();
let mut state =
@ -141,6 +142,11 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec();
for bb in reverse_postorder {
// N.B. With loops, reverse postorder cannot produce a valid topological order.
// A statement or terminator from inside the loop, that is not processed yet, may have performed an indirect write.
if maybe_loop_headers.contains(bb) {
state.invalidate_derefs();
}
let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb];
state.visit_basic_block_data(bb, data);
}

View file

@ -84,7 +84,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
body,
arena,
map: Map::new(tcx, body, Some(MAX_PLACES)),
maybe_loop_headers: maybe_loop_headers(body),
maybe_loop_headers: loops::maybe_loop_headers(body),
opportunities: Vec::new(),
};
@ -830,29 +830,3 @@ enum Update {
Incr,
Decr,
}
/// Compute the set of loop headers in the given body. A loop header is usually defined as a block
/// which dominates one of its predecessors. This definition is only correct for reducible CFGs.
/// However, computing dominators is expensive, so we approximate according to the post-order
/// traversal order. A loop header for us is a block which is visited after its predecessor in
/// post-order. This is ok as we mostly need a heuristic.
fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len());
let mut visited = DenseBitSet::new_empty(body.basic_blocks.len());
for (bb, bbdata) in traversal::postorder(body) {
// Post-order means we visit successors before the block for acyclic CFGs.
// If the successor is not visited yet, consider it a loop header.
for succ in bbdata.terminator().successors() {
if !visited.contains(succ) {
maybe_loop_headers.insert(succ);
}
}
// Only mark `bb` as visited after we checked the successors, in case we have a self-loop.
// bb1: goto -> bb1;
let _new = visited.insert(bb);
debug_assert!(_new);
}
maybe_loop_headers
}

View file

@ -99,19 +99,23 @@ where
response_no_constraints(cx, input, Certainty::overflow(false))
}
fn is_ambiguous_result(result: QueryResult<I>) -> bool {
result.is_ok_and(|response| {
has_no_inference_or_external_constraints(response)
fn is_ambiguous_result(result: QueryResult<I>) -> Option<Certainty> {
result.ok().and_then(|response| {
if has_no_inference_or_external_constraints(response)
&& matches!(response.value.certainty, Certainty::Maybe { .. })
{
Some(response.value.certainty)
} else {
None
}
})
}
fn propagate_ambiguity(
cx: I,
for_input: CanonicalInput<I>,
from_result: QueryResult<I>,
certainty: Certainty,
) -> QueryResult<I> {
let certainty = from_result.unwrap().value.certainty;
response_no_constraints(cx, for_input, certainty)
}

View file

@ -11,7 +11,7 @@ use crate::inherent::*;
use crate::ir_print::IrPrint;
use crate::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
use crate::relate::Relate;
use crate::solve::{CanonicalInput, ExternalConstraintsData, QueryResult, inspect};
use crate::solve::{CanonicalInput, Certainty, ExternalConstraintsData, QueryResult, inspect};
use crate::visit::{Flags, TypeVisitable};
use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph};
@ -550,6 +550,7 @@ impl<T, R, E> CollectAndApply<T, R> for Result<T, E> {
impl<I: Interner> search_graph::Cx for I {
type Input = CanonicalInput<I>;
type Result = QueryResult<I>;
type AmbiguityInfo = Certainty;
type DepNodeIndex = I::DepNodeIndex;
type Tracked<T: Debug + Clone> = I::Tracked<T>;

View file

@ -40,6 +40,7 @@ pub use global_cache::GlobalCache;
pub trait Cx: Copy {
type Input: Debug + Eq + Hash + Copy;
type Result: Debug + Eq + Hash + Copy;
type AmbiguityInfo: Debug + Eq + Hash + Copy;
type DepNodeIndex;
type Tracked<T: Debug + Clone>: Debug;
@ -96,11 +97,13 @@ pub trait Delegate: Sized {
input: <Self::Cx as Cx>::Input,
) -> <Self::Cx as Cx>::Result;
fn is_ambiguous_result(result: <Self::Cx as Cx>::Result) -> bool;
fn is_ambiguous_result(
result: <Self::Cx as Cx>::Result,
) -> Option<<Self::Cx as Cx>::AmbiguityInfo>;
fn propagate_ambiguity(
cx: Self::Cx,
for_input: <Self::Cx as Cx>::Input,
from_result: <Self::Cx as Cx>::Result,
ambiguity_info: <Self::Cx as Cx>::AmbiguityInfo,
) -> <Self::Cx as Cx>::Result;
fn compute_goal(
@ -913,9 +916,9 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
/// heads from the stack. This may not necessarily mean that we've actually
/// reached a fixpoint for that cycle head, which impacts the way we rebase
/// provisional cache entries.
enum RebaseReason {
enum RebaseReason<X: Cx> {
NoCycleUsages,
Ambiguity,
Ambiguity(X::AmbiguityInfo),
Overflow,
/// We've actually reached a fixpoint.
///
@ -951,7 +954,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
&mut self,
cx: X,
stack_entry: &StackEntry<X>,
rebase_reason: RebaseReason,
rebase_reason: RebaseReason<X>,
) {
let popped_head_index = self.stack.next_index();
#[allow(rustc::potential_query_instability)]
@ -969,10 +972,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
return true;
};
let Some(new_highest_head_index) = heads.opt_highest_cycle_head_index() else {
return false;
};
// We're rebasing an entry `e` over a head `p`. This head
// has a number of own heads `h` it depends on.
//
@ -1033,8 +1032,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
// is not actually equal to the final provisional result. We
// need to discard the provisional cache entry in this case.
RebaseReason::NoCycleUsages => return false,
RebaseReason::Ambiguity => {
*result = D::propagate_ambiguity(cx, input, *result);
RebaseReason::Ambiguity(info) => {
*result = D::propagate_ambiguity(cx, input, info);
}
RebaseReason::Overflow => *result = D::fixpoint_overflow_result(cx, input),
RebaseReason::ReachedFixpoint(None) => {}
@ -1046,6 +1045,10 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
};
}
let Some(new_highest_head_index) = heads.opt_highest_cycle_head_index() else {
return false;
};
// We now care about the path from the next highest cycle head to the
// provisional cache entry.
*path_from_head = path_from_head.extend(Self::cycle_path_kind(
@ -1268,6 +1271,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
}
/// Whether we've reached a fixpoint when evaluating a cycle head.
#[instrument(level = "trace", skip(self, stack_entry), ret)]
fn reached_fixpoint(
&mut self,
stack_entry: &StackEntry<X>,
@ -1355,8 +1359,12 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
// As we only get to this branch if we haven't yet reached a fixpoint,
// we also taint all provisional cache entries which depend on the
// current goal.
if D::is_ambiguous_result(result) {
self.rebase_provisional_cache_entries(cx, &stack_entry, RebaseReason::Ambiguity);
if let Some(info) = D::is_ambiguous_result(result) {
self.rebase_provisional_cache_entries(
cx,
&stack_entry,
RebaseReason::Ambiguity(info),
);
return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
};

View file

@ -575,7 +575,8 @@ mod impls {
($($t:ty)*) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for $t {
#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
impl const Clone for $t {
#[inline(always)]
fn clone(&self) -> Self {
*self
@ -593,7 +594,8 @@ mod impls {
}
#[unstable(feature = "never_type", issue = "35121")]
impl Clone for ! {
#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
impl const Clone for ! {
#[inline]
fn clone(&self) -> Self {
*self
@ -601,7 +603,8 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PointeeSized> Clone for *const T {
#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
impl<T: PointeeSized> const Clone for *const T {
#[inline(always)]
fn clone(&self) -> Self {
*self
@ -609,7 +612,8 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PointeeSized> Clone for *mut T {
#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
impl<T: PointeeSized> const Clone for *mut T {
#[inline(always)]
fn clone(&self) -> Self {
*self
@ -618,7 +622,8 @@ mod impls {
/// Shared references can be cloned, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PointeeSized> Clone for &T {
#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
impl<T: PointeeSized> const Clone for &T {
#[inline(always)]
#[rustc_diagnostic_item = "noop_method_clone"]
fn clone(&self) -> Self {

View file

@ -59,8 +59,7 @@ impl_full_ops! {
u8: add(intrinsics::u8_add_with_overflow), mul/div(u16);
u16: add(intrinsics::u16_add_with_overflow), mul/div(u32);
u32: add(intrinsics::u32_add_with_overflow), mul/div(u64);
// See RFC #521 for enabling this.
// u64: add(intrinsics::u64_add_with_overflow), mul/div(u128);
u64: add(intrinsics::u64_add_with_overflow), mul/div(u128);
}
/// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32} value

View file

@ -564,7 +564,10 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
slice_index_fail(self.start, slice.len(), slice.len())
}
// SAFETY: `self` is checked to be valid and in bounds above.
unsafe { &*self.get_unchecked(slice) }
unsafe {
let new_len = crate::intrinsics::unchecked_sub(slice.len(), self.start);
&*get_offset_len_noubcheck(slice, self.start, new_len)
}
}
#[inline]
@ -573,7 +576,10 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
slice_index_fail(self.start, slice.len(), slice.len())
}
// SAFETY: `self` is checked to be valid and in bounds above.
unsafe { &mut *self.get_unchecked_mut(slice) }
unsafe {
let new_len = crate::intrinsics::unchecked_sub(slice.len(), self.start);
&mut *get_offset_len_mut_noubcheck(slice, self.start, new_len)
}
}
}

View file

@ -58,7 +58,7 @@ macro_rules! define_client_handles {
}
}
impl<S> DecodeMut<'_, '_, S> for $oty {
impl<S> Decode<'_, '_, S> for $oty {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
$oty {
handle: handle::Handle::decode(r, s),
@ -82,7 +82,7 @@ macro_rules! define_client_handles {
}
}
impl<S> DecodeMut<'_, '_, S> for $ity {
impl<S> Decode<'_, '_, S> for $ity {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
$ity {
handle: handle::Handle::decode(r, s),
@ -276,7 +276,7 @@ fn maybe_install_panic_hook(force_show_panics: bool) {
/// Client-side helper for handling client panics, entering the bridge,
/// deserializing input and serializing output.
// FIXME(eddyb) maybe replace `Bridge::enter` with this?
fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
fn run_client<A: for<'a, 's> Decode<'a, 's, ()>, R: Encode<()>>(
config: BridgeConfig<'_>,
f: impl FnOnce(A) -> R,
) -> Buffer {

View file

@ -143,7 +143,7 @@ mod symbol;
use buffer::Buffer;
pub use rpc::PanicMessage;
use rpc::{DecodeMut, Encode, Reader, Writer};
use rpc::{Decode, Encode, Reader, Writer};
/// Configuration for establishing an active connection between a server and a
/// client. The server creates the bridge config (`run_server` in `server.rs`),
@ -168,7 +168,7 @@ impl !Sync for BridgeConfig<'_> {}
#[forbid(unsafe_code)]
#[allow(non_camel_case_types)]
mod api_tags {
use super::rpc::{DecodeMut, Encode, Reader, Writer};
use super::rpc::{Decode, Encode, Reader, Writer};
macro_rules! declare_tags {
($($name:ident {

View file

@ -12,7 +12,7 @@ pub(super) trait Encode<S>: Sized {
pub(super) type Reader<'a> = &'a [u8];
pub(super) trait DecodeMut<'a, 's, S>: Sized {
pub(super) trait Decode<'a, 's, S>: Sized {
fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self;
}
@ -24,7 +24,7 @@ macro_rules! rpc_encode_decode {
}
}
impl<S> DecodeMut<'_, '_, S> for $ty {
impl<S> Decode<'_, '_, S> for $ty {
fn decode(r: &mut Reader<'_>, _: &mut S) -> Self {
const N: usize = size_of::<$ty>();
@ -43,12 +43,12 @@ macro_rules! rpc_encode_decode {
}
}
impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S>
impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S>
for $name $(<$($T),+>)?
{
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
$name {
$($field: DecodeMut::decode(r, s)),*
$($field: Decode::decode(r, s)),*
}
}
}
@ -58,23 +58,18 @@ macro_rules! rpc_encode_decode {
fn encode(self, w: &mut Writer, s: &mut S) {
// HACK(eddyb): `Tag` enum duplicated between the
// two impls as there's no other place to stash it.
#[allow(non_upper_case_globals)]
mod tag {
#[repr(u8)] enum Tag { $($variant),* }
$(pub(crate) const $variant: u8 = Tag::$variant as u8;)*
}
#[repr(u8)] enum Tag { $($variant),* }
match self {
$($name::$variant $(($field))* => {
tag::$variant.encode(w, s);
(Tag::$variant as u8).encode(w, s);
$($field.encode(w, s);)*
})*
}
}
}
impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S>
impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S>
for $name $(<$($T),+>)?
{
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
@ -89,7 +84,7 @@ macro_rules! rpc_encode_decode {
match u8::decode(r, s) {
$(tag::$variant => {
$(let $field = DecodeMut::decode(r, s);)*
$(let $field = Decode::decode(r, s);)*
$name::$variant $(($field))*
})*
_ => unreachable!(),
@ -103,7 +98,7 @@ impl<S> Encode<S> for () {
fn encode(self, _: &mut Writer, _: &mut S) {}
}
impl<S> DecodeMut<'_, '_, S> for () {
impl<S> Decode<'_, '_, S> for () {
fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {}
}
@ -113,7 +108,7 @@ impl<S> Encode<S> for u8 {
}
}
impl<S> DecodeMut<'_, '_, S> for u8 {
impl<S> Decode<'_, '_, S> for u8 {
fn decode(r: &mut Reader<'_>, _: &mut S) -> Self {
let x = r[0];
*r = &r[1..];
@ -130,7 +125,7 @@ impl<S> Encode<S> for bool {
}
}
impl<S> DecodeMut<'_, '_, S> for bool {
impl<S> Decode<'_, '_, S> for bool {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
match u8::decode(r, s) {
0 => false,
@ -146,7 +141,7 @@ impl<S> Encode<S> for char {
}
}
impl<S> DecodeMut<'_, '_, S> for char {
impl<S> Decode<'_, '_, S> for char {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
char::from_u32(u32::decode(r, s)).unwrap()
}
@ -158,7 +153,7 @@ impl<S> Encode<S> for NonZero<u32> {
}
}
impl<S> DecodeMut<'_, '_, S> for NonZero<u32> {
impl<S> Decode<'_, '_, S> for NonZero<u32> {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
Self::new(u32::decode(r, s)).unwrap()
}
@ -171,11 +166,11 @@ impl<S, A: Encode<S>, B: Encode<S>> Encode<S> for (A, B) {
}
}
impl<'a, S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S>
impl<'a, S, A: for<'s> Decode<'a, 's, S>, B: for<'s> Decode<'a, 's, S>> Decode<'a, '_, S>
for (A, B)
{
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
(DecodeMut::decode(r, s), DecodeMut::decode(r, s))
(Decode::decode(r, s), Decode::decode(r, s))
}
}
@ -186,7 +181,7 @@ impl<S> Encode<S> for &[u8] {
}
}
impl<'a, S> DecodeMut<'a, '_, S> for &'a [u8] {
impl<'a, S> Decode<'a, '_, S> for &'a [u8] {
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
let len = usize::decode(r, s);
let xs = &r[..len];
@ -201,7 +196,7 @@ impl<S> Encode<S> for &str {
}
}
impl<'a, S> DecodeMut<'a, '_, S> for &'a str {
impl<'a, S> Decode<'a, '_, S> for &'a str {
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
str::from_utf8(<&[u8]>::decode(r, s)).unwrap()
}
@ -213,7 +208,7 @@ impl<S> Encode<S> for String {
}
}
impl<S> DecodeMut<'_, '_, S> for String {
impl<S> Decode<'_, '_, S> for String {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
<&str>::decode(r, s).to_string()
}
@ -228,7 +223,7 @@ impl<S, T: Encode<S>> Encode<S> for Vec<T> {
}
}
impl<'a, S, T: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> for Vec<T> {
impl<'a, S, T: for<'s> Decode<'a, 's, S>> Decode<'a, '_, S> for Vec<T> {
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
let len = usize::decode(r, s);
let mut vec = Vec::with_capacity(len);
@ -288,7 +283,7 @@ impl<S> Encode<S> for PanicMessage {
}
}
impl<S> DecodeMut<'_, '_, S> for PanicMessage {
impl<S> Decode<'_, '_, S> for PanicMessage {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
match Option::<String>::decode(r, s) {
Some(s) => PanicMessage::String(s),

View file

@ -50,7 +50,7 @@ macro_rules! define_reify_functions {
>(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty {
// FIXME(eddyb) describe the `F` type (e.g. via `type_name::<F>`) once panic
// formatting becomes possible in `const fn`.
assert!(size_of::<F>() == 0, "selfless_reify: closure must be zero-sized");
const { assert!(size_of::<F>() == 0, "selfless_reify: closure must be zero-sized"); }
$(extern $abi)? fn wrapper<
$($($param,)*)?

View file

@ -32,7 +32,7 @@ macro_rules! define_server_handles {
}
}
impl<S: Types> DecodeMut<'_, '_, HandleStore<MarkedTypes<S>>>
impl<S: Types> Decode<'_, '_, HandleStore<MarkedTypes<S>>>
for Marked<S::$oty, client::$oty>
{
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<MarkedTypes<S>>) -> Self {
@ -40,7 +40,7 @@ macro_rules! define_server_handles {
}
}
impl<'s, S: Types> DecodeMut<'_, 's, HandleStore<MarkedTypes<S>>>
impl<'s, S: Types> Decode<'_, 's, HandleStore<MarkedTypes<S>>>
for &'s Marked<S::$oty, client::$oty>
{
fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore<MarkedTypes<S>>) -> Self {
@ -48,7 +48,7 @@ macro_rules! define_server_handles {
}
}
impl<'s, S: Types> DecodeMut<'_, 's, HandleStore<MarkedTypes<S>>>
impl<'s, S: Types> Decode<'_, 's, HandleStore<MarkedTypes<S>>>
for &'s mut Marked<S::$oty, client::$oty>
{
fn decode(
@ -67,7 +67,7 @@ macro_rules! define_server_handles {
}
}
impl<S: Types> DecodeMut<'_, '_, HandleStore<MarkedTypes<S>>>
impl<S: Types> Decode<'_, '_, HandleStore<MarkedTypes<S>>>
for Marked<S::$ity, client::$ity>
{
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<MarkedTypes<S>>) -> Self {
@ -355,7 +355,7 @@ pub trait MessagePipe<T>: Sized {
fn run_server<
S: Server,
I: Encode<HandleStore<MarkedTypes<S>>>,
O: for<'a, 's> DecodeMut<'a, 's, HandleStore<MarkedTypes<S>>>,
O: for<'a, 's> Decode<'a, 's, HandleStore<MarkedTypes<S>>>,
>(
strategy: &impl ExecutionStrategy,
handle_counters: &'static client::HandleCounters,

View file

@ -102,7 +102,7 @@ impl<S> Encode<S> for Symbol {
}
}
impl<S: server::Server> DecodeMut<'_, '_, server::HandleStore<server::MarkedTypes<S>>>
impl<S: server::Server> Decode<'_, '_, server::HandleStore<server::MarkedTypes<S>>>
for Marked<S::Symbol, Symbol>
{
fn decode(r: &mut Reader<'_>, s: &mut server::HandleStore<server::MarkedTypes<S>>) -> Self {
@ -118,7 +118,7 @@ impl<S: server::Server> Encode<server::HandleStore<server::MarkedTypes<S>>>
}
}
impl<S> DecodeMut<'_, '_, S> for Symbol {
impl<S> Decode<'_, '_, S> for Symbol {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
Symbol::new(<&str>::decode(r, s))
}

View file

@ -1,4 +1,3 @@
#[path = "../unsupported/os.rs"]
pub mod os;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;

View file

@ -0,0 +1,19 @@
#[expect(dead_code)]
#[path = "../unsupported/os.rs"]
mod unsupported_os;
pub use unsupported_os::{
JoinPathsError, SplitPaths, chdir, current_exe, errno, error_string, getcwd, getpid, home_dir,
join_paths, split_paths, temp_dir,
};
pub use super::unsupported;
pub fn exit(_code: i32) -> ! {
unsafe {
vex_sdk::vexSystemExitRequest();
loop {
vex_sdk::vexTasksRun();
}
}
}

View file

@ -274,6 +274,8 @@ impl Step for GenerateCopyright {
cache_dir
};
let _guard = builder.group("generate-copyright");
let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
cmd.env("CARGO_MANIFESTS", &cargo_manifests);
cmd.env("LICENSE_METADATA", &license_metadata);

View file

@ -74,7 +74,7 @@ impl Step for Vendor {
/// This function runs `cargo vendor` and ensures all required submodules
/// are initialized before vendoring begins.
fn run(self, builder: &Builder<'_>) -> Self::Output {
builder.info(&format!("Vendoring sources to {:?}", self.root_dir));
let _guard = builder.group(&format!("Vendoring sources to {:?}", self.root_dir));
let mut cmd = command(&builder.initial_cargo);
cmd.arg("vendor");

View file

@ -111,12 +111,12 @@ ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf
ENV TARGETS=$TARGETS,riscv32imafc-unknown-none-elf
ENV TARGETS=$TARGETS,riscv64imac-unknown-none-elf
ENV TARGETS=$TARGETS,riscv64gc-unknown-none-elf
ENV TARGETS=$TARGETS,armebv7r-none-eabi
ENV TARGETS=$TARGETS,armebv7r-none-eabihf
ENV TARGETS=$TARGETS,armv7r-none-eabi
ENV TARGETS=$TARGETS,armv7r-none-eabihf
ENV TARGETS=$TARGETS,armv8r-none-eabihf
ENV TARGETS=$TARGETS,thumbv7neon-unknown-linux-gnueabihf
ENV TARGETS=$TARGETS,armv7a-none-eabi
ENV TARGETS=$TARGETS,armv7a-none-eabihf
ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft" \
CFLAGS_arm_unknown_linux_musleabi="-march=armv6 -marm" \
@ -130,7 +130,9 @@ ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft
CC_armv7a_none_eabi=arm-none-eabi-gcc \
CC_armv7a_none_eabihf=arm-none-eabi-gcc \
CFLAGS_armv7a_none_eabi=-march=armv7-a \
CFLAGS_armv7a_none_eabihf=-march=armv7-a+vfpv3 \
CFLAGS_armv7a_none_eabihf=-march=armv7-a+fp \
CC_armv8r_none_eabihf=arm-none-eabi-gcc \
CFLAGS_armv8r_none_eabihf="-march=armv8-r+fp.sp -mfpu=fp-armv8" \
CC_aarch64_unknown_none_softfloat=aarch64-none-elf-gcc \
CFLAGS_aarch64_unknown_none_softfloat=-mstrict-align -march=armv8-a+nofp+nosimd \
CC_aarch64_unknown_none=aarch64-none-elf-gcc \

View file

@ -89,6 +89,7 @@ static TARGETS: &[&str] = &[
"armv7-unknown-linux-gnueabi",
"armv7-unknown-linux-gnueabihf",
"armv7a-none-eabi",
"armv7a-none-eabihf",
"thumbv7neon-unknown-linux-gnueabihf",
"armv7-unknown-linux-musleabi",
"armv7-unknown-linux-musleabihf",

View file

@ -0,0 +1,115 @@
- // MIR for `loop_deref_mut` before GVN
+ // MIR for `loop_deref_mut` after GVN
fn loop_deref_mut(_1: &mut Value) -> Value {
debug val => _1;
let mut _0: Value;
let _2: &Value;
let _3: &Value;
let mut _4: &Value;
let mut _6: !;
let mut _8: isize;
let mut _9: !;
let mut _10: ();
let mut _12: i32;
let _13: ();
let mut _14: bool;
let mut _15: !;
let mut _16: Value;
scope 1 {
debug val_alias => _2;
let mut _5: bool;
scope 2 {
debug stop => _5;
let _7: i32;
scope 3 {
debug v => _7;
let _11: Value;
scope 4 {
debug v => _11;
}
}
}
}
bb0: {
StorageLive(_2);
- StorageLive(_3);
+ nop;
StorageLive(_4);
_4 = &(*_1);
_3 = get::<Value>(move _4) -> [return: bb1, unwind unreachable];
}
bb1: {
_2 = &(*_3);
StorageDead(_4);
- StorageDead(_3);
+ nop;
StorageLive(_5);
_5 = const false;
- _8 = discriminant((*_2));
+ _8 = discriminant((*_3));
switchInt(move _8) -> [0: bb3, otherwise: bb2];
}
bb2: {
unreachable;
}
bb3: {
- StorageLive(_7);
- _7 = copy (((*_2) as V0).0: i32);
+ nop;
+ _7 = copy (((*_3) as V0).0: i32);
StorageLive(_9);
goto -> bb4;
}
bb4: {
StorageLive(_11);
StorageLive(_12);
_12 = copy _7;
- _11 = Value::V0(move _12);
+ _11 = Value::V0(copy _7);
StorageDead(_12);
StorageLive(_13);
StorageLive(_14);
_14 = copy _5;
switchInt(move _14) -> [0: bb6, otherwise: bb5];
}
bb5: {
_0 = move _11;
StorageDead(_14);
StorageDead(_13);
StorageDead(_11);
StorageDead(_9);
- StorageDead(_7);
+ nop;
StorageDead(_5);
StorageDead(_2);
return;
}
bb6: {
_13 = const ();
StorageDead(_14);
StorageDead(_13);
_5 = const true;
StorageLive(_16);
- _16 = Value::V1;
- (*_1) = move _16;
+ _16 = const Value::V1;
+ (*_1) = const Value::V1;
StorageDead(_16);
_10 = const ();
StorageDead(_11);
goto -> bb4;
}
+ }
+
+ ALLOC0 (size: 8, align: 4) {
+ 01 00 00 00 __ __ __ __ │ ....░░░░
}

39
tests/mir-opt/gvn_loop.rs Normal file
View file

@ -0,0 +1,39 @@
//@ test-mir-pass: GVN
#![crate_type = "lib"]
#![feature(core_intrinsics, rustc_attrs)]
pub enum Value {
V0(i32),
V1,
}
// Check that we do not use the dereferenced value of `val_alias` when returning.
// EMIT_MIR gvn_loop.loop_deref_mut.GVN.diff
fn loop_deref_mut(val: &mut Value) -> Value {
// CHECK-LABEL: fn loop_deref_mut(
// CHECK: [[VAL_REF:_.*]] = get::<Value>(
// CHECK: [[V:_.*]] = copy (((*[[VAL_REF]]) as V0).0: i32);
// CEHCK-NOT: copy (*[[VAL_REF]]);
// CHECK: [[RET:_*]] = Value::V0(copy [[V]]);
// CEHCK-NOT: copy (*[[VAL_REF]]);
// CHECK: _0 = move [[RET]]
let val_alias: &Value = get(val);
let mut stop = false;
let Value::V0(v) = *val_alias else { unsafe { core::intrinsics::unreachable() } };
loop {
let v = Value::V0(v);
if stop {
return v;
}
stop = true;
*val = Value::V1;
}
}
#[inline(never)]
#[rustc_nounwind]
fn get<T>(v: &T) -> &T {
v
}

View file

@ -0,0 +1,22 @@
//@ check-pass
// Regression test for #147542
// Ensures that we don't suggest removing parens in a break with label and loop
// when the parens are necessary for correct parsing.
#![warn(unused_parens)]
#![warn(break_with_label_and_loop)]
fn xyz() -> usize {
'foo: {
// parens bellow are necessary break of break with label and loop
break 'foo ({
println!("Hello!");
123
});
}
}
fn main() {
xyz();
}

View file

@ -0,0 +1,34 @@
//@ compile-flags: -O
//@ run-pass
pub enum Value {
V0(i32),
V1,
}
fn set_discriminant(val: &mut Value) -> Value {
let val_alias: &Value = get(val);
let mut stop = false;
let Value::V0(v) = *val_alias else {
unreachable!();
};
loop {
let v = Value::V0(v);
if stop {
return v;
}
stop = true;
*val = Value::V1;
}
}
fn main() {
let mut v = Value::V0(1);
let v = set_discriminant(&mut v);
assert!(matches!(v, Value::V0(1)));
}
#[inline(never)]
fn get<T>(v: &T) -> &T {
v
}

View file

@ -0,0 +1,24 @@
#![feature(never_patterns)]
#![allow(incomplete_features)]
enum Never {}
fn example(x: Never) -> [i32; 1] {
let ! = x;
[1]
}
fn function_param_never(!: Never) -> [i32; 1] {
[1]
}
fn generic_never<T>(!: T) -> [i32; 1] //~ ERROR mismatched types
where
T: Copy,
{
[1]
}
fn main() {
let _ = "12".lines().map(|!| [1]); //~ ERROR mismatched types
}

View file

@ -0,0 +1,18 @@
error: mismatched types
--> $DIR/never-pattern-as-closure-param-141592.rs:15:21
|
LL | fn generic_never<T>(!: T) -> [i32; 1]
| ^ a never pattern must be used on an uninhabited type
|
= note: the matched value is of type `T`
error: mismatched types
--> $DIR/never-pattern-as-closure-param-141592.rs:23:31
|
LL | let _ = "12".lines().map(|!| [1]);
| ^ a never pattern must be used on an uninhabited type
|
= note: the matched value is of type `str`
error: aborting due to 2 previous errors

View file

@ -0,0 +1,44 @@
//@ compile-flags: -Znext-solver
#![feature(rustc_attrs)]
#![rustc_no_implicit_bounds]
// A regression test making sure that when forcing dependent
// provisional cache entries to ambiguous, we use the `MaybeCause`
// of the cycle head. We ended up trying to use the current result
// of the provisional cache entry, which is incorrect and caused an
// ICE when trying to unwrap it.
struct Root<T>(T);
struct Head<T>(T);
struct Error<T>(T);
struct NotImplemented<T>(T);
#[rustc_coinductive]
trait Trait {}
impl<T> Trait for Root<T>
where
Head<T>: Trait,
{}
impl<T> Trait for Head<T>
where
Root<T>: Trait,
T: Trait, // ambiguous
{}
impl<T> Trait for Head<T>
where
Error<T>: Trait,
NotImplemented<T>: Trait,
{}
impl<T> Trait for Error<T>
where
Head<T>: Trait,
NotImplemented<T>: Trait,
{}
fn impls_trait<T: Trait>() {}
fn main() {
impls_trait::<Root<_>>() //~ ERROR type annotations needed
}

View file

@ -0,0 +1,27 @@
error[E0283]: type annotations needed
--> $DIR/forced_ambiguity-use-head-maybe-cause.rs:43:19
|
LL | impls_trait::<Root<_>>()
| ^^^^^^^ cannot infer type for struct `Head<_>`
|
= note: cannot satisfy `Head<_>: Trait`
= help: the trait `Trait` is implemented for `Head<T>`
note: required for `Root<_>` to implement `Trait`
--> $DIR/forced_ambiguity-use-head-maybe-cause.rs:18:9
|
LL | impl<T> Trait for Root<T>
| ^^^^^ ^^^^^^^
LL | where
LL | Head<T>: Trait,
| ----- unsatisfied trait bound introduced here
= note: 8 redundant requirements hidden
= note: required for `Root<_>` to implement `Trait`
note: required by a bound in `impls_trait`
--> $DIR/forced_ambiguity-use-head-maybe-cause.rs:41:19
|
LL | fn impls_trait<T: Trait>() {}
| ^^^^^ required by this bound in `impls_trait`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0283`.

View file

@ -0,0 +1,44 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@ check-pass
// Regression test for trait-system-refactor-initiative#240. Hidden types should
// equate *before* inference var fallback, otherwise we can get mismatched types.
#[derive(Clone, Copy)]
struct FileSystem;
impl FileSystem {
fn build<T>(self, commands: T) -> Option<impl Sized> {
match false {
true => Some(commands),
false => {
drop(match self.build::<_>(commands) {
Some(x) => x,
None => return None,
});
panic!()
},
}
}
}
fn build2<T, U>() -> impl Sized {
if false {
build2::<U, T>()
} else {
loop {}
};
1u32
}
fn build3<'a>() -> impl Sized + use<'a> {
if false {
build3()
} else {
loop {}
};
1u32
}
fn main() {}