Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d442cf5
control libunwind linkage mode via `crt-static` on gnullvm targets
mati865 Sep 28, 2024
b440ef8
Move some alloc tests to the alloctests crate
bjorn3 Dec 4, 2024
3e3bcfa
[CI] Use a lockfile for installing the `datadog` package
Kobzol Dec 9, 2024
3b05779
Add feature gate, not working yet
compiler-errors Nov 16, 2024
a7fa4cb
Implement projection and shim for AFIDT
compiler-errors Nov 16, 2024
57e8a1c
Don't check RPITITs that are Self:Sized for PointerLike
compiler-errors Dec 10, 2024
67df7cb
Simplify `rustc_mir_dataflow::abs_domain`.
nnethercote Dec 8, 2024
f7ca820
Forbid unsafe_op_in_unsafe_fn in hurd-specific os and sys files
sthibaul Dec 10, 2024
014363e
Don't emit "field expressions may not have generic arguments" if it's…
Dec 10, 2024
c04b52a
Add regression tests
oli-obk Dec 9, 2024
f11edf7
allow `symbol_intern_string_literal` lint in test modules
onur-ozkan Dec 11, 2024
1268445
remove `Kind` check for `symbol_intern_string_literal`
onur-ozkan Dec 11, 2024
6a8bc4b
Remove consteval note from <*mut T>::align_offset docs.
zachs18 Dec 11, 2024
6d3d61f
Evaluate constants in SIMD vec lengths before rejecting them
oli-obk Dec 9, 2024
98edb8f
Clarify why a type is rejected for asm!
oli-obk Dec 9, 2024
1bc5897
Stabilize the Rust 2024 prelude
ehuss Dec 11, 2024
40c9645
Remove `PErr`.
nnethercote Dec 12, 2024
2caada1
Properly consider APITs for never type fallback ascription fix
compiler-errors Dec 10, 2024
2779de7
Rollup merge of #122003 - mati865:gnullvm-build-libunwind, r=petroche…
jieyouxu Dec 12, 2024
85ab5be
Rollup merge of #133122 - compiler-errors:afidt, r=oli-obk
jieyouxu Dec 12, 2024
65472d2
Rollup merge of #133859 - bjorn3:move_tests_to_alloctests, r=tgross35
jieyouxu Dec 12, 2024
9aef64f
Rollup merge of #134070 - oli-obk:push-nquzymupzlsq, r=jieyouxu
jieyouxu Dec 12, 2024
95125c1
Rollup merge of #134095 - Kobzol:datadog-lockfile, r=MarcoIeni
jieyouxu Dec 12, 2024
b2434ea
Rollup merge of #134144 - compiler-errors:fallback-apit, r=WaffleLapkin
jieyouxu Dec 12, 2024
41bec17
Rollup merge of #134152 - nnethercote:simplify-rustc_mir_dataflow-abs…
jieyouxu Dec 12, 2024
c5a1869
Rollup merge of #134154 - dev-ardi:field-expr-generics, r=compiler-er…
jieyouxu Dec 12, 2024
6daf30a
Rollup merge of #134155 - sthibaul:unsafe_op_in_unsafe_fn, r=tgross35
jieyouxu Dec 12, 2024
69d9a2a
Rollup merge of #134173 - onur-ozkan:allow-symbol-intern-string-liter…
jieyouxu Dec 12, 2024
3025feb
Rollup merge of #134178 - ehuss:stabilize-2024-prelude, r=amanieu,tra…
jieyouxu Dec 12, 2024
52919ed
Rollup merge of #134179 - zachs18:align_offset_mut_ptr_doc, r=working…
jieyouxu Dec 12, 2024
328b086
Rollup merge of #134187 - nnethercote:rm-PErr, r=jieyouxu
jieyouxu Dec 12, 2024
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implement projection and shim for AFIDT
  • Loading branch information
