Auto merge of #137406 - matthiaskrgr:rollup-9nknrsb, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #136458 (Do not deduplicate list of associated types provided by dyn principal)
 - #136474 ([`compiletest`-related cleanups 3/7] Make the distinction between sources root vs test suite sources root in compiletest less confusing)
 - #136592 (Make sure we don't overrun the stack in canonicalizer)
 - #136787 (Remove `lifetime_capture_rules_2024` feature)
 - #137207 (Add #[track_caller] to Duration Div impl)
 - #137245 (Tweak E0277 when predicate comes indirectly from ?)
 - #137257 (Ignore fake borrows for packed field check)
 - #137399 (fix ICE in layout computation with unnormalizable const)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-02-22 03:05:26 +00:00
commit b87eda7fdf
65 changed files with 785 additions and 386 deletions

View file

@ -135,6 +135,8 @@ declare_features! (
Some("removed as it caused some confusion and discussion was inactive for years")),
/// Lazily evaluate constants. This allows constants to depend on type parameters.
(removed, lazy_normalization_consts, "1.46.0", Some(72219), Some("superseded by `generic_const_exprs`")),
/// Changes `impl Trait` to capture all lifetimes in scope.
(removed, lifetime_capture_rules_2024, "1.76.0", None, Some("unnecessary -- use edition 2024 instead")),
/// Allows using the `#[link_args]` attribute.
(removed, link_args, "1.53.0", Some(29596),
Some("removed in favor of using `-C link-arg=ARG` on command line, \

View file

@ -214,8 +214,6 @@ declare_features! (
(internal, intrinsics, "1.0.0", None),
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
(internal, lang_items, "1.0.0", None),
/// Changes `impl Trait` to capture all lifetimes in scope.
(unstable, lifetime_capture_rules_2024, "1.76.0", None),
/// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406
(internal, link_cfg, "1.14.0", None),
/// Allows using `?Trait` trait bounds in more contexts.

View file

@ -305,21 +305,15 @@ fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVaria
}
/// Whether this opaque always captures lifetimes in scope.
/// Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024`
/// is enabled. We don't check the span of the edition, since this is done
/// on a per-opaque basis to account for nested opaques.
fn opaque_captures_all_in_scope_lifetimes<'tcx>(
tcx: TyCtxt<'tcx>,
opaque: &'tcx hir::OpaqueTy<'tcx>,
) -> bool {
/// Right now, this is all RPITIT and TAITs, and when the opaque
/// is coming from a span corresponding to edition 2024.
fn opaque_captures_all_in_scope_lifetimes<'tcx>(opaque: &'tcx hir::OpaqueTy<'tcx>) -> bool {
match opaque.origin {
// if the opaque has the `use<...>` syntax, the user is telling us that they only want
// to account for those lifetimes, so do not try to be clever.
_ if opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) => false,
hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::TyAlias { .. } => true,
_ if tcx.features().lifetime_capture_rules_2024() || opaque.span.at_least_rust_2024() => {
true
}
_ if opaque.span.at_least_rust_2024() => true,
hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(),
}
}
@ -519,8 +513,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) {
let captures = RefCell::new(FxIndexMap::default());
let capture_all_in_scope_lifetimes =
opaque_captures_all_in_scope_lifetimes(self.tcx, opaque);
let capture_all_in_scope_lifetimes = opaque_captures_all_in_scope_lifetimes(opaque);
if capture_all_in_scope_lifetimes {
let lifetime_ident = |def_id: LocalDefId| {
let name = self.tcx.item_name(def_id.to_def_id());
@ -2276,7 +2269,7 @@ fn is_late_bound_map(
}
let mut appears_in_output =
AllCollector { tcx, has_fully_capturing_opaque: false, regions: Default::default() };
AllCollector { has_fully_capturing_opaque: false, regions: Default::default() };
intravisit::walk_fn_ret_ty(&mut appears_in_output, &sig.decl.output);
if appears_in_output.has_fully_capturing_opaque {
appears_in_output.regions.extend(generics.params.iter().map(|param| param.def_id));
@ -2289,7 +2282,7 @@ fn is_late_bound_map(
// Subtle point: because we disallow nested bindings, we can just
// ignore binders here and scrape up all names we see.
let mut appears_in_where_clause =
AllCollector { tcx, has_fully_capturing_opaque: true, regions: Default::default() };
AllCollector { has_fully_capturing_opaque: true, regions: Default::default() };
appears_in_where_clause.visit_generics(generics);
debug!(?appears_in_where_clause.regions);
@ -2455,23 +2448,21 @@ fn is_late_bound_map(
}
}
struct AllCollector<'tcx> {
tcx: TyCtxt<'tcx>,
struct AllCollector {
has_fully_capturing_opaque: bool,
regions: FxHashSet<LocalDefId>,
}
impl<'v> Visitor<'v> for AllCollector<'v> {
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
impl<'tcx> Visitor<'tcx> for AllCollector {
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
self.regions.insert(def_id);
}
}
fn visit_opaque_ty(&mut self, opaque: &'v hir::OpaqueTy<'v>) {
fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) {
if !self.has_fully_capturing_opaque {
self.has_fully_capturing_opaque =
opaque_captures_all_in_scope_lifetimes(self.tcx, opaque);
self.has_fully_capturing_opaque = opaque_captures_all_in_scope_lifetimes(opaque);
}
intravisit::walk_opaque_ty(self, opaque);
}

View file

@ -1,4 +1,4 @@
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::struct_span_code_err;
use rustc_hir as hir;
@ -58,9 +58,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
let (trait_bounds, mut projection_bounds) =
let (elaborated_trait_bounds, elaborated_projection_bounds) =
traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
.into_iter()
.partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
@ -103,29 +103,81 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
// Map the projection bounds onto a key that makes it easy to remove redundant
// bounds that are constrained by supertraits of the principal def id.
//
// Also make sure we detect conflicting bounds from expanding a trait alias and
// also specifying it manually, like:
// ```
// type Alias = Trait<Assoc = i32>;
// let _: &dyn Alias<Assoc = u32> = /* ... */;
// ```
let mut projection_bounds = FxIndexMap::default();
for (proj, proj_span) in elaborated_projection_bounds {
let key = (
proj.skip_binder().projection_term.def_id,
tcx.anonymize_bound_vars(
proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
),
);
if let Some((old_proj, old_proj_span)) =
projection_bounds.insert(key, (proj, proj_span))
&& tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj)
{
let item = tcx.item_name(proj.item_def_id());
self.dcx()
.struct_span_err(
span,
format!(
"conflicting associated type bounds for `{item}` when \
expanding trait alias"
),
)
.with_span_label(
old_proj_span,
format!("`{item}` is specified to be `{}` here", old_proj.term()),
)
.with_span_label(
proj_span,
format!("`{item}` is specified to be `{}` here", proj.term()),
)
.emit();
}
}
let principal_trait = regular_traits.into_iter().next();
let mut needed_associated_types = FxIndexSet::default();
if let Some((principal_trait, spans)) = &principal_trait {
let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx);
for ClauseWithSupertraitSpan { pred, supertrait_span } in traits::elaborate(
let mut needed_associated_types = vec![];
if let Some((principal_trait, ref spans)) = principal_trait {
let principal_trait = principal_trait.map_bound(|trait_pred| {
assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
trait_pred.trait_ref
});
for ClauseWithSupertraitSpan { clause, supertrait_span } in traits::elaborate(
tcx,
[ClauseWithSupertraitSpan::new(pred, *spans.last().unwrap())],
[ClauseWithSupertraitSpan::new(
ty::TraitRef::identity(tcx, principal_trait.def_id()).upcast(tcx),
*spans.last().unwrap(),
)],
)
.filter_only_self()
{
debug!("observing object predicate `{pred:?}`");
let clause = clause.instantiate_supertrait(tcx, principal_trait);
debug!("observing object predicate `{clause:?}`");
let bound_predicate = pred.kind();
let bound_predicate = clause.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
ty::ClauseKind::Trait(pred) => {
// FIXME(negative_bounds): Handle this correctly...
let trait_ref =
tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
needed_associated_types.extend(
tcx.associated_items(trait_ref.def_id())
tcx.associated_items(pred.trait_ref.def_id)
.in_definition_order()
// We only care about associated types.
.filter(|item| item.kind == ty::AssocKind::Type)
// No RPITITs -- even with `async_fn_in_dyn_trait`, they are implicit.
.filter(|item| !item.is_impl_trait_in_trait())
// If the associated type has a `where Self: Sized` bound,
// we do not need to constrain the associated type.
@ -133,7 +185,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.map(|item| (item.def_id, trait_ref)),
);
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
ty::ClauseKind::Projection(pred) => {
let pred = bound_predicate.rebind(pred);
// A `Self` within the original bound will be instantiated with a
// `trait_object_dummy_self`, so check for that.
@ -161,8 +213,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
// the discussion in #56288 for alternatives.
if !references_self {
// Include projections defined on supertraits.
projection_bounds.push((pred, supertrait_span));
let key = (
pred.skip_binder().projection_term.def_id,
tcx.anonymize_bound_vars(
pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
),
);
if !projection_bounds.contains_key(&key) {
projection_bounds.insert(key, (pred, supertrait_span));
}
}
self.check_elaborated_projection_mentions_input_lifetimes(
@ -182,12 +241,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// types that we expect to be provided by the user, so the following loop
// removes all the associated types that have a corresponding `Projection`
// clause, either from expanding trait aliases or written by the user.
for &(projection_bound, span) in &projection_bounds {
for &(projection_bound, span) in projection_bounds.values() {
let def_id = projection_bound.item_def_id();
let trait_ref = tcx.anonymize_bound_vars(
projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
);
needed_associated_types.swap_remove(&(def_id, trait_ref));
if tcx.generics_require_sized_self(def_id) {
tcx.emit_node_span_lint(
UNUSED_ASSOCIATED_TYPE_BOUNDS,
@ -198,9 +253,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
let mut missing_assoc_types = FxIndexSet::default();
let projection_bounds: Vec<_> = needed_associated_types
.into_iter()
.filter_map(|key| {
if let Some(assoc) = projection_bounds.get(&key) {
Some(*assoc)
} else {
missing_assoc_types.insert(key);
None
}
})
.collect();
if let Err(guar) = self.check_for_required_assoc_tys(
principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
needed_associated_types,
missing_assoc_types,
potential_assoc_types,
hir_bounds,
) {
@ -266,7 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
})
});
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
let existential_projections = projection_bounds.into_iter().map(|(bound, _)| {
bound.map_bound(|mut b| {
assert_eq!(b.projection_term.self_ty(), dummy_self);
@ -291,12 +359,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
})
});
let auto_trait_predicates = auto_traits.into_iter().map(|(trait_pred, _)| {
assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
let mut auto_trait_predicates: Vec<_> = auto_traits
.into_iter()
.map(|(trait_pred, _)| {
assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
});
ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
})
.collect();
auto_trait_predicates.dedup();
// N.b. principal, projections, auto traits
// FIXME: This is actually wrong with multiple principals in regards to symbol mangling
@ -306,7 +378,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.chain(auto_trait_predicates)
.collect::<SmallVec<[_; 8]>>();
v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
v.dedup();
let existential_predicates = tcx.mk_poly_existential_predicates(&v);
// Use explicitly-specified region bound, unless the bound is missing.

View file

@ -86,8 +86,7 @@ declare_lint! {
///
/// ### Example
///
/// ```rust,compile_fail
/// # #![feature(lifetime_capture_rules_2024)]
/// ```rust,edition2024,compile_fail
/// # #![deny(impl_trait_redundant_captures)]
/// fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x }
/// ```
@ -268,8 +267,7 @@ where
&& parent == self.parent_def_id
{
let opaque_span = self.tcx.def_span(opaque_def_id);
let new_capture_rules = opaque_span.at_least_rust_2024()
|| self.tcx.features().lifetime_capture_rules_2024();
let new_capture_rules = opaque_span.at_least_rust_2024();
if !new_capture_rules
&& !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..)))
{

View file

@ -1364,13 +1364,13 @@ impl PlaceContext {
matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
}
/// Returns `true` if this place context represents a borrow.
/// Returns `true` if this place context represents a borrow, excluding fake borrows
/// (which are an artifact of borrowck and not actually borrows in runtime MIR).
pub fn is_borrow(self) -> bool {
matches!(
self,
PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow
) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
| PlaceContext::MutatingUse(MutatingUseContext::Borrow)
)
}

View file

@ -12,7 +12,7 @@ use std::borrow::Cow;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
use rustc_errors::{Applicability, Diag, EmissionGuarantee, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_hir::def_id::DefId;
@ -996,4 +996,7 @@ pub enum CodegenObligationError {
/// but was included during typeck due to the trivial_bounds feature.
Unimplemented,
FulfillmentError,
/// The selected impl has unconstrained generic parameters. This will emit an error
/// during impl WF checking.
UnconstrainedParam(ErrorGuaranteed),
}

View file

@ -79,20 +79,14 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
b: Self,
) -> RelateResult<'tcx, Self> {
let tcx = relation.cx();
// FIXME: this is wasteful, but want to do a perf run to see how slow it is.
// We need to perform this deduplication as we sometimes generate duplicate projections
// in `a`.
let mut a_v: Vec<_> = a.into_iter().collect();
let mut b_v: Vec<_> = b.into_iter().collect();
a_v.dedup();
b_v.dedup();
if a_v.len() != b_v.len() {
// Fast path for when the auto traits do not match, or if the principals
// are from different traits and therefore the projections definitely don't
// match up.
if a.len() != b.len() {
return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
}
let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
match (ep_a.skip_binder(), ep_b.skip_binder()) {
let v =
iter::zip(a, b).map(|(ep_a, ep_b)| match (ep_a.skip_binder(), ep_b.skip_binder()) {
(ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => {
Ok(ep_a.rebind(ty::ExistentialPredicate::Trait(
relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
@ -109,8 +103,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
ty::ExistentialPredicate::AutoTrait(b),
) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))),
_ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))),
}
});
});
tcx.mk_poly_existential_predicates_from_iter(v)
}
}

View file

@ -18,7 +18,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use rustc_type_ir::TyKind::*;
use rustc_type_ir::visit::TypeVisitableExt;
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind};
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, elaborate};
use tracing::instrument;
use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
@ -720,6 +720,34 @@ impl<'tcx> Ty<'tcx> {
reg: ty::Region<'tcx>,
repr: DynKind,
) -> Ty<'tcx> {
if cfg!(debug_assertions) {
let projection_count = obj.projection_bounds().count();
let expected_count: usize = obj
.principal_def_id()
.into_iter()
.flat_map(|principal_def_id| {
// NOTE: This should agree with `needed_associated_types` in
// dyn trait lowering, or else we'll have ICEs.
elaborate::supertraits(
tcx,
ty::Binder::dummy(ty::TraitRef::identity(tcx, principal_def_id)),
)
.map(|principal| {
tcx.associated_items(principal.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| !item.is_impl_trait_in_trait())
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
.count()
})
})
.sum();
assert_eq!(
projection_count, expected_count,
"expected {obj:?} to have {expected_count} projections, \
but it has {projection_count}"
);
}
Ty::new(tcx, Dynamic(obj, reg, repr))
}

