Skip to content

Commit

Permalink
Auto merge of #115722 - Mark-Simulacrum:beta-backport, r=Mark-Simulacrum
Browse files Browse the repository at this point in the history
[beta] backport

This PR backports:
- #115559: implied bounds: do not ICE on unconstrained region vars
- #115446: fix version for abi_thiscall to 1.73.0, which was forgotten to change when stabilized and (later) moved to beta
- #115276: rustdoc: correctly deal with self ty params when eliding default object lifetimes

r? `@Mark-Simulacrum`
  • Loading branch information
bors committed Sep 9, 2023
2 parents 9f37cd4 + 309468c commit ea99593
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 18 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ declare_features! (
/// instead of just the platforms on which it is the C ABI.
(accepted, abi_sysv64, "1.24.0", Some(36167), None),
/// Allows using the `thiscall` ABI.
(accepted, abi_thiscall, "1.19.0", None, None),
(accepted, abi_thiscall, "1.73.0", None, None),
/// Allows using ADX intrinsics from `core::arch::{x86, x86_64}`.
(accepted, adx_target_feature, "1.61.0", Some(44839), None),
/// Allows explicit discriminants on non-unit enum variants.
Expand Down
14 changes: 5 additions & 9 deletions compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,12 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);

// We do not expect existential variables in implied bounds.
// We may however encounter unconstrained lifetime variables in invalid
// code. See #110161 for context.
// We may however encounter unconstrained lifetime variables
// in very rare cases.
//
// See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for
// an example.
assert!(!ty.has_non_region_infer());
if ty.has_infer() {
self.tcx.sess.delay_span_bug(
self.tcx.def_span(body_id),
"skipped implied_outlives_bounds due to unconstrained lifetimes",
);
return vec![];
}

let mut canonical_var_values = OriginalQueryValues::default();
let canonical_ty =
Expand Down
27 changes: 20 additions & 7 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1959,31 +1959,44 @@ fn can_elide_trait_object_lifetime_bound<'tcx>(
#[derive(Debug)]
pub(crate) enum ContainerTy<'tcx> {
Ref(ty::Region<'tcx>),
Regular { ty: DefId, args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, arg: usize },
Regular {
ty: DefId,
args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>,
has_self: bool,
arg: usize,
},
}