compiler-errors committed Dec 10, 2024
commit a7fa4cbcb498b80b126a954b5944f19a11e28dec
37 changes: 20 additions & 17 deletions compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -677,23 +677,26 @@ impl<'tcx> Instance<'tcx> {
//
// 1) The underlying method expects a caller location parameter
// in the ABI
if resolved.def.requires_caller_location(tcx)
// 2) The caller location parameter comes from having `#[track_caller]`
// on the implementation, and *not* on the trait method.
&& !tcx.should_inherit_track_caller(def)
// If the method implementation comes from the trait definition itself
// (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`),
// then we don't need to generate a shim. This check is needed because
// `should_inherit_track_caller` returns `false` if our method
// implementation comes from the trait block, and not an impl block
&& !matches!(
tcx.opt_associated_item(def),
Some(ty::AssocItem {
container: ty::AssocItemContainer::Trait,
..
})
)
{
let needs_track_caller_shim = resolved.def.requires_caller_location(tcx)
// 2) The caller location parameter comes from having `#[track_caller]`
// on the implementation, and *not* on the trait method.
&& !tcx.should_inherit_track_caller(def)
// If the method implementation comes from the trait definition itself
// (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`),
// then we don't need to generate a shim. This check is needed because
// `should_inherit_track_caller` returns `false` if our method
// implementation comes from the trait block, and not an impl block
&& !matches!(
tcx.opt_associated_item(def),
Some(ty::AssocItem {
container: ty::AssocItemContainer::Trait,
..
})
);
// We also need to generate a shim if this is an AFIT.
let needs_rpitit_shim =
tcx.return_position_impl_trait_in_trait_shim_data(def).is_some();
if needs_track_caller_shim || needs_rpitit_shim {
if tcx.is_closure_like(def) {
debug!(
" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ mod opaque_types;
mod parameterized;
mod predicate;
mod region;
mod return_position_impl_trait_in_trait;
mod rvalue_scopes;
mod structural_impls;
#[allow(hidden_glob_reexports)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use rustc_hir::def_id::DefId;

use crate::ty::{self, ExistentialPredicateStableCmpExt, TyCtxt};

impl<'tcx> TyCtxt<'tcx> {
/// Given a `def_id` of a trait or impl method, compute whether that method needs to
/// have an RPITIT shim applied to it for it to be object safe. If so, return the
/// `def_id` of the RPITIT, and also the args of trait method that returns the RPITIT.
///
/// NOTE that these args are not, in general, the same as than the RPITIT's args. They
/// are a subset of those args, since they do not include the late-bound lifetimes of
/// the RPITIT. Depending on the context, these will need to be dealt with in different
/// ways -- in codegen, it's okay to fill them with ReErased.
pub fn return_position_impl_trait_in_trait_shim_data(
self,
def_id: DefId,
) -> Option<(DefId, ty::EarlyBinder<'tcx, ty::GenericArgsRef<'tcx>>)> {
let assoc_item = self.opt_associated_item(def_id)?;

let (trait_item_def_id, opt_impl_def_id) = match assoc_item.container {
ty::AssocItemContainer::Impl => {
(assoc_item.trait_item_def_id?, Some(self.parent(def_id)))
}
ty::AssocItemContainer::Trait => (def_id, None),
};

let sig = self.fn_sig(trait_item_def_id);

// Check if the trait returns an RPITIT.
let ty::Alias(ty::Projection, ty::AliasTy { def_id, .. }) =
*sig.skip_binder().skip_binder().output().kind()
else {
return None;
};
if !self.is_impl_trait_in_trait(def_id) {
return None;
}

let args = if let Some(impl_def_id) = opt_impl_def_id {
// Rebase the args from the RPITIT onto the impl trait ref, so we can later
// substitute them with the method args of the *impl* method, since that's
// the instance we're building a vtable shim for.
ty::GenericArgs::identity_for_item(self, trait_item_def_id).rebase_onto(
self,
self.parent(trait_item_def_id),
self.impl_trait_ref(impl_def_id)
.expect("expected impl trait ref from parent of impl item")
.instantiate_identity()
.args,
)
} else {
// This is when we have a default trait implementation.
ty::GenericArgs::identity_for_item(self, trait_item_def_id)
};

Some((def_id, ty::EarlyBinder::bind(args)))
}

/// Given a `DefId` of an RPITIT and its args, return the existential predicates
/// that corresponds to the RPITIT's bounds with the self type erased.
pub fn item_bounds_to_existential_predicates(
self,
def_id: DefId,
args: ty::GenericArgsRef<'tcx>,
) -> &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
let mut bounds: Vec<_> = self
.item_super_predicates(def_id)
.iter_instantiated(self, args)
.filter_map(|clause| {
clause
.kind()
.map_bound(|clause| match clause {
ty::ClauseKind::Trait(trait_pred) => Some(ty::ExistentialPredicate::Trait(
ty::ExistentialTraitRef::erase_self_ty(self, trait_pred.trait_ref),
)),
ty::ClauseKind::Projection(projection_pred) => {
Some(ty::ExistentialPredicate::Projection(
ty::ExistentialProjection::erase_self_ty(self, projection_pred),
))
}
ty::ClauseKind::TypeOutlives(_) => {
// Type outlives bounds don't really turn into anything,
// since we must use an intersection region for the `dyn*`'s
// region anyways.
None
}
_ => unreachable!("unexpected clause in item bounds: {clause:?}"),
})
.transpose()
})
.collect();
bounds.sort_by(|a, b| a.skip_binder().stable_cmp(self, &b.skip_binder()));
self.mk_poly_existential_predicates(&bounds)
}
}
56 changes: 53 additions & 3 deletions compiler/rustc_mir_transform/src/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use rustc_index::{Idx, IndexVec};
use rustc_middle::mir::patch::MirPatch;
use rustc_middle::mir::*;
use rustc_middle::query::Providers;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::{
self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, GenericArgs, Ty, TyCtxt,
};
Expand Down Expand Up @@ -710,6 +711,13 @@ fn build_call_shim<'tcx>(
};

let def_id = instance.def_id();

let rpitit_shim = if let ty::InstanceKind::ReifyShim(..) = instance {
tcx.return_position_impl_trait_in_trait_shim_data(def_id)
} else {
None
};

let sig = tcx.fn_sig(def_id);
let sig = sig.map_bound(|sig| tcx.instantiate_bound_regions_with_erased(sig));

Expand Down Expand Up @@ -765,9 +773,34 @@ fn build_call_shim<'tcx>(
let mut local_decls = local_decls_for_sig(&sig, span);
let source_info = SourceInfo::outermost(span);

let mut destination = Place::return_place();
if let Some((rpitit_def_id, fn_args)) = rpitit_shim {
let rpitit_args =
fn_args.instantiate_identity().extend_to(tcx, rpitit_def_id, |param, _| {
match param.kind {
ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
ty::GenericParamDefKind::Type { .. }
| ty::GenericParamDefKind::Const { .. } => {
unreachable!("rpitit should have no addition ty/ct")
}
}
});
let dyn_star_ty = Ty::new_dynamic(
tcx,
tcx.item_bounds_to_existential_predicates(rpitit_def_id, rpitit_args),
tcx.lifetimes.re_erased,
ty::DynStar,
);
destination = local_decls.push(local_decls[RETURN_PLACE].clone()).into();
local_decls[RETURN_PLACE].ty = dyn_star_ty;
let mut inputs_and_output = sig.inputs_and_output.to_vec();
*inputs_and_output.last_mut().unwrap() = dyn_star_ty;
sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
}

let rcvr_place = || {
assert!(rcvr_adjustment.is_some());
Place::from(Local::new(1 + 0))
Place::from(Local::new(1))
};
let mut statements = vec![];

Expand Down Expand Up @@ -854,7 +887,7 @@ fn build_call_shim<'tcx>(
TerminatorKind::Call {
func: callee,
args,
destination: Place::return_place(),
destination,
target: Some(BasicBlock::new(1)),
unwind: if let Some(Adjustment::RefMut) = rcvr_adjustment {
UnwindAction::Cleanup(BasicBlock::new(3))
Expand Down Expand Up @@ -882,7 +915,24 @@ fn build_call_shim<'tcx>(
);
}
// BB #1/#2 - return
block(&mut blocks, vec![], TerminatorKind::Return, false);
// NOTE: If this is an RPITIT in dyn, we also want to coerce
// the return type of the function into a `dyn*`.
let stmts = if rpitit_shim.is_some() {
vec![Statement {
source_info,
kind: StatementKind::Assign(Box::new((
Place::return_place(),
Rvalue::Cast(
CastKind::PointerCoercion(PointerCoercion::DynStar, CoercionSource::Implicit),
Operand::Move(destination),
sig.output(),
),
))),
}]
} else {
vec![]
};
block(&mut blocks, stmts, TerminatorKind::Return, false);
if let Some(Adjustment::RefMut) = rcvr_adjustment {
// BB #3 - drop if closure panics
block(
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_monomorphize/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ fn custom_coerce_unsize_info<'tcx>(
..
})) => Ok(tcx.coerce_unsized_info(impl_def_id)?.custom_kind.unwrap()),
impl_source => {
bug!("invalid `CoerceUnsized` impl_source: {:?}", impl_source);
bug!(
"invalid `CoerceUnsized` from {source_ty} to {target_ty}: impl_source: {:?}",
impl_source
);
}
}
}
Expand Down
58 changes: 57 additions & 1 deletion compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::DefKind;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin};
use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
use rustc_middle::traits::select::OverflowError;
use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData};
Expand All @@ -18,6 +18,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast};
use rustc_middle::{bug, span_bug};
use rustc_span::symbol::sym;
use thin_vec::thin_vec;
use tracing::{debug, instrument};