View file

@ -1,6 +1,6 @@
use std::cmp::Ordering;
use rustc_type_ir::data_structures::HashMap;
use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack};
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_type_ir::inherent::*;
use rustc_type_ir::solve::{Goal, QueryInput};
@ -389,7 +389,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
| ty::Alias(_, _)
| ty::Bound(_, _)
| ty::Error(_) => {
return t.super_fold_with(self);
return ensure_sufficient_stack(|| t.super_fold_with(self));
}
};

View file

@ -192,19 +192,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let have_alt_message = message.is_some() || label.is_some();
let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id());
let is_question_mark = matches!(
root_obligation.cause.code().peel_derives(),
ObligationCauseCode::QuestionMark,
) && !(
self.tcx.is_diagnostic_item(sym::FromResidual, main_trait_predicate.def_id())
|| self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::Try)
);
let is_unsize =
self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize);
let question_mark_message = "the question mark operation (`?`) implicitly \
performs a conversion on the error value \
using the `From` trait";
let (message, notes, append_const_msg) = if is_try_conversion {
// We have a `-> Result<_, E1>` and `gives_E2()?`.
(
Some(format!(
"`?` couldn't convert the error to `{}`",
main_trait_predicate.skip_binder().self_ty(),
)),
vec![
"the question mark operation (`?`) implicitly performs a \
conversion on the error value using the `From` trait"
.to_owned(),
],
vec![question_mark_message.to_owned()],
Some(AppendConstMessage::Default),
)
} else if is_question_mark {
// Similar to the case above, but in this case the conversion is for a
// trait object: `-> Result<_, Box<dyn Error>` and `gives_E()?` when
// `E: Error` isn't met.
(
Some(format!(
"`?` couldn't convert the error: `{main_trait_predicate}` is \
not satisfied",
)),
vec![question_mark_message.to_owned()],
Some(AppendConstMessage::Default),
)
} else {
@ -220,8 +239,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&mut long_ty_file,
);
let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait)
{
let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(
main_trait_predicate.def_id(),
LangItem::TransmuteTrait,
) {
// Recompute the safe transmute reason and use that for the error reporting
match self.get_safe_transmute_error_and_reason(
obligation.clone(),
@ -249,18 +270,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
*err.long_ty_path() = long_ty_file;
let mut suggested = false;
if is_try_conversion {
if is_try_conversion || is_question_mark {
suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
}
if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
err.span_label(
ret_span,
format!(
"expected `{}` because of this",
main_trait_predicate.skip_binder().self_ty()
),
);
if let Some(ret_span) = self.return_type_span(&obligation) {
if is_try_conversion {
err.span_label(
ret_span,
format!(
"expected `{}` because of this",
main_trait_predicate.skip_binder().self_ty()
),
);
} else if is_question_mark {
err.span_label(ret_span, format!("required `{main_trait_predicate}` because of this"));
}
}
if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Tuple) {
@ -302,10 +327,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// If it has a custom `#[rustc_on_unimplemented]`
// error message, let's display it as the label!
err.span_label(span, s);
if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_)) {
if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_))
// When the self type is a type param We don't need to "the trait
// `std::marker::Sized` is not implemented for `T`" as we will point
// at the type param with a label to suggest constraining it.
&& !self.tcx.is_diagnostic_item(sym::FromResidual, leaf_trait_predicate.def_id())
// Don't say "the trait `FromResidual<Option<Infallible>>` is
// not implemented for `Result<T, E>`".
{
err.help(explanation);
}
} else if let Some(custom_explanation) = safe_transmute_explanation {
@ -932,16 +961,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let Some(typeck) = &self.typeck_results else {
return false;
};
let Some((ObligationCauseCode::QuestionMark, Some(y))) =
obligation.cause.code().parent_with_predicate()
else {
let ObligationCauseCode::QuestionMark = obligation.cause.code().peel_derives() else {
return false;
};
if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) {
return false;
}
let self_ty = trait_pred.skip_binder().self_ty();
let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type());
self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred);
let mut prev_ty = self.resolve_vars_if_possible(
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
@ -1106,6 +1131,56 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
suggested
}
fn note_missing_impl_for_question_mark(
&self,
err: &mut Diag<'_>,
self_ty: Ty<'_>,
found_ty: Option<Ty<'_>>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
match (self_ty.kind(), found_ty) {
(ty::Adt(def, _), Some(ty))
if let ty::Adt(found, _) = ty.kind()
&& def.did().is_local()
&& found.did().is_local() =>
{
err.span_note(
self.tcx.def_span(def.did()),
format!("`{self_ty}` needs to implement `From<{ty}>`"),
);
err.span_note(
self.tcx.def_span(found.did()),
format!("alternatively, `{ty}` needs to implement `Into<{self_ty}>`"),
);
}
(ty::Adt(def, _), None) if def.did().is_local() => {
err.span_note(
self.tcx.def_span(def.did()),
format!(
"`{self_ty}` needs to implement `{}`",
trait_pred.skip_binder().trait_ref.print_only_trait_path(),
),
);
}
(ty::Adt(def, _), Some(ty)) if def.did().is_local() => {
err.span_note(
self.tcx.def_span(def.did()),
format!("`{self_ty}` needs to implement `From<{ty}>`"),
);
}
(_, Some(ty))
if let ty::Adt(def, _) = ty.kind()
&& def.did().is_local() =>
{
err.span_note(
self.tcx.def_span(def.did()),
format!("`{ty}` needs to implement `Into<{self_ty}>`"),
);
}
_ => {}
}
}
fn report_const_param_not_wf(
&self,
ty: Ty<'tcx>,
@ -2035,6 +2110,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return false;
}
if let &[cand] = &candidates[..] {
if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id)
&& !self.tcx.features().enabled(sym::try_trait_v2)
{
return false;
}
let (desc, mention_castable) =
match (cand.self_ty().kind(), trait_pred.self_ty().skip_binder().kind()) {
(ty::FnPtr(..), ty::FnDef(..)) => {

View file

@ -80,16 +80,14 @@ pub(crate) fn codegen_select_candidate<'tcx>(
// but never resolved, causing the return value of a query to contain inference
// vars. We do not have a concept for this and will in fact ICE in stable hashing
// of the return value. So bail out instead.
match impl_source {
ImplSource::UserDefined(impl_) => {
tcx.dcx().span_delayed_bug(
tcx.def_span(impl_.impl_def_id),
"this impl has unconstrained generic parameters",
);
}
let guar = match impl_source {
ImplSource::UserDefined(impl_) => tcx.dcx().span_delayed_bug(
tcx.def_span(impl_.impl_def_id),
"this impl has unconstrained generic parameters",
),
_ => unreachable!(),
}
return Err(CodegenObligationError::FulfillmentError);
};
return Err(CodegenObligationError::UnconstrainedParam(guar));
}
Ok(&*tcx.arena.alloc(impl_source))

View file

@ -112,6 +112,7 @@ fn resolve_associated_item<'tcx>(
| CodegenObligationError::Unimplemented
| CodegenObligationError::FulfillmentError,
) => return Ok(None),
Err(CodegenObligationError::UnconstrainedParam(guar)) => return Err(guar),
};
// Now that we know which impl is being used, we can dispatch to