impl<'tcx> ContainerTy<'tcx> {
fn object_lifetime_default(self, tcx: TyCtxt<'tcx>) -> ObjectLifetimeDefault<'tcx> {
match self {
Self::Ref(region) => ObjectLifetimeDefault::Arg(region),
Self::Regular { ty: container, args, arg: index } => {
Self::Regular { ty: container, args, has_self, arg: index } => {
let (DefKind::Struct
| DefKind::Union
| DefKind::Enum
| DefKind::TyAlias { .. }
| DefKind::Trait
| DefKind::AssocTy
| DefKind::Variant) = tcx.def_kind(container)
| DefKind::Trait) = tcx.def_kind(container)
else {
return ObjectLifetimeDefault::Empty;
};

let generics = tcx.generics_of(container);
let param = generics.params[index].def_id;
let default = tcx.object_lifetime_default(param);
debug_assert_eq!(generics.parent_count, 0);

// If the container is a trait object type, the arguments won't contain the self type but the
// generics of the corresponding trait will. In such a case, offset the index by one.
// For comparison, if the container is a trait inside a bound, the arguments do contain the
// self type.
let offset =
if !has_self && generics.parent.is_none() && generics.has_self { 1 } else { 0 };
let param = generics.params[index + offset].def_id;

let default = tcx.object_lifetime_default(param);
match default {
rbv::ObjectLifetimeDefault::Param(lifetime) => {
// The index is relative to the parent generics but since we don't have any,
// we don't need to translate it.
let index = generics.param_def_id_to_index[&lifetime];
let arg = args.skip_binder()[index as usize].expect_region();
ObjectLifetimeDefault::Arg(arg)
Expand Down
4 changes: 3 additions & 1 deletion src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,10 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
pub(crate) fn ty_args_to_args<'tcx>(
cx: &mut DocContext<'tcx>,
args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>,
mut skip_first: bool,
has_self: bool,
container: Option<DefId>,
) -> Vec<GenericArg> {
let mut skip_first = has_self;
let mut ret_val =
Vec::with_capacity(args.skip_binder().len().saturating_sub(if skip_first { 1 } else { 0 }));

Expand All @@ -99,6 +100,7 @@ pub(crate) fn ty_args_to_args<'tcx>(
container.map(|container| crate::clean::ContainerTy::Regular {
ty: container,
args,
has_self,
arg: index,
}),
))),
Expand Down
19 changes: 19 additions & 0 deletions tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,22 @@ pub trait HigherRankedBoundTrait1<'e> where for<'l> Self: 'e + 'l {}
pub trait AmbiguousBoundTrait<'a, 'b>: 'a + 'b {}

pub struct AmbiguousBoundWrapper<'a, 'b, T: ?Sized + 'a + 'b>(&'a T, &'b T);

// Trait objects inside of another trait object, a trait bound or an associated type.

pub trait Inner {}
pub trait Outer<T: ?Sized> {}
pub trait Base {
type Type<T: ?Sized>;
}
impl Base for () {
type Type<T: ?Sized> = ();
}

pub type NestedTraitObjects = dyn Outer<dyn Inner>;

pub fn apit_rpit(o: impl Outer<dyn Inner>) -> impl Outer<dyn Inner> {
o
}

pub type AssocTy = <() as Base>::Type<dyn Inner>;
15 changes: 15 additions & 0 deletions tests/rustdoc/inline_cross/dyn_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,18 @@ pub use dyn_trait::BareAmbiguousBoundEarly1;
// @has user/type.BareAmbiguousBoundStatic.html
// @has - '//*[@class="rust item-decl"]//code' "dyn AmbiguousBoundTrait<'o, 'o> + 'static;"
pub use dyn_trait::BareAmbiguousBoundStatic;

// Regression test for issue #115179:

// @has user/type.NestedTraitObjects.html
// @has - '//*[@class="rust item-decl"]//code' "dyn Outer<dyn Inner>;"
pub use dyn_trait::NestedTraitObjects;

// @has user/fn.apit_rpit.html
// @has - '//pre[@class="rust item-decl"]' \
// "apit_rpit(o: impl Outer<dyn Inner>) -> impl Outer<dyn Inner>"
pub use dyn_trait::apit_rpit;

// @has user/type.AssocTy.html
// @has - '//*[@class="rust item-decl"]//code' "<() as Base>::Type<dyn Inner>"
pub use dyn_trait::AssocTy;
28 changes: 28 additions & 0 deletions tests/ui/implied-bounds/implied-bounds-unconstrained-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// check-pass

// Regression test for #112832.
pub trait QueryDb {
type Db;
}

pub struct QueryTable<Q, DB> {
db: DB,
storage: Q,
}

// We normalize `<Q as QueryDb>::Db` to `<Q as AsyncQueryFunction<'d>>::SendDb`
// using the where-bound. 'd is an unconstrained region variable which previously
// triggered an assert.
impl<Q> QueryTable<Q, <Q as QueryDb>::Db> where Q: for<'d> AsyncQueryFunction<'d> {}

pub trait AsyncQueryFunction<'d>: QueryDb<Db = <Self as AsyncQueryFunction<'d>>::SendDb> {
type SendDb: 'd;
}

pub trait QueryStorageOpsAsync<Q>
where
Q: for<'d> AsyncQueryFunction<'d>,
{
}

fn main() {}
20 changes: 20 additions & 0 deletions tests/ui/implied-bounds/implied-bounds-unconstrained-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// check-pass

// Another minimized regression test for #112832.
trait Trait {
type Assoc;
}

trait Sub<'a>: Trait<Assoc = <Self as Sub<'a>>::SubAssoc> {
type SubAssoc;
}

// By using the where-clause we normalize `<T as Trait>::Assoc` to
// `<T as Sub<'a>>::SubAssoc` where `'a` is an unconstrained region
// variable.
fn foo<T>(x: <T as Trait>::Assoc)
where
for<'a> T: Sub<'a>,
{}

fn main() {}

0 comments on commit ea99593

Please sign in to comment.