use super::{
Expand Down Expand Up @@ -61,6 +62,9 @@ enum ProjectionCandidate<'tcx> {
/// Bounds specified on an object type
Object(ty::PolyProjectionPredicate<'tcx>),

/// Built-in bound for a dyn async fn in trait
ObjectRpitit,

/// From an "impl" (or a "pseudo-impl" returned by select)
Select(Selection<'tcx>),
}
Expand Down Expand Up @@ -827,6 +831,17 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
env_predicates,
false,
);

// `dyn Trait` automagically project their AFITs to `dyn* Future`.
if tcx.is_impl_trait_in_trait(obligation.predicate.def_id)
&& let Some(out_trait_def_id) = data.principal_def_id()
&& let rpitit_trait_def_id = tcx.parent(obligation.predicate.def_id)
&& tcx
.supertrait_def_ids(out_trait_def_id)
.any(|trait_def_id| trait_def_id == rpitit_trait_def_id)
{
candidate_set.push_candidate(ProjectionCandidate::ObjectRpitit);
}
}

#[instrument(
Expand Down Expand Up @@ -1247,6 +1262,8 @@ fn confirm_candidate<'cx, 'tcx>(
ProjectionCandidate::Select(impl_source) => {
confirm_select_candidate(selcx, obligation, impl_source)
}

ProjectionCandidate::ObjectRpitit => confirm_object_rpitit_candidate(selcx, obligation),
};