View file

@ -147,12 +147,25 @@ fn extract_const_value<'tcx>(
) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
match ct.kind() {
ty::ConstKind::Value(cv) => Ok(cv),
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) => {
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
if !ct.has_param() {
bug!("failed to normalize const, but it is not generic: {ct:?}");
}
Err(error(cx, LayoutError::TooGeneric(ty)))
}
ty::ConstKind::Unevaluated(_) => {
let err = if ct.has_param() {
LayoutError::TooGeneric(ty)
} else {
// This case is reachable with unsatisfiable predicates and GCE (which will
// cause anon consts to inherit the unsatisfiable predicates). For example
// if we have an unsatisfiable `u8: Trait` bound, then it's not a compile
// error to mention `[u8; <u8 as Trait>::CONST]`, but we can't compute its
// layout.
LayoutError::Unknown(ty)
};
Err(error(cx, err))
}
ty::ConstKind::Infer(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_)

View file

@ -44,25 +44,22 @@ pub trait Elaboratable<I: Interner> {
}
pub struct ClauseWithSupertraitSpan<I: Interner> {
pub pred: I::Predicate,
pub clause: I::Clause,
// Span of the supertrait predicatae that lead to this clause.
pub supertrait_span: I::Span,
}
impl<I: Interner> ClauseWithSupertraitSpan<I> {
pub fn new(pred: I::Predicate, span: I::Span) -> Self {
ClauseWithSupertraitSpan { pred, supertrait_span: span }
pub fn new(clause: I::Clause, span: I::Span) -> Self {
ClauseWithSupertraitSpan { clause, supertrait_span: span }
}
}
impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
fn predicate(&self) -> <I as Interner>::Predicate {
self.pred
self.clause.as_predicate()
}
fn child(&self, clause: <I as Interner>::Clause) -> Self {
ClauseWithSupertraitSpan {
pred: clause.as_predicate(),
supertrait_span: self.supertrait_span,
}
ClauseWithSupertraitSpan { clause, supertrait_span: self.supertrait_span }
}
fn child_with_derived_cause(
@ -72,7 +69,7 @@ impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
_parent_trait_pred: crate::Binder<I, crate::TraitPredicate<I>>,
_index: usize,
) -> Self {
ClauseWithSupertraitSpan { pred: clause.as_predicate(), supertrait_span }
ClauseWithSupertraitSpan { clause, supertrait_span }
}
}

View file