// When checking for cycle during evaluation, we compare predicates with
Expand Down Expand Up @@ -2034,6 +2051,45 @@ fn confirm_impl_candidate<'cx, 'tcx>(
}
}

fn confirm_object_rpitit_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>,
) -> Progress<'tcx> {
let tcx = selcx.tcx();
let mut obligations = thin_vec![];

// Compute an intersection lifetime for all the input components of this GAT.
let intersection =
selcx.infcx.next_region_var(RegionVariableOrigin::MiscVariable(obligation.cause.span));
for component in obligation.predicate.args {
match component.unpack() {
ty::GenericArgKind::Lifetime(lt) => {
obligations.push(obligation.with(tcx, ty::OutlivesPredicate(lt, intersection)));
}
ty::GenericArgKind::Type(ty) => {
obligations.push(obligation.with(tcx, ty::OutlivesPredicate(ty, intersection)));
}
ty::GenericArgKind::Const(_ct) => {
// Consts have no outlives...
}
}
}

Progress {
term: Ty::new_dynamic(
tcx,
tcx.item_bounds_to_existential_predicates(
obligation.predicate.def_id,
obligation.predicate.args,
),
intersection,
ty::DynStar,
)
.into(),
obligations,
}
}

// Get obligations corresponding to the predicates from the where-clause of the
// associated type itself.
fn assoc_ty_own_obligations<'cx, 'tcx>(
Expand Down
Loading