@ -1168,6 +1168,7 @@ impl Div<u32> for Duration {
type Output = Duration;
#[inline]
#[track_caller]
fn div(self, rhs: u32) -> Duration {
self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar")
}
@ -1176,6 +1177,7 @@ impl Div<u32> for Duration {
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
impl DivAssign<u32> for Duration {
#[inline]
#[track_caller]
fn div_assign(&mut self, rhs: u32) {
*self = *self / rhs;
}

View file

@ -1762,7 +1762,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
cmd.arg("--coverage-dump-path").arg(coverage_dump);
}
cmd.arg("--src-base").arg(builder.src.join("tests").join(suite));
cmd.arg("--src-root").arg(&builder.src);
cmd.arg("--src-test-suite-root").arg(builder.src.join("tests").join(suite));
cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite));
// When top stage is 0, that means that we're testing an externally provided compiler.

View file

@ -215,8 +215,10 @@ pub struct Config {
/// `None` then these tests will be ignored.
pub run_clang_based_tests_with: Option<String>,
/// The directory containing the tests to run
pub src_base: PathBuf,
/// The directory containing the sources.
pub src_root: PathBuf,
/// The directory containing the test suite sources. Must be a subdirectory of `src_root`.
pub src_test_suite_root: PathBuf,
/// The directory where programs should be built
pub build_base: PathBuf,

View file

@ -1026,19 +1026,6 @@ impl Config {
}
}
pub fn find_rust_src_root(&self) -> Option<PathBuf> {
let mut path = self.src_base.clone();
let path_postfix = Path::new("src/etc/lldb_batchmode.py");
while path.pop() {
if path.join(&path_postfix).is_file() {
return Some(path);
}
}
None
}
fn parse_edition(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "edition")
}
@ -1098,7 +1085,7 @@ fn expand_variables(mut value: String, config: &Config) -> String {
}
if value.contains(SRC_BASE) {
value = value.replace(SRC_BASE, &config.src_base.to_string_lossy());
value = value.replace(SRC_BASE, &config.src_test_suite_root.to_str().unwrap());
}
if value.contains(BUILD_BASE) {

View file

@ -153,7 +153,8 @@ impl ConfigBuilder {
"--run-lib-path=",
"--python=",
"--jsondocck-path=",
"--src-base=",
"--src-root=",
"--src-test-suite-root=",
"--build-base=",
"--sysroot-base=",
"--cc=c",

View file

@ -61,7 +61,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
.optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH")
.optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH")
.optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR")
.reqopt("", "src-base", "directory to scan for test files", "PATH")
.reqopt("", "src-root", "directory containing sources", "PATH")
.reqopt("", "src-test-suite-root", "directory containing test suite sources", "PATH")
.reqopt("", "build-base", "directory to deposit test outputs", "PATH")
.reqopt("", "sysroot-base", "directory containing the compiler sysroot", "PATH")
.reqopt("", "stage", "stage number under test", "N")
@ -243,7 +244,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
|| header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
);
let src_base = opt_path(matches, "src-base");
let run_ignored = matches.opt_present("ignored");
let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions");
let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions");
@ -300,6 +300,15 @@ pub fn parse_config(args: Vec<String>) -> Config {
None => panic!("`--stage` is required"),
};
let src_root = opt_path(matches, "src-root");
let src_test_suite_root = opt_path(matches, "src-test-suite-root");
assert!(
src_test_suite_root.starts_with(&src_root),
"`src-root` must be a parent of `src-test-suite-root`: `src-root`=`{}`, `src-test-suite-root` = `{}`",
src_root.display(),
src_test_suite_root.display()
);
Config {
bless: matches.opt_present("bless"),
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
@ -314,7 +323,10 @@ pub fn parse_config(args: Vec<String>) -> Config {
run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"),
llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from),
llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from),
src_base,
src_root,
src_test_suite_root,
build_base: opt_path(matches, "build-base"),
sysroot_base: opt_path(matches, "sysroot-base"),
@ -422,7 +434,10 @@ pub fn log_config(config: &Config) {
logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
logv(c, format!("cargo_path: {:?}", config.cargo_path));
logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path));
logv(c, format!("src_base: {:?}", config.src_base.display()));
logv(c, format!("src_root: {}", config.src_root.display()));
logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root.display()));
logv(c, format!("build_base: {:?}", config.build_base.display()));
logv(c, format!("stage: {}", config.stage));
logv(c, format!("stage_id: {}", config.stage_id));
@ -620,20 +635,29 @@ struct TestCollector {
/// regardless of whether any filters/tests were specified on the command-line,
/// because filtering is handled later by libtest.
pub fn collect_and_make_tests(config: Arc<Config>) -> Vec<test::TestDescAndFn> {
debug!("making tests from {:?}", config.src_base.display());
debug!("making tests from {}", config.src_test_suite_root.display());
let common_inputs_stamp = common_inputs_stamp(&config);
let modified_tests = modified_tests(&config, &config.src_base).unwrap_or_else(|err| {
panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err)
});
let modified_tests =
modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| {
panic!(
"modified_tests got error from dir: {}, error: {}",
config.src_test_suite_root.display(),
err
)
});
let cache = HeadersCache::load(&config);
let cx = TestCollectorCx { config, cache, common_inputs_stamp, modified_tests };
let mut collector =
TestCollector { tests: vec![], found_path_stems: HashSet::new(), poisoned: false };
collect_tests_from_dir(&cx, &mut collector, &cx.config.src_base, Path::new("")).unwrap_or_else(
|reason| panic!("Could not read tests from {}: {reason}", cx.config.src_base.display()),
);
collect_tests_from_dir(&cx, &mut collector, &cx.config.src_test_suite_root, Path::new(""))
.unwrap_or_else(|reason| {
panic!(
"Could not read tests from {}: {reason}",
cx.config.src_test_suite_root.display()
)
});
let TestCollector { tests, found_path_stems, poisoned } = collector;
@ -655,7 +679,7 @@ pub fn collect_and_make_tests(config: Arc<Config>) -> Vec<test::TestDescAndFn> {
/// common to some subset of tests, and are hopefully unlikely to be modified
/// while working on other tests.)
fn common_inputs_stamp(config: &Config) -> Stamp {
let rust_src_dir = config.find_rust_src_root().expect("Could not find Rust source root");
let src_root = &config.src_root;
let mut stamp = Stamp::from_path(&config.rustc_path);
@ -670,17 +694,17 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
"src/etc/lldb_providers.py",
];
for file in &pretty_printer_files {
let path = rust_src_dir.join(file);
let path = src_root.join(file);
stamp.add_path(&path);
}
stamp.add_dir(&rust_src_dir.join("src/etc/natvis"));
stamp.add_dir(&src_root.join("src/etc/natvis"));
stamp.add_dir(&config.run_lib_path);
if let Some(ref rustdoc_path) = config.rustdoc_path {
stamp.add_path(&rustdoc_path);
stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py"));
stamp.add_path(&src_root.join("src/etc/htmldocck.py"));
}
// Re-run coverage tests if the `coverage-dump` tool was modified,
@ -689,10 +713,10 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
stamp.add_path(coverage_dump_path)
}
stamp.add_dir(&rust_src_dir.join("src/tools/run-make-support"));
stamp.add_dir(&src_root.join("src/tools/run-make-support"));
// Compiletest itself.
stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/"));
stamp.add_dir(&src_root.join("src/tools/compiletest"));
stamp
}
@ -933,10 +957,7 @@ fn files_related_to_test(
}
// `minicore.rs` test auxiliary: we need to make sure tests get rerun if this changes.
//
// FIXME(jieyouxu): untangle these paths, we should provide both a path to root `tests/` or
// `tests/auxiliary/` and the test suite in question. `src_base` is also a terrible name.
related.push(config.src_base.parent().unwrap().join("auxiliary").join("minicore.rs"));
related.push(config.src_root.join("tests").join("auxiliary").join("minicore.rs"));
related
}
@ -1026,10 +1047,8 @@ fn make_test_name(
testpaths: &TestPaths,
revision: Option<&str>,
) -> test::TestName {
// Print the name of the file, relative to the repository root.
// `src_base` looks like `/path/to/rust/tests/ui`
let root_directory = config.src_base.parent().unwrap().parent().unwrap();
let path = testpaths.file.strip_prefix(root_directory).unwrap();
// Print the name of the file, relative to the sources root.
let path = testpaths.file.strip_prefix(&config.src_root).unwrap();
let debugger = match config.debugger {
Some(d) => format!("-{}", d),
None => String::new(),

View file

@ -1365,7 +1365,7 @@ impl<'test> TestCx<'test> {
//
// Note: avoid adding a subdirectory of an already filtered directory here, otherwise the
// same slice of text will be double counted and the truncation might not happen.
add_path(&self.config.src_base);
add_path(&self.config.src_test_suite_root);
add_path(&self.config.build_base);
read2_abbreviated(child, &filter_paths_from_len).expect("failed to read output")
@ -1471,7 +1471,7 @@ impl<'test> TestCx<'test> {
// Similarly, vendored sources shouldn't be shown when running from a dist tarball.
rustc.arg("-Z").arg(format!(
"ignore-directory-in-diagnostics-source-blocks={}",
self.config.find_rust_src_root().unwrap().join("vendor").display(),
self.config.src_root.join("vendor").to_str().unwrap(),
));
// Optionally prevent default --sysroot if specified in test compile-flags.
@ -1632,7 +1632,7 @@ impl<'test> TestCx<'test> {
if self.props.remap_src_base {
rustc.arg(format!(
"--remap-path-prefix={}={}",
self.config.src_base.display(),
self.config.src_test_suite_root.to_str().unwrap(),
FAKE_SRC_BASE,
));
}

View file

@ -257,11 +257,8 @@ impl TestCx<'_> {
println!("Adb process is already finished.");
}
} else {
let rust_src_root =
self.config.find_rust_src_root().expect("Could not find Rust source root");
let rust_pp_module_rel_path = Path::new("./src/etc");
let rust_pp_module_abs_path =
rust_src_root.join(rust_pp_module_rel_path).to_str().unwrap().to_owned();
let rust_pp_module_abs_path = self.config.src_root.join("src").join("etc");
let rust_pp_module_abs_path = rust_pp_module_abs_path.to_str().unwrap();
// write debugger script
let mut script_str = String::with_capacity(2048);
script_str.push_str(&format!("set charset {}\n", Self::charset()));
@ -338,7 +335,7 @@ impl TestCx<'_> {
let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") {
format!("{pp}:{rust_pp_module_abs_path}")
} else {
rust_pp_module_abs_path
rust_pp_module_abs_path.to_string()
};
gdb.args(debugger_opts).env("PYTHONPATH", pythonpath);
@ -407,11 +404,8 @@ impl TestCx<'_> {
// Make LLDB emit its version, so we have it documented in the test output
script_str.push_str("version\n");
// Switch LLDB into "Rust mode"
let rust_src_root =
self.config.find_rust_src_root().expect("Could not find Rust source root");
let rust_pp_module_rel_path = Path::new("./src/etc");
let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path);
// Switch LLDB into "Rust mode".
let rust_pp_module_abs_path = self.config.src_root.join("src/etc");
script_str.push_str(&format!(
"command script import {}/lldb_lookup.py\n",
@ -445,7 +439,7 @@ impl TestCx<'_> {
let debugger_script = self.make_out_name("debugger.script");
// Let LLDB execute the script via lldb_batchmode.py
let debugger_run_result = self.run_lldb(&exe_file, &debugger_script, &rust_src_root);
let debugger_run_result = self.run_lldb(&exe_file, &debugger_script);
if !debugger_run_result.status.success() {
self.fatal_proc_rec("Error while running LLDB", &debugger_run_result);
@ -456,18 +450,13 @@ impl TestCx<'_> {
}
}
fn run_lldb(
&self,
test_executable: &Path,
debugger_script: &Path,
rust_src_root: &Path,
) -> ProcRes {
fn run_lldb(&self, test_executable: &Path, debugger_script: &Path) -> ProcRes {
// Prepare the lldb_batchmode which executes the debugger script
let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
let lldb_script_path = self.config.src_root.join("src/etc/lldb_batchmode.py");
let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") {
format!("{pp}:{}", self.config.lldb_python_dir.as_ref().unwrap())
} else {
self.config.lldb_python_dir.as_ref().unwrap().to_string()
self.config.lldb_python_dir.clone().unwrap()
};
self.run_command_to_procres(
Command::new(&self.config.python)

View file

@ -9,12 +9,11 @@ impl TestCx<'_> {
self.document(&out_dir, &self.testpaths);
let root = self.config.find_rust_src_root().unwrap();
let file_stem =
self.testpaths.file.file_stem().and_then(|f| f.to_str()).expect("no file stem");
let res = self.run_command_to_procres(
Command::new(&nodejs)
.arg(root.join("src/tools/rustdoc-js/tester.js"))
.arg(self.config.src_root.join("src/tools/rustdoc-js/tester.js"))
.arg("--doc-folder")
.arg(out_dir)
.arg("--crate-name")

View file

@ -21,8 +21,6 @@ impl TestCx<'_> {
fn run_rmake_legacy_test(&self) {
let cwd = env::current_dir().unwrap();
let src_root = self.config.src_base.parent().unwrap().parent().unwrap();
let src_root = cwd.join(&src_root);
// FIXME(Zalathar): This should probably be `output_base_dir` to avoid
// an unnecessary extra subdirectory, but since legacy Makefile tests
@ -51,7 +49,7 @@ impl TestCx<'_> {
.stderr(Stdio::piped())
.env("TARGET", &self.config.target)
.env("PYTHON", &self.config.python)
.env("S", src_root)
.env("S", &self.config.src_root)
.env("RUST_BUILD_STAGE", &self.config.stage_id)
.env("RUSTC", cwd.join(&self.config.rustc_path))
.env("TMPDIR", &tmpdir)
@ -181,28 +179,10 @@ impl TestCx<'_> {
// library.
// 2. We need to run the recipe binary.
// So we assume the rust-lang/rust project setup looks like the following (our `.` is the
// top-level directory, irrelevant entries to our purposes omitted):
//
// ```
// . // <- `source_root`
// ├── build/ // <- `build_root`
// ├── compiler/
// ├── library/
// ├── src/
// │ └── tools/
// │ └── run_make_support/
// └── tests
// └── run-make/
// ```
// `source_root` is the top-level directory containing the rust-lang/rust checkout.
let source_root =
self.config.find_rust_src_root().expect("could not determine rust source root");
// `self.config.build_base` is actually the build base folder + "test" + test suite name, it
// looks like `build/<host_triple>/test/run-make`. But we want `build/<host_triple>/`. Note
// that the `build` directory does not need to be called `build`, nor does it need to be
// under `source_root`, so we must compute it based off of `self.config.build_base`.
// under `src_root`, so we must compute it based off of `self.config.build_base`.
let build_root =
self.config.build_base.parent().and_then(Path::parent).unwrap().to_path_buf();
@ -389,10 +369,9 @@ impl TestCx<'_> {
.env("TARGET", &self.config.target)
// Some tests unfortunately still need Python, so provide path to a Python interpreter.
.env("PYTHON", &self.config.python)
// Provide path to checkout root. This is the top-level directory containing
// rust-lang/rust checkout.
.env("SOURCE_ROOT", &source_root)
// Path to the build directory. This is usually the same as `source_root.join("build").join("host")`.
// Provide path to sources root.
.env("SOURCE_ROOT", &self.config.src_root)
// Path to the host build directory.
.env("BUILD_ROOT", &build_root)
// Provide path to stage-corresponding rustc.
.env("RUSTC", &self.config.rustc_path)
@ -408,11 +387,11 @@ impl TestCx<'_> {
.env("LLVM_COMPONENTS", &self.config.llvm_components);
if let Some(ref cargo) = self.config.cargo_path {
cmd.env("CARGO", source_root.join(cargo));
cmd.env("CARGO", cargo);
}
if let Some(ref rustdoc) = self.config.rustdoc_path {
cmd.env("RUSTDOC", source_root.join(rustdoc));
cmd.env("RUSTDOC", rustdoc);
}
if let Some(ref node) = self.config.nodejs {

View file

@ -17,9 +17,10 @@ impl TestCx<'_> {
if self.props.check_test_line_numbers_match {
self.check_rustdoc_test_option(proc_res);
} else {
let root = self.config.find_rust_src_root().unwrap();
let mut cmd = Command::new(&self.config.python);
cmd.arg(root.join("src/etc/htmldocck.py")).arg(&out_dir).arg(&self.testpaths.file);
cmd.arg(self.config.src_root.join("src/etc/htmldocck.py"))
.arg(&out_dir)
.arg(&self.testpaths.file);
if self.config.bless {
cmd.arg("--bless");
}

View file

@ -1,20 +0,0 @@
//@ known-bug: rust-lang/rust#125957
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
#![feature(associated_const_equality)]
pub struct Equal<const T: usize, const R: usize>();
pub enum ParseMode {
Raw,
}
pub trait Parse {
const PARSE_MODE: ParseMode;
}
pub trait RenderRaw: Parse<PARSE_MODE = { ParseMode::Raw }> {}
trait GenericVec<T> {
fn unwrap() -> dyn RenderRaw;
}
fn main() {}

View file

@ -1,28 +0,0 @@
//@ known-bug: #132330
//@compile-flags: -Znext-solver=globally
trait Service {
type S;
}
trait Framing {
type F;
}
impl Framing for () {
type F = ();
}
trait HttpService<F: Framing>: Service<S = F::F> {}
type BoxService = Box<dyn HttpService<(), S = ()>>;
fn build_server<F: FnOnce() -> BoxService>(_: F) {}
fn make_server<F: Framing>() -> Box<dyn HttpService<F, S = F::F>> {
unimplemented!()
}
fn main() {
build_server(|| make_server())
}

View file

@ -2,11 +2,13 @@
// Similar to stress testing, the test case requires a larger call stack,
// so we ignore rustc's debug assertions.
//@ build-pass
// ignore-tidy-linelength
// Regression for #93775, needs build-pass to test it.
//@ build-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
#![recursion_limit = "1001"]
use std::marker::PhantomData;
@ -14,7 +16,64 @@ use std::marker::PhantomData;
struct Z;
struct S<T>(PhantomData<T>);
type Nested = S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<Z>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;
type Nested = S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<Z>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;
trait AsNum {
const NUM: u32;

View file

@ -4,5 +4,5 @@ trait I32Iterator = Iterator<Item = i32>;
fn main() {
let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
//~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
//~^ ERROR conflicting associated type bounds
}

View file

@ -1,11 +1,13 @@
error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
--> $DIR/associated-types-overridden-binding-2.rs:6:43
error: conflicting associated type bounds for `Item` when expanding trait alias
--> $DIR/associated-types-overridden-binding-2.rs:6:13
|
LL | trait I32Iterator = Iterator<Item = i32>;
| ---------- `Item` is specified to be `i32` here
...
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
| ^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
|
= note: required for the cast from `&std::vec::IntoIter<u32>` to `&dyn Iterator<Item = u32, Item = i32>`
| ^^^^^^^^^^^^^^^^----------^
| |
| `Item` is specified to be `u32` here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0271`.

View file

@ -8,4 +8,5 @@ trait U32Iterator = I32Iterator<Item = u32>; //~ ERROR type annotations needed
fn main() {
let _: &dyn I32Iterator<Item = u32>;
//~^ ERROR conflicting associated type bounds
}

View file

@ -22,6 +22,17 @@ note: required by a bound in `I32Iterator`
LL | trait I32Iterator = Iterator<Item = i32>;
| ^^^^^^^^^^ required by this bound in `I32Iterator`
error: aborting due to 2 previous errors
error: conflicting associated type bounds for `Item` when expanding trait alias
--> $DIR/associated-types-overridden-binding.rs:10:13
|
LL | trait I32Iterator = Iterator<Item = i32>;
| ---------- `Item` is specified to be `i32` here
...
LL | let _: &dyn I32Iterator<Item = u32>;
| ^^^^^^^^^^^^^^^^----------^
| |
| `Item` is specified to be `u32` here
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0284`.

View file

@ -17,8 +17,6 @@ LL | | test()?;
... |
LL | | }
| |_- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `FromResidual<_>` is not implemented for `()`
error: aborting due to 2 previous errors

View file

@ -6,8 +6,6 @@ LL | async {
LL | let x: Option<u32> = None;
LL | x?;
| ^ cannot use the `?` operator in an async block that returns `{integer}`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-in-async.rs:16:10
@ -20,8 +18,6 @@ LL | | x?;
LL | | 22_u32
LL | | };
| |_____- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-in-async.rs:25:6
@ -34,8 +30,6 @@ LL | | x?;
LL | | 22
LL | | }
| |_- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
error: aborting due to 3 previous errors

View file

@ -0,0 +1,18 @@
//@ check-pass
// This test checks that we look at consider the super traits of trait objects
// when deducing closure signatures.
trait Foo: Fn(Bar) {}
impl<T> Foo for T where T: Fn(Bar) {}
struct Bar;
impl Bar {
fn bar(&self) {}
}
fn main() {
let x: &dyn Foo = &|x| {
x.bar();
};
}

View file

@ -0,0 +1,21 @@
//@ check-pass
// We previously incorrectly deduplicated the list of projection bounds
// of trait objects, causing us to incorrectly reject this code, cc #136458.
trait Sup<T> {
type Assoc;
}
impl<T> Sup<T> for () {
type Assoc = T;
}
trait Trait<A, B>: Sup<A, Assoc = A> + Sup<B, Assoc = B> {}
impl<T, U> Trait<T, U> for () {}
fn main() {
let x: &dyn Trait<(), _> = &();
let y: &dyn Trait<_, ()> = x;
}

View file

@ -1,13 +1,13 @@
//@ known-bug: #117647
//@ edition: 2024
#![feature(lifetime_capture_rules_2024)]
#![feature(rustc_attrs)]
#![allow(internal_features)]
#![rustc_variance_of_opaques]
use std::ops::Deref;
fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> { //~ ['a: o]
//~^ ERROR cannot capture higher-ranked lifetime
Box::new(x)
}

View file

@ -1,17 +1,17 @@
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
--> $DIR/implicit-capture-late.rs:10:55
--> $DIR/implicit-capture-late.rs:9:55
|
LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
| ^^^^^^^^^^^ `impl Trait` implicitly captures all lifetimes in scope
|
note: lifetime declared here
--> $DIR/implicit-capture-late.rs:10:36
--> $DIR/implicit-capture-late.rs:9:36
|
LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
| ^^
error: ['a: o]
--> $DIR/implicit-capture-late.rs:10:55
--> $DIR/implicit-capture-late.rs:9:55
|
LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
| ^^^^^^^^^^^

View file

@ -1,9 +1,8 @@
//@ check-pass
//@ edition: 2024
// Show how precise captures allow us to skip capturing a higher-ranked lifetime
#![feature(lifetime_capture_rules_2024)]
trait Trait<'a> {
type Item;
}

View file

@ -1,9 +1,8 @@
//@ check-pass
//@ edition: 2024
// Show that precise captures allow us to skip a lifetime param for outlives
#![feature(lifetime_capture_rules_2024)]
fn hello<'a: 'a, 'b: 'b>() -> impl Sized + use<'a> { }
fn outlives<'a, T: 'a>(_: T) {}

View file

@ -1,23 +1,23 @@
error: ['a: *, 'a: o]
--> $DIR/variance.rs:13:36
--> $DIR/variance.rs:11:36
|
LL | fn not_captured_early<'a: 'a>() -> impl Sized {}
| ^^^^^^^^^^
error: ['a: *, 'a: o]
--> $DIR/variance.rs:18:32
--> $DIR/variance.rs:15:32
|
LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: ['a: o]
--> $DIR/variance.rs:20:40
--> $DIR/variance.rs:17:40
|
LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
| ^^^^^^^^^^
error: ['a: o]
--> $DIR/variance.rs:25:36
--> $DIR/variance.rs:21:36
|
LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,26 +0,0 @@
error: ['a: *, 'a: o]
--> $DIR/variance.rs:13:36
|
LL | fn not_captured_early<'a: 'a>() -> impl Sized {}
| ^^^^^^^^^^
error: ['a: *, 'a: o]
--> $DIR/variance.rs:18:32
|
LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: ['a: o]
--> $DIR/variance.rs:20:40
|
LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
| ^^^^^^^^^^
error: ['a: o]
--> $DIR/variance.rs:25:36
|
LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors

View file

@ -1,23 +1,23 @@
error: ['a: *]
--> $DIR/variance.rs:13:36
--> $DIR/variance.rs:11:36
|
LL | fn not_captured_early<'a: 'a>() -> impl Sized {}
| ^^^^^^^^^^
error: ['a: *, 'a: o]
--> $DIR/variance.rs:18:32
--> $DIR/variance.rs:15:32
|
LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: []
--> $DIR/variance.rs:20:40
--> $DIR/variance.rs:17:40
|
LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
| ^^^^^^^^^^
error: ['a: o]
--> $DIR/variance.rs:25:36
--> $DIR/variance.rs:21:36
|
LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,8 +1,6 @@
//@ revisions: old new e2024
//@ revisions: old e2024
//@[e2024] edition: 2024
#![cfg_attr(new, feature(lifetime_capture_rules_2024))]
#![feature(rustc_attrs)]
#![allow(internal_features)]
#![rustc_variance_of_opaques]
@ -12,15 +10,13 @@ impl<T> Captures<'_> for T {}
fn not_captured_early<'a: 'a>() -> impl Sized {}
//[old]~^ ['a: *]
//[new]~^^ ['a: *, 'a: o]
//[e2024]~^^^ ['a: *, 'a: o]
//[e2024]~^^ ['a: *, 'a: o]
fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ ['a: *, 'a: o]
fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
//[old]~^ []
//[new]~^^ ['a: o]
//[e2024]~^^^ ['a: o]
//[e2024]~^^ ['a: o]
fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ ['a: o]

View file

@ -0,0 +1,27 @@
//! With `feature(generic_const_exprs)`, anon consts (e.g. length in array types) will
//! inherit their parent's predicates. When combined with `feature(trivial_bounds)`, it
//! is possible to have an unevaluated constant that is rigid, but not generic.
//!
//! This is what happens below: `u8: A` does not hold in the global environment, but
//! with trivial bounds + GCE it it possible that `<u8 as A>::B` can appear in an array
//! length without causing a compile error. This constant is *rigid* (i.e. it cannot be
//! normalized further), but it is *not generic* (i.e. it does not depend on any generic
//! parameters).
//!
//! This test ensures that we do not ICE in layout computation when encountering such a
//! constant.
#![feature(rustc_attrs)]
#![feature(generic_const_exprs)] //~ WARNING: the feature `generic_const_exprs` is incomplete
#![feature(trivial_bounds)]
#![crate_type = "lib"]
trait A {
const B: usize;
}
#[rustc_layout(debug)]
struct S([u8; <u8 as A>::B]) //~ ERROR: the type `[u8; <u8 as A>::B]` has an unknown layout
where
u8: A;

View file

@ -0,0 +1,17 @@
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/gce-rigid-const-in-array-len.rs:15:12
|
LL | #![feature(generic_const_exprs)]
| ^^^^^^^^^^^^^^^^^^^
|
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
= note: `#[warn(incomplete_features)]` on by default
error: the type `[u8; <u8 as A>::B]` has an unknown layout
--> $DIR/gce-rigid-const-in-array-len.rs:25:1
|
LL | struct S([u8; <u8 as A>::B])
| ^^^^^^^^
error: aborting due to 1 previous error; 1 warning emitted

View file

@ -0,0 +1,18 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/137308>.
//!
//! This used to ICE in layout computation, because `<u8 as A>::B` fails to normalize
//! due to the unconstrained param on the impl.
#![feature(rustc_attrs)]
#![crate_type = "lib"]
trait A {
const B: usize;
}
impl<C: ?Sized> A for u8 { //~ ERROR: the type parameter `C` is not constrained
const B: usize = 42;
}
#[rustc_layout(debug)]
struct S([u8; <u8 as A>::B]); //~ ERROR: the type has an unknown layout

View file

@ -0,0 +1,15 @@
error[E0207]: the type parameter `C` is not constrained by the impl trait, self type, or predicates
--> $DIR/unconstrained-param-ice-137308.rs:13:6
|
LL | impl<C: ?Sized> A for u8 {
| ^ unconstrained type parameter
error: the type has an unknown layout
--> $DIR/unconstrained-param-ice-137308.rs:18:1
|
LL | struct S([u8; <u8 as A>::B]);
| ^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0207`.

View file

@ -0,0 +1,27 @@
//@ check-pass
// Regression test for <https://github.com/rust-lang/rust/issues/137250>.
// Ensure that we don't emit unaligned packed field reference errors for the fake
// borrows that we generate during match lowering. These fake borrows are there to
// ensure in *borrow-checking* that we don't modify the value being matched, but
// they are removed after the MIR is processed by `CleanupPostBorrowck`.
#[repr(packed)]
pub struct Packed(i32);
fn f(x: Packed) {
match &x {
Packed(4) => {},
_ if true => {},
_ => {}
}
match x {
Packed(4) => {},
_ if true => {},
_ => {}
}
}
fn main() {}

View file

@ -6,7 +6,6 @@ LL | fn test1() {
LL | let mut _file = File::create("foo.txt")?;
| ^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
help: consider adding return type
|
LL ~ fn test1() -> Result<(), Box<dyn std::error::Error>> {
@ -23,7 +22,6 @@ LL | fn test2() {
LL | let mut _file = File::create("foo.txt")?;
| ^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
help: consider adding return type
|
LL ~ fn test2() -> Result<(), Box<dyn std::error::Error>> {
@ -41,7 +39,6 @@ LL | fn test4(&self) {
LL | let mut _file = File::create("foo.txt")?;
| ^ cannot use the `?` operator in a method that returns `()`
|
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
help: consider adding return type
|
LL ~ fn test4(&self) -> Result<(), Box<dyn std::error::Error>> {
@ -59,7 +56,6 @@ LL | fn test5(&self) {
LL | let mut _file = File::create("foo.txt")?;
| ^ cannot use the `?` operator in a method that returns `()`
|
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
help: consider adding return type
|
LL ~ fn test5(&self) -> Result<(), Box<dyn std::error::Error>> {
@ -78,7 +74,6 @@ LL | fn main() {
LL | let mut _file = File::create("foo.txt")?;
| ^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
help: consider adding return type
|
LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> {
@ -99,7 +94,6 @@ LL | let mut _file = File::create("foo.txt")?;
LL | mac!();
| ------ in this macro invocation
|
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider adding return type
|

View file

@ -1,9 +1,12 @@
//@ known-bug: rust-lang/rust#126944
//@ check-pass
// Regression test for #126944.
// Step 1: Create two names for a single type: `Thing` and `AlsoThing`
struct Thing;
struct Dummy;
pub trait DummyTrait {
trait DummyTrait {
type DummyType;
}
impl DummyTrait for Dummy {
@ -13,7 +16,7 @@ type AlsoThing = <Dummy as DummyTrait>::DummyType;
// Step 2: Create names for a single trait object type: `TraitObject` and `AlsoTraitObject`
pub trait SomeTrait {
trait SomeTrait {
type Item;
}
type TraitObject = dyn SomeTrait<Item = AlsoThing>;
@ -21,12 +24,12 @@ type AlsoTraitObject = dyn SomeTrait<Item = Thing>;
// Step 3: Force the compiler to check whether the two names are the same type
pub trait Supertrait {
trait Supertrait {
type Foo;
}
pub trait Subtrait: Supertrait<Foo = TraitObject> {}
trait Subtrait: Supertrait<Foo = TraitObject> {}
pub trait HasOutput<A: ?Sized> {
trait HasOutput<A: ?Sized> {
type Output;
}
@ -36,3 +39,5 @@ where
{
todo!()
}
fn main() {}

View file

@ -0,0 +1,32 @@
// Regression test for #133361.
trait Sup<T> {
type Assoc;
}
impl<T> Sup<T> for () {
type Assoc = T;
}
impl<T, U> Dyn<T, U> for () {}
trait Dyn<A, B>: Sup<A, Assoc = A> + Sup<B, Assoc = B> {}
trait Trait {
type Assoc;
}
impl Trait for dyn Dyn<(), ()> {
type Assoc = &'static str;
}
impl<A, B> Trait for dyn Dyn<A, B> {
//~^ ERROR conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)`
type Assoc = usize;
}
fn call<A, B>(x: usize) -> <dyn Dyn<A, B> as Trait>::Assoc {
x
}
fn main() {
let x: &'static str = call::<(), ()>(0xDEADBEEF);
println!("{x}");
}

View file

@ -0,0 +1,12 @@
error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)`
--> $DIR/incomplete-multiple-super-projection.rs:20:1
|
LL | impl Trait for dyn Dyn<(), ()> {
| ------------------------------ first implementation here
...
LL | impl<A, B> Trait for dyn Dyn<A, B> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Dyn<(), ()> + 'static)`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`.

View file

@ -1,4 +1,4 @@
//@ known-bug: #79590
//@ check-pass
trait Database: Restriction<Inner = u32> {}

View file

@ -0,0 +1,24 @@
//@ check-pass
// Make sure that we still deduce outlives bounds from supertrait projections
// and require them for well-formedness.
trait Trait {
type Assoc;
}
trait Bar {
type Assoc;
}
trait Foo<'a, T: 'a>: Bar<Assoc = &'a T> {
}
fn outlives<'a, T: 'a>() {}
fn implied_outlives<'a, T: Trait>(x: &dyn Foo<'a, T::Assoc>) {
outlives::<'a, T::Assoc>();
}
fn main() {}

View file

@ -154,12 +154,12 @@ error[E0308]: mismatched types
--> $DIR/pretty.rs:41:56
|
LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x }
| - ^ expected `()`, found `&dyn HasGat<u8, Assoc<bool> = ()>`
| - ^ expected `()`, found `&dyn HasGat<u8>`
| |
| help: try adding a return type: `-> &dyn HasGat<u8, Assoc<bool> = ()>`
| help: try adding a return type: `-> &dyn HasGat<u8>`
|
= note: expected unit type `()`
found reference `&dyn HasGat<u8, Assoc<bool> = ()>`
found reference `&dyn HasGat<u8>`
error: aborting due to 14 previous errors; 1 warning emitted

View file

@ -0,0 +1,12 @@
//@ check-pass
trait Foo: Bar<Out = ()> {}
trait Bar {
type Out;
}
fn w(x: &dyn Foo<Out = ()>) {
let x: &dyn Foo = x;
}
fn main() {}

View file

@ -20,9 +20,6 @@ LL | fn option_to_result() -> Result<u64, String> {
| -------------------------------------------- this function returns a `Result`
LL | Some(3)?;
| ^ use `.ok_or(...)?` to provide an error compatible with `Result<u64, String>`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>`
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result`
--> $DIR/bad-interconversion.rs:15:31
@ -31,9 +28,6 @@ LL | fn control_flow_to_result() -> Result<u64, String> {
| -------------------------------------------------- this function returns a `Result`
LL | Ok(ControlFlow::Break(123)?)
| ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result<u64, String>`
|
= help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>`
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
--> $DIR/bad-interconversion.rs:20:22
@ -42,9 +36,6 @@ LL | fn result_to_option() -> Option<u16> {
| ------------------------------------ this function returns an `Option`
LL | Some(Err("hello")?)
| ^ use `.ok()?` if you want to discard the `Result<Infallible, &str>` error information
|
= help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>`
= help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>`
error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
--> $DIR/bad-interconversion.rs:25:33
@ -53,9 +44,6 @@ LL | fn control_flow_to_option() -> Option<u64> {
| ------------------------------------------ this function returns an `Option`
LL | Some(ControlFlow::Break(123)?)
| ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option<u64>`
|
= help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
= help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>`
error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
--> $DIR/bad-interconversion.rs:30:39

View file

@ -0,0 +1,29 @@
struct E;
//~^ NOTE `E` needs to implement `std::error::Error`
//~| NOTE alternatively, `E` needs to implement `Into<X>`
struct X; //~ NOTE `X` needs to implement `From<E>`
fn foo() -> Result<(), Box<dyn std::error::Error>> { //~ NOTE required `E: std::error::Error` because of this
Ok(bar()?)
//~^ ERROR `?` couldn't convert the error: `E: std::error::Error` is not satisfied
//~| NOTE the trait `std::error::Error` is not implemented for `E`
//~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
//~| NOTE required for `Box<dyn std::error::Error>` to implement `From<E>`
//~| NOTE this has type `Result<_, E>`
//~| NOTE in this expansion
//~| NOTE in this expansion
//~| NOTE in this expansion
}
fn bat() -> Result<(), X> { //~ NOTE expected `X` because of this
Ok(bar()?)
//~^ ERROR `?` couldn't convert the error to `X`
//~| NOTE the trait `From<E>` is not implemented for `X`
//~| NOTE this can't be annotated with `?` because it has type `Result<_, E>`
//~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
//~| NOTE in this expansion
//~| NOTE in this expansion
}
fn bar() -> Result<(), E> {
Err(E)
}
fn main() {}

View file

@ -0,0 +1,43 @@
error[E0277]: `?` couldn't convert the error: `E: std::error::Error` is not satisfied
--> $DIR/bad-question-mark-on-trait-object.rs:7:13
|
LL | fn foo() -> Result<(), Box<dyn std::error::Error>> {
| -------------------------------------- required `E: std::error::Error` because of this
LL | Ok(bar()?)
| -----^ the trait `std::error::Error` is not implemented for `E`
| |
| this has type `Result<_, E>`
|
note: `E` needs to implement `std::error::Error`
--> $DIR/bad-question-mark-on-trait-object.rs:1:1
|
LL | struct E;
| ^^^^^^^^
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= note: required for `Box<dyn std::error::Error>` to implement `From<E>`
error[E0277]: `?` couldn't convert the error to `X`
--> $DIR/bad-question-mark-on-trait-object.rs:18:13
|
LL | fn bat() -> Result<(), X> {
| ------------- expected `X` because of this
LL | Ok(bar()?)
| -----^ the trait `From<E>` is not implemented for `X`
| |
| this can't be annotated with `?` because it has type `Result<_, E>`
|
note: `X` needs to implement `From<E>`
--> $DIR/bad-question-mark-on-trait-object.rs:4:1
|
LL | struct X;
| ^^^^^^^^
note: alternatively, `E` needs to implement `Into<X>`
--> $DIR/bad-question-mark-on-trait-object.rs:1:1
|
LL | struct E;
| ^^^^^^^^
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -6,9 +6,6 @@ LL | fn test_result() -> Result<(),()> {
LL | let a:Option<()> = Some(());
LL | a?;
| ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>`
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
--> $DIR/option-to-result.rs:11:6
@ -18,9 +15,6 @@ LL | fn test_option() -> Option<i32>{
LL | let a:Result<i32, i32> = Ok(5);
LL | a?;
| ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information
|
= help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>`
= help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>`
error: aborting due to 2 previous errors

View file

@ -6,8 +6,6 @@ LL | fn a_function() -> u32 {
LL | let x: Option<u32> = None;
LL | x?;
| ^ cannot use the `?` operator in a function that returns `u32`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-diagnostics.rs:14:10
@ -17,8 +15,6 @@ LL | let a_closure = || {
LL | let x: Option<u32> = None;
LL | x?;
| ^ cannot use the `?` operator in a closure that returns `{integer}`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-diagnostics.rs:26:14
@ -28,8 +24,6 @@ LL | fn a_method() {
LL | let x: Option<u32> = None;
LL | x?;
| ^ cannot use the `?` operator in a method that returns `()`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option-diagnostics.rs:39:14
@ -39,8 +33,6 @@ LL | fn a_trait_method() {
LL | let x: Option<u32> = None;
LL | x?;
| ^ cannot use the `?` operator in a trait method that returns `()`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
error: aborting due to 4 previous errors

View file

@ -6,9 +6,6 @@ LL | fn foo() -> Result<u32, ()> {
LL | let x: Option<u32> = None;
LL | x?;
| ^ use `.ok_or(...)?` to provide an error compatible with `Result<u32, ()>`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>`
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/try-on-option.rs:11:6
@ -18,8 +15,6 @@ LL | fn bar() -> u32 {
LL | let x: Option<u32> = None;
LL | x?;
| ^ cannot use the `?` operator in a function that returns `u32`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
error: aborting due to 2 previous errors

View file

@ -7,7 +7,6 @@ LL | // error for a `Try` type on a non-`Try` fn
LL | std::fs::File::open("foo")?;
| ^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
help: consider adding return type
|
LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> {
@ -33,8 +32,6 @@ LL | fn main() {
...
LL | ()?;
| ^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `FromResidual<_>` is not implemented for `()`
error[E0277]: the trait bound `(): Try` is not satisfied
--> $DIR/try-operator-on-main.rs:14:25