Merge pull request #4615 from rust-lang/rustup-2025-10-03
Automatic Rustup
This commit is contained in:
commit
179da5da69
503 changed files with 9957 additions and 4879 deletions
|
|
@ -476,9 +476,6 @@
|
|||
# when the stage 0 compiler is actually built from in-tree sources.
|
||||
#build.compiletest-allow-stage0 = false
|
||||
|
||||
# Whether to use the precompiled stage0 libtest with compiletest.
|
||||
#build.compiletest-use-stage0-libtest = true
|
||||
|
||||
# Default value for the `--extra-checks` flag of tidy.
|
||||
#
|
||||
# See `./x test tidy --help` for details.
|
||||
|
|
|
|||
|
|
@ -72,7 +72,11 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
|||
const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
]);
|
||||
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason");
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
|
|
|
|||
|
|
@ -207,10 +207,9 @@ pub fn check_attribute_safety(
|
|||
}
|
||||
}
|
||||
|
||||
// - Normal builtin attribute, or any non-builtin attribute
|
||||
// - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is
|
||||
// not permitted on non-builtin attributes or normal builtin attributes
|
||||
(Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => {
|
||||
// - Normal builtin attribute
|
||||
// - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes
|
||||
(Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
|
||||
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
|
||||
span: unsafe_span,
|
||||
name: attr_item.path.clone(),
|
||||
|
|
@ -224,9 +223,8 @@ pub fn check_attribute_safety(
|
|||
}
|
||||
|
||||
// - Non-builtin attribute
|
||||
// - No explicit `#[unsafe(..)]` written.
|
||||
(None, Safety::Default) => {
|
||||
// OK
|
||||
(None, Safety::Unsafe(_) | Safety::Default) => {
|
||||
// OK (not checked here)
|
||||
}
|
||||
|
||||
(
|
||||
|
|
|
|||
|
|
@ -426,7 +426,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub(crate) fn path_does_not_live_long_enough(&self, span: Span, path: &str) -> Diag<'infcx> {
|
||||
struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,)
|
||||
struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path)
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_return_reference_to_local(
|
||||
|
|
@ -480,7 +480,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'infcx> {
|
||||
struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",)
|
||||
struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2992,6 +2992,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.buffer_error(err);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self, explanation))]
|
||||
fn report_local_value_does_not_live_long_enough(
|
||||
&self,
|
||||
location: Location,
|
||||
|
|
@ -3001,13 +3002,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
borrow_spans: UseSpans<'tcx>,
|
||||
explanation: BorrowExplanation<'tcx>,
|
||||
) -> Diag<'infcx> {
|
||||
debug!(
|
||||
"report_local_value_does_not_live_long_enough(\
|
||||
{:?}, {:?}, {:?}, {:?}, {:?}\
|
||||
)",
|
||||
location, name, borrow, drop_span, borrow_spans
|
||||
);
|
||||
|
||||
let borrow_span = borrow_spans.var_or_use_path_span();
|
||||
if let BorrowExplanation::MustBeValidFor {
|
||||
category,
|
||||
|
|
@ -3974,7 +3968,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Index(_)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(_) => kind,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -416,6 +416,26 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
{
|
||||
self.add_object_lifetime_default_note(tcx, err, unsize_ty);
|
||||
}
|
||||
|
||||
let mut preds = path
|
||||
.iter()
|
||||
.filter_map(|constraint| match constraint.category {
|
||||
ConstraintCategory::Predicate(pred) if !pred.is_dummy() => Some(pred),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<Span>>();
|
||||
preds.sort();
|
||||
preds.dedup();
|
||||
if !preds.is_empty() {
|
||||
let s = if preds.len() == 1 { "" } else { "s" };
|
||||
err.span_note(
|
||||
preds,
|
||||
format!(
|
||||
"requirement{s} that the value outlives `{region_name}` introduced here"
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -402,7 +402,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
ProjectionElem::Downcast(..) if opt.including_downcast => return None,
|
||||
ProjectionElem::Downcast(..) => (),
|
||||
ProjectionElem::OpaqueCast(..) => (),
|
||||
ProjectionElem::Subtype(..) => (),
|
||||
ProjectionElem::UnwrapUnsafeBinder(_) => (),
|
||||
ProjectionElem::Field(field, _ty) => {
|
||||
// FIXME(project-rfc_2229#36): print capture precisely here.
|
||||
|
|
@ -484,9 +483,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
|
||||
}
|
||||
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
|
||||
ProjectionElem::Subtype(ty)
|
||||
| ProjectionElem::OpaqueCast(ty)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty),
|
||||
ProjectionElem::OpaqueCast(ty) | ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||
PlaceTy::from_ty(*ty)
|
||||
}
|
||||
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -192,7 +192,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
[
|
||||
..,
|
||||
ProjectionElem::Index(_)
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::OpaqueCast { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
fn mir_borrowck(
|
||||
tcx: TyCtxt<'_>,
|
||||
def: LocalDefId,
|
||||
) -> Result<&ConcreteOpaqueTypes<'_>, ErrorGuaranteed> {
|
||||
) -> Result<&DefinitionSiteHiddenTypes<'_>, ErrorGuaranteed> {
|
||||
assert!(!tcx.is_typeck_child(def.to_def_id()));
|
||||
let (input_body, _) = tcx.mir_promoted(def);
|
||||
debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
|
||||
|
|
@ -130,7 +130,7 @@ fn mir_borrowck(
|
|||
Err(guar)
|
||||
} else if input_body.should_skip() {
|
||||
debug!("Skipping borrowck because of injected body");
|
||||
let opaque_types = ConcreteOpaqueTypes(Default::default());
|
||||
let opaque_types = DefinitionSiteHiddenTypes(Default::default());
|
||||
Ok(tcx.arena.alloc(opaque_types))
|
||||
} else {
|
||||
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None);
|
||||
|
|
@ -278,7 +278,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
|
|||
mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
fold_regions(tcx, self.inner, |r, depth| match r.kind() {
|
||||
ty::ReBound(debruijn, br) => {
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) => {
|
||||
debug_assert_eq!(debruijn, depth);
|
||||
map(ty::RegionVid::from_usize(br.var.index()))
|
||||
}
|
||||
|
|
@ -1989,10 +1989,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
},
|
||||
// `OpaqueCast`: only transmutes the type, so no moves there.
|
||||
// `Downcast` : only changes information about a `Place` without moving.
|
||||
// `Subtype` : only transmutes the type, so no moves.
|
||||
// So it's safe to skip these.
|
||||
ProjectionElem::OpaqueCast(_)
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Downcast(_, _)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(_) => (),
|
||||
}
|
||||
|
|
@ -2218,7 +2216,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
for (place_base, elem) in place.iter_projections().rev() {
|
||||
match elem {
|
||||
ProjectionElem::Index(_/*operand*/) |
|
||||
ProjectionElem::Subtype(_) |
|
||||
ProjectionElem::OpaqueCast(_) |
|
||||
ProjectionElem::ConstantIndex { .. } |
|
||||
// assigning to P[i] requires P to be valid.
|
||||
|
|
@ -2610,7 +2607,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
| ProjectionElem::Index(..)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Subtype(..)
|
||||
| ProjectionElem::OpaqueCast { .. }
|
||||
| ProjectionElem::Downcast(..)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(_) => {
|
||||
|
|
|
|||
|
|
@ -249,7 +249,6 @@ fn place_components_conflict<'tcx>(
|
|||
| (ProjectionElem::ConstantIndex { .. }, _, _)
|
||||
| (ProjectionElem::Subslice { .. }, _, _)
|
||||
| (ProjectionElem::OpaqueCast { .. }, _, _)
|
||||
| (ProjectionElem::Subtype(_), _, _)
|
||||
| (ProjectionElem::Downcast { .. }, _, _)
|
||||
| (ProjectionElem::UnwrapUnsafeBinder(_), _, _) => {
|
||||
// Recursive case. This can still be disjoint on a
|
||||
|
|
@ -510,7 +509,6 @@ fn place_projection_conflict<'tcx>(
|
|||
| ProjectionElem::Field(..)
|
||||
| ProjectionElem::Index(..)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::OpaqueCast { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Downcast(..),
|
||||
|
|
|
|||
|
|
@ -77,9 +77,6 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
|
|||
| ProjectionElem::Index(_) => {
|
||||
cursor = cursor_base;
|
||||
}
|
||||
ProjectionElem::Subtype(..) => {
|
||||
panic!("Subtype projection is not allowed before borrow check")
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
match self.kind {
|
||||
PrefixSet::Shallow => {
|
||||
|
|
|
|||
|
|
@ -1382,10 +1382,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
|
||||
/// The constraints we get from equating the hidden type of each use of an opaque
|
||||
/// with its final concrete type may end up getting preferred over other, potentially
|
||||
/// with its final hidden type may end up getting preferred over other, potentially
|
||||
/// longer constraint paths.
|
||||
///
|
||||
/// Given that we compute the final concrete type by relying on this existing constraint
|
||||
/// Given that we compute the final hidden type by relying on this existing constraint
|
||||
/// path, this can easily end up hiding the actual reason for why we require these regions
|
||||
/// to be equal.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
|||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, OpaqueTypeStorageEntries};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::mir::{Body, ConcreteOpaqueTypes, ConstraintCategory};
|
||||
use rustc_middle::mir::{Body, ConstraintCategory, DefinitionSiteHiddenTypes};
|
||||
use rustc_middle::ty::{
|
||||
self, DefiningScopeKind, EarlyBinder, FallibleTypeFolder, GenericArg, GenericArgsRef,
|
||||
OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable,
|
||||
|
|
@ -129,9 +129,9 @@ fn nll_var_to_universal_region<'tcx>(
|
|||
/// Collect all defining uses of opaque types inside of this typeck root. This
|
||||
/// expects the hidden type to be mapped to the definition parameters of the opaque
|
||||
/// and errors if we end up with distinct hidden types.
|
||||
fn add_concrete_opaque_type<'tcx>(
|
||||
fn add_hidden_type<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
hidden_ty: OpaqueHiddenType<'tcx>,
|
||||
) {
|
||||
|
|
@ -139,7 +139,7 @@ fn add_concrete_opaque_type<'tcx>(
|
|||
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to
|
||||
// `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we
|
||||
// only know that once we convert the generic parameters to those of the opaque type.
|
||||
if let Some(prev) = concrete_opaque_types.0.get_mut(&def_id) {
|
||||
if let Some(prev) = hidden_types.0.get_mut(&def_id) {
|
||||
if prev.ty != hidden_ty.ty {
|
||||
let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| {
|
||||
let (Ok(e) | Err(e)) = prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit());
|
||||
|
|
@ -151,15 +151,15 @@ fn add_concrete_opaque_type<'tcx>(
|
|||
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
|
||||
prev.span = prev.span.substitute_dummy(hidden_ty.span);
|
||||
} else {
|
||||
concrete_opaque_types.0.insert(def_id, hidden_ty);
|
||||
hidden_types.0.insert(def_id, hidden_ty);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_concrete_opaque_type<'tcx>(
|
||||
concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>,
|
||||
fn get_hidden_type<'tcx>(
|
||||
hidden_types: &DefinitionSiteHiddenTypes<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> Option<EarlyBinder<'tcx, OpaqueHiddenType<'tcx>>> {
|
||||
concrete_opaque_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty))
|
||||
hidden_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -173,22 +173,22 @@ struct DefiningUse<'tcx> {
|
|||
}
|
||||
|
||||
/// This computes the actual hidden types of the opaque types and maps them to their
|
||||
/// definition sites. Outside of registering the computed concrete types this function
|
||||
/// definition sites. Outside of registering the computed hidden types this function
|
||||
/// does not mutate the current borrowck state.
|
||||
///
|
||||
/// While it may fail to infer the hidden type and return errors, we always apply
|
||||
/// the computed concrete hidden type to all opaque type uses to check whether they
|
||||
/// the computed hidden type to all opaque type uses to check whether they
|
||||
/// are correct. This is necessary to support non-defining uses of opaques in their
|
||||
/// defining scope.
|
||||
///
|
||||
/// It also means that this whole function is not really soundness critical as we
|
||||
/// recheck all uses of the opaques regardless.
|
||||
pub(crate) fn compute_concrete_opaque_types<'tcx>(
|
||||
pub(crate) fn compute_definition_site_hidden_types<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
|
||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
|
||||
let mut errors = Vec::new();
|
||||
|
|
@ -201,8 +201,7 @@ pub(crate) fn compute_concrete_opaque_types<'tcx>(
|
|||
// We start by checking each use of an opaque type during type check and
|
||||
// check whether the generic arguments of the opaque type are fully
|
||||
// universal, if so, it's a defining use.
|
||||
let defining_uses =
|
||||
collect_defining_uses(&mut rcx, concrete_opaque_types, opaque_types, &mut errors);
|
||||
let defining_uses = collect_defining_uses(&mut rcx, hidden_types, opaque_types, &mut errors);
|
||||
|
||||
// We now compute and apply member constraints for all regions in the hidden
|
||||
// types of each defining use. This mutates the region values of the `rcx` which
|
||||
|
|
@ -210,11 +209,11 @@ pub(crate) fn compute_concrete_opaque_types<'tcx>(
|
|||
apply_member_constraints(&mut rcx, &defining_uses);
|
||||
|
||||
// After applying member constraints, we now check whether all member regions ended
|
||||
// up equal to one of their choice regions and compute the actual concrete type of
|
||||
// up equal to one of their choice regions and compute the actual hidden type of
|
||||
// the opaque type definition. This is stored in the `root_cx`.
|
||||
compute_concrete_types_from_defining_uses(
|
||||
compute_definition_site_hidden_types_from_defining_uses(
|
||||
&rcx,
|
||||
concrete_opaque_types,
|
||||
hidden_types,
|
||||
&defining_uses,
|
||||
&mut errors,
|
||||
);
|
||||
|
|
@ -224,7 +223,7 @@ pub(crate) fn compute_concrete_opaque_types<'tcx>(
|
|||
#[instrument(level = "debug", skip_all, ret)]
|
||||
fn collect_defining_uses<'tcx>(
|
||||
rcx: &mut RegionCtxt<'_, 'tcx>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
|
||||
) -> Vec<DefiningUse<'tcx>> {
|
||||
|
|
@ -244,9 +243,9 @@ fn collect_defining_uses<'tcx>(
|
|||
// with `TypingMode::Borrowck`.
|
||||
if infcx.tcx.use_typing_mode_borrowck() {
|
||||
match err {
|
||||
NonDefiningUseReason::Tainted(guar) => add_concrete_opaque_type(
|
||||
NonDefiningUseReason::Tainted(guar) => add_hidden_type(
|
||||
infcx.tcx,
|
||||
concrete_opaque_types,
|
||||
hidden_types,
|
||||
opaque_type_key.def_id,
|
||||
OpaqueHiddenType::new_error(infcx.tcx, guar),
|
||||
),
|
||||
|
|
@ -277,9 +276,9 @@ fn collect_defining_uses<'tcx>(
|
|||
defining_uses
|
||||
}
|
||||
|
||||
fn compute_concrete_types_from_defining_uses<'tcx>(
|
||||
fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
|
||||
rcx: &RegionCtxt<'_, 'tcx>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>,
|
||||
defining_uses: &[DefiningUse<'tcx>],
|
||||
errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
|
||||
) {
|
||||
|
|
@ -358,9 +357,9 @@ fn compute_concrete_types_from_defining_uses<'tcx>(
|
|||
},
|
||||
));
|
||||
}
|
||||
add_concrete_opaque_type(
|
||||
add_hidden_type(
|
||||
tcx,
|
||||
concrete_opaque_types,
|
||||
hidden_types,
|
||||
opaque_type_key.def_id,
|
||||
OpaqueHiddenType { span: hidden_type.span, ty },
|
||||
);
|
||||
|
|
@ -489,20 +488,20 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ToArgRegionsFolder<'_, 'tcx> {
|
|||
///
|
||||
/// It does this by equating the hidden type of each use with the instantiated final
|
||||
/// hidden type of the opaque.
|
||||
pub(crate) fn apply_computed_concrete_opaque_types<'tcx>(
|
||||
pub(crate) fn apply_definition_site_hidden_types<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
region_bound_pairs: &RegionBoundPairs<'tcx>,
|
||||
known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
let mut errors = Vec::new();
|
||||
for &(key, hidden_type) in opaque_types {
|
||||
let Some(expected) = get_concrete_opaque_type(concrete_opaque_types, key.def_id) else {
|
||||
let Some(expected) = get_hidden_type(hidden_types, key.def_id) else {
|
||||
if !tcx.use_typing_mode_borrowck() {
|
||||
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
|
||||
&& alias_ty.def_id == key.def_id.to_def_id()
|
||||
|
|
@ -521,12 +520,7 @@ pub(crate) fn apply_computed_concrete_opaque_types<'tcx>(
|
|||
hidden_type.span,
|
||||
"non-defining use in the defining scope with no defining uses",
|
||||
);
|
||||
add_concrete_opaque_type(
|
||||
tcx,
|
||||
concrete_opaque_types,
|
||||
key.def_id,
|
||||
OpaqueHiddenType::new_error(tcx, guar),
|
||||
);
|
||||
add_hidden_type(tcx, hidden_types, key.def_id, OpaqueHiddenType::new_error(tcx, guar));
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -566,18 +560,13 @@ pub(crate) fn apply_computed_concrete_opaque_types<'tcx>(
|
|||
"equating opaque types",
|
||||
),
|
||||
) {
|
||||
add_concrete_opaque_type(
|
||||
tcx,
|
||||
concrete_opaque_types,
|
||||
key.def_id,
|
||||
OpaqueHiddenType::new_error(tcx, guar),
|
||||
);
|
||||
add_hidden_type(tcx, hidden_types, key.def_id, OpaqueHiddenType::new_error(tcx, guar));
|
||||
}
|
||||
}
|
||||
errors
|
||||
}
|
||||
|
||||
/// In theory `apply_concrete_opaque_types` could introduce new uses of opaque types.
|
||||
/// In theory `apply_definition_site_hidden_types` could introduce new uses of opaque types.
|
||||
/// We do not check these new uses so this could be unsound.
|
||||
///
|
||||
/// We detect any new uses and simply delay a bug if they occur. If this results in
|
||||
|
|
@ -682,13 +671,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
///
|
||||
/// (*) C1 and C2 were introduced in the comments on
|
||||
/// `register_member_constraints`. Read that comment for more context.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `def_id`, the `impl Trait` type
|
||||
/// - `args`, the args used to instantiate this opaque type
|
||||
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
|
||||
/// `opaque_defn.concrete_ty`
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn infer_opaque_definition_from_instantiation(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ use smallvec::SmallVec;
|
|||
use crate::consumers::BorrowckConsumer;
|
||||
use crate::nll::compute_closure_requirements_modulo_opaques;
|
||||
use crate::region_infer::opaque_types::{
|
||||
apply_computed_concrete_opaque_types, clone_and_resolve_opaque_types,
|
||||
compute_concrete_opaque_types, detect_opaque_types_added_while_handling_opaque_types,
|
||||
apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
|
||||
compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
|
||||
};
|
||||
use crate::type_check::{Locations, constraint_conversion};
|
||||
use crate::{
|
||||
ClosureRegionRequirements, CollectRegionConstraintsResult, ConcreteOpaqueTypes,
|
||||
ClosureRegionRequirements, CollectRegionConstraintsResult, DefinitionSiteHiddenTypes,
|
||||
PropagatedBorrowCheckResults, borrowck_check_region_constraints,
|
||||
borrowck_collect_region_constraints,
|
||||
};
|
||||
|
|
@ -27,7 +27,7 @@ use crate::{
|
|||
pub(super) struct BorrowCheckRootCtxt<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
root_def_id: LocalDefId,
|
||||
concrete_opaque_types: ConcreteOpaqueTypes<'tcx>,
|
||||
hidden_types: DefinitionSiteHiddenTypes<'tcx>,
|
||||
/// The region constraints computed by [borrowck_collect_region_constraints]. This uses
|
||||
/// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
|
||||
/// their parents.
|
||||
|
|
@ -49,7 +49,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
BorrowCheckRootCtxt {
|
||||
tcx,
|
||||
root_def_id,
|
||||
concrete_opaque_types: Default::default(),
|
||||
hidden_types: Default::default(),
|
||||
collect_region_constraints_results: Default::default(),
|
||||
propagated_borrowck_results: Default::default(),
|
||||
tainted_by_errors: None,
|
||||
|
|
@ -72,11 +72,11 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
&self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars
|
||||
}
|
||||
|
||||
pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> {
|
||||
pub(super) fn finalize(self) -> Result<&'tcx DefinitionSiteHiddenTypes<'tcx>, ErrorGuaranteed> {
|
||||
if let Some(guar) = self.tainted_by_errors {
|
||||
Err(guar)
|
||||
} else {
|
||||
Ok(self.tcx.arena.alloc(self.concrete_opaque_types))
|
||||
Ok(self.tcx.arena.alloc(self.hidden_types))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -88,12 +88,12 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
&input.universal_region_relations,
|
||||
&mut input.constraints,
|
||||
);
|
||||
input.deferred_opaque_type_errors = compute_concrete_opaque_types(
|
||||
input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
|
||||
&input.infcx,
|
||||
&input.universal_region_relations,
|
||||
&input.constraints,
|
||||
Rc::clone(&input.location_map),
|
||||
&mut self.concrete_opaque_types,
|
||||
&mut self.hidden_types,
|
||||
&opaque_types,
|
||||
);
|
||||
per_body_info.push((num_entries, opaque_types));
|
||||
|
|
@ -103,14 +103,14 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
self.collect_region_constraints_results.values_mut().zip(per_body_info)
|
||||
{
|
||||
if input.deferred_opaque_type_errors.is_empty() {
|
||||
input.deferred_opaque_type_errors = apply_computed_concrete_opaque_types(
|
||||
input.deferred_opaque_type_errors = apply_definition_site_hidden_types(
|
||||
&input.infcx,
|
||||
&input.body_owned,
|
||||
&input.universal_region_relations.universal_regions,
|
||||
&input.region_bound_pairs,
|
||||
&input.known_type_outlives_obligations,
|
||||
&mut input.constraints,
|
||||
&mut self.concrete_opaque_types,
|
||||
&mut self.hidden_types,
|
||||
&opaque_types,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1558,6 +1558,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
),
|
||||
}
|
||||
}
|
||||
CastKind::Subtype => {
|
||||
bug!("CastKind::Subtype shouldn't exist in borrowck")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1882,9 +1885,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
)
|
||||
.unwrap();
|
||||
}
|
||||
ProjectionElem::Subtype(_) => {
|
||||
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2412,9 +2412,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
| ProjectionElem::UnwrapUnsafeBinder(_) => {
|
||||
// other field access
|
||||
}
|
||||
ProjectionElem::Subtype(_) => {
|
||||
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -789,7 +789,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
|
|||
let operand = codegen_operand(fx, operand);
|
||||
crate::unsize::coerce_unsized_into(fx, operand, lval);
|
||||
}
|
||||
Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => {
|
||||
Rvalue::Cast(CastKind::Transmute | CastKind::Subtype, ref operand, _to_ty) => {
|
||||
let operand = codegen_operand(fx, operand);
|
||||
lval.write_cvalue_transmute(fx, operand);
|
||||
}
|
||||
|
|
@ -996,7 +996,7 @@ pub(crate) fn codegen_place<'tcx>(
|
|||
cplace = cplace.place_deref(fx);
|
||||
}
|
||||
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
|
||||
PlaceElem::Subtype(ty) | PlaceElem::UnwrapUnsafeBinder(ty) => {
|
||||
PlaceElem::UnwrapUnsafeBinder(ty) => {
|
||||
cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty));
|
||||
}
|
||||
PlaceElem::Field(field, _ty) => {
|
||||
|
|
|
|||
|
|
@ -660,7 +660,7 @@ impl<'tcx> CPlace<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Used for `ProjectionElem::Subtype`, `ty` has to be monomorphized before
|
||||
/// Used for `ProjectionElem::UnwrapUnsafeBinder`, `ty` has to be monomorphized before
|
||||
/// passed on.
|
||||
pub(crate) fn place_transmute_type(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@ use rustc_ast::expand::allocator::{
|
|||
};
|
||||
use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{DebugInfo, OomStrategy};
|
||||
use rustc_span::sym;
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
|
||||
use crate::attributes::llfn_attrs_from_instance;
|
||||
|
|
@ -59,7 +60,26 @@ pub(crate) unsafe fn codegen(
|
|||
let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name));
|
||||
let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name));
|
||||
|
||||
create_wrapper_function(tcx, &cx, &from_name, Some(&to_name), &args, output, false);
|
||||
let alloc_attr_flag = match method.name {
|
||||
sym::alloc => CodegenFnAttrFlags::ALLOCATOR,
|
||||
sym::dealloc => CodegenFnAttrFlags::DEALLOCATOR,
|
||||
sym::realloc => CodegenFnAttrFlags::REALLOCATOR,
|
||||
sym::alloc_zeroed => CodegenFnAttrFlags::ALLOCATOR_ZEROED,
|
||||
_ => unreachable!("Unknown allocator method!"),
|
||||
};
|
||||
|
||||
let mut attrs = CodegenFnAttrs::new();
|
||||
attrs.flags |= alloc_attr_flag;
|
||||
create_wrapper_function(
|
||||
tcx,
|
||||
&cx,
|
||||
&from_name,
|
||||
Some(&to_name),
|
||||
&args,
|
||||
output,
|
||||
false,
|
||||
&attrs,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,6 +92,7 @@ pub(crate) unsafe fn codegen(
|
|||
&[usize, usize], // size, align
|
||||
None,
|
||||
true,
|
||||
&CodegenFnAttrs::new(),
|
||||
);
|
||||
|
||||
unsafe {
|
||||
|
|
@ -93,6 +114,7 @@ pub(crate) unsafe fn codegen(
|
|||
&[],
|
||||
None,
|
||||
false,
|
||||
&CodegenFnAttrs::new(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -139,6 +161,7 @@ fn create_wrapper_function(
|
|||
args: &[&Type],
|
||||
output: Option<&Type>,
|
||||
no_return: bool,
|
||||
attrs: &CodegenFnAttrs,
|
||||
) {
|
||||
let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void()));
|
||||
let llfn = declare_simple_fn(
|
||||
|
|
@ -150,8 +173,7 @@ fn create_wrapper_function(
|
|||
ty,
|
||||
);
|
||||
|
||||
let attrs = CodegenFnAttrs::new();
|
||||
llfn_attrs_from_instance(cx, tcx, llfn, &attrs, None);
|
||||
llfn_attrs_from_instance(cx, tcx, llfn, attrs, None);
|
||||
|
||||
let no_return = if no_return {
|
||||
// -> ! DIFlagNoReturn
|
||||
|
|
|
|||
|
|
@ -538,9 +538,7 @@ pub(crate) fn inline_asm_call<'ll>(
|
|||
bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)),
|
||||
)
|
||||
}));
|
||||
let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) };
|
||||
let md = bx.get_metadata_value(md);
|
||||
llvm::LLVMSetMetadata(call, kind, md);
|
||||
bx.cx.set_metadata_node(call, kind, &srcloc);
|
||||
|
||||
Some(call)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use std::borrow::{Borrow, Cow};
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
use std::{iter, ptr};
|
||||
|
||||
use rustc_ast::expand::typetree::FncTree;
|
||||
pub(crate) mod autodiff;
|
||||
pub(crate) mod gpu_offload;
|
||||
|
||||
use libc::{c_char, c_uint, size_t};
|
||||
use libc::{c_char, c_uint};
|
||||
use rustc_abi as abi;
|
||||
use rustc_abi::{Align, Size, WrappingRange};
|
||||
use rustc_codegen_ssa::MemFlags;
|
||||
|
|
@ -396,10 +396,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
md.push(weight(is_cold));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let md_node = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len() as size_t);
|
||||
self.cx.set_metadata(switch, llvm::MD_prof, md_node);
|
||||
}
|
||||
self.cx.set_metadata_node(switch, llvm::MD_prof, &md);
|
||||
}
|
||||
|
||||
fn invoke(
|
||||
|
|
@ -801,22 +798,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let llty = self.cx.val_ty(load);
|
||||
let md = [
|
||||
llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)),
|
||||
llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))),
|
||||
];
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len());
|
||||
self.set_metadata(load, llvm::MD_range, md);
|
||||
}
|
||||
let llty = self.cx.val_ty(load);
|
||||
let md = [
|
||||
llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)),
|
||||
llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))),
|
||||
];
|
||||
self.set_metadata_node(load, llvm::MD_range, &md);
|
||||
}
|
||||
|
||||
fn nonnull_metadata(&mut self, load: &'ll Value) {
|
||||
unsafe {
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
|
||||
self.set_metadata(load, llvm::MD_nonnull, md);
|
||||
}
|
||||
self.set_metadata_node(load, llvm::MD_nonnull, &[]);
|
||||
}
|
||||
|
||||
fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
|
||||
|
|
@ -865,8 +856,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
//
|
||||
// [1]: https://llvm.org/docs/LangRef.html#store-instruction
|
||||
let one = llvm::LLVMValueAsMetadata(self.cx.const_i32(1));
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, &one, 1);
|
||||
self.set_metadata(store, llvm::MD_nontemporal, md);
|
||||
self.set_metadata_node(store, llvm::MD_nontemporal, &[one]);
|
||||
}
|
||||
}
|
||||
store
|
||||
|
|
@ -1381,10 +1371,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
fn set_invariant_load(&mut self, load: &'ll Value) {
|
||||
unsafe {
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
|
||||
self.set_metadata(load, llvm::MD_invariant_load, md);
|
||||
}
|
||||
self.set_metadata_node(load, llvm::MD_invariant_load, &[]);
|
||||
}
|
||||
|
||||
fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) {
|
||||
|
|
@ -1528,25 +1515,16 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
|
|||
}
|
||||
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
||||
fn align_metadata(&mut self, load: &'ll Value, align: Align) {
|
||||
unsafe {
|
||||
let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))];
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len());
|
||||
self.set_metadata(load, llvm::MD_align, md);
|
||||
}
|
||||
let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))];
|
||||
self.set_metadata_node(load, llvm::MD_align, &md);
|
||||
}
|
||||
|
||||
fn noundef_metadata(&mut self, load: &'ll Value) {
|
||||
unsafe {
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
|
||||
self.set_metadata(load, llvm::MD_noundef, md);
|
||||
}
|
||||
self.set_metadata_node(load, llvm::MD_noundef, &[]);
|
||||
}
|
||||
|
||||
pub(crate) fn set_unpredictable(&mut self, inst: &'ll Value) {
|
||||
unsafe {
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
|
||||
self.set_metadata(inst, llvm::MD_unpredictable, md);
|
||||
}
|
||||
self.set_metadata_node(inst, llvm::MD_unpredictable, &[]);
|
||||
}
|
||||
}
|
||||
impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
|
||||
|
|
|
|||
|
|
@ -378,5 +378,12 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>(
|
|||
|
||||
let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
|
||||
|
||||
builder.store_to_place(call, dest.val);
|
||||
let fn_ret_ty = builder.cx.val_ty(call);
|
||||
if fn_ret_ty != builder.cx.type_void() && fn_ret_ty != builder.cx.type_struct(&[], false) {
|
||||
// If we return void or an empty struct, then our caller (due to how we generated it)
|
||||
// does not expect a return value. As such, we have no pointer (or place) into which
|
||||
// we could store our value, and would store into an undef, which would cause UB.
|
||||
// As such, we just ignore the return value in those cases.
|
||||
builder.store_to_place(call, dest.val);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -494,16 +494,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
|
||||
let alloc = self.create_metadata(bytes);
|
||||
let data = [section, alloc];
|
||||
let meta =
|
||||
unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) };
|
||||
let val = self.get_metadata_value(meta);
|
||||
unsafe {
|
||||
llvm::LLVMAddNamedMetadataOperand(
|
||||
self.llmod,
|
||||
c"wasm.custom_sections".as_ptr(),
|
||||
val,
|
||||
)
|
||||
};
|
||||
self.module_add_named_metadata_node(self.llmod(), c"wasm.custom_sections", &data);
|
||||
}
|
||||
} else {
|
||||
base::set_link_section(g, attrs);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ use smallvec::SmallVec;
|
|||
use crate::back::write::to_llvm_code_model;
|
||||
use crate::callee::get_fn;
|
||||
use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
|
||||
use crate::llvm::Metadata;
|
||||
use crate::llvm::{Metadata, MetadataKindId, Module};
|
||||
use crate::type_::Type;
|
||||
use crate::value::Value;
|
||||
use crate::{attributes, common, coverageinfo, debuginfo, llvm, llvm_util};
|
||||
|
|
@ -495,14 +495,7 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"));
|
||||
|
||||
let name_metadata = cx.create_metadata(rustc_producer.as_bytes());
|
||||
|
||||
unsafe {
|
||||
llvm::LLVMAddNamedMetadataOperand(
|
||||
llmod,
|
||||
c"llvm.ident".as_ptr(),
|
||||
&cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)),
|
||||
);
|
||||
}
|
||||
cx.module_add_named_metadata_node(llmod, c"llvm.ident", &[name_metadata]);
|
||||
|
||||
// Emit RISC-V specific target-abi metadata
|
||||
// to workaround lld as the LTO plugin not
|
||||
|
|
@ -1002,15 +995,75 @@ impl CodegenCx<'_, '_> {
|
|||
}
|
||||
|
||||
impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
||||
/// Wrapper for `LLVMMDNodeInContext2`, i.e. `llvm::MDNode::get`.
|
||||
pub(crate) fn md_node_in_context(&self, md_list: &[&'ll Metadata]) -> &'ll Metadata {
|
||||
unsafe { llvm::LLVMMDNodeInContext2(self.llcx(), md_list.as_ptr(), md_list.len()) }
|
||||
}
|
||||
|
||||
/// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`.
|
||||
pub(crate) fn set_metadata<'a>(
|
||||
&self,
|
||||
val: &'a Value,
|
||||
kind_id: impl Into<llvm::MetadataKindId>,
|
||||
kind_id: MetadataKindId,
|
||||
md: &'ll Metadata,
|
||||
) {
|
||||
let node = self.get_metadata_value(md);
|
||||
llvm::LLVMSetMetadata(val, kind_id.into(), node);
|
||||
llvm::LLVMSetMetadata(val, kind_id, node);
|
||||
}
|
||||
|
||||
/// Helper method for the sequence of calls:
|
||||
/// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
|
||||
/// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`)
|
||||
/// - `LLVMSetMetadata` (to set that node as metadata of `kind_id` for `instruction`)
|
||||
pub(crate) fn set_metadata_node(
|
||||
&self,
|
||||
instruction: &'ll Value,
|
||||
kind_id: MetadataKindId,
|
||||
md_list: &[&'ll Metadata],
|
||||
) {
|
||||
let md = self.md_node_in_context(md_list);
|
||||
self.set_metadata(instruction, kind_id, md);
|
||||
}
|
||||
|
||||
/// Helper method for the sequence of calls:
|
||||
/// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
|
||||
/// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`)
|
||||
/// - `LLVMAddNamedMetadataOperand` (to set that node as metadata of `kind_name` for `module`)
|
||||
pub(crate) fn module_add_named_metadata_node(
|
||||
&self,
|
||||
module: &'ll Module,
|
||||
kind_name: &CStr,
|
||||
md_list: &[&'ll Metadata],
|
||||
) {
|
||||
let md = self.md_node_in_context(md_list);
|
||||
let md_as_val = self.get_metadata_value(md);
|
||||
unsafe { llvm::LLVMAddNamedMetadataOperand(module, kind_name.as_ptr(), md_as_val) };
|
||||
}
|
||||
|
||||
/// Helper method for the sequence of calls:
|
||||
/// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
|
||||
/// - `LLVMRustGlobalAddMetadata` (to set that node as metadata of `kind_id` for `global`)
|
||||
pub(crate) fn global_add_metadata_node(
|
||||
&self,
|
||||
global: &'ll Value,
|
||||
kind_id: MetadataKindId,
|
||||
md_list: &[&'ll Metadata],
|
||||
) {
|
||||
let md = self.md_node_in_context(md_list);
|
||||
unsafe { llvm::LLVMRustGlobalAddMetadata(global, kind_id, md) };
|
||||
}
|
||||
|
||||
/// Helper method for the sequence of calls:
|
||||
/// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
|
||||
/// - `LLVMGlobalSetMetadata` (to set that node as metadata of `kind_id` for `global`)
|
||||
pub(crate) fn global_set_metadata_node(
|
||||
&self,
|
||||
global: &'ll Value,
|
||||
kind_id: MetadataKindId,
|
||||
md_list: &[&'ll Metadata],
|
||||
) {
|
||||
let md = self.md_node_in_context(md_list);
|
||||
unsafe { llvm::LLVMGlobalSetMetadata(global, kind_id, md) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,26 +2,25 @@
|
|||
|
||||
use std::ffi::CString;
|
||||
|
||||
use crate::common::AsCCharPtr;
|
||||
use crate::coverageinfo::ffi;
|
||||
use crate::llvm;
|
||||
|
||||
pub(crate) fn covmap_var_name() -> CString {
|
||||
CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
CString::new(llvm::build_byte_buffer(|s| {
|
||||
llvm::LLVMRustCoverageWriteCovmapVarNameToString(s);
|
||||
}))
|
||||
.expect("covmap variable name should not contain NUL")
|
||||
}
|
||||
|
||||
pub(crate) fn covmap_section_name(llmod: &llvm::Module) -> CString {
|
||||
CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
CString::new(llvm::build_byte_buffer(|s| {
|
||||
llvm::LLVMRustCoverageWriteCovmapSectionNameToString(llmod, s);
|
||||
}))
|
||||
.expect("covmap section name should not contain NUL")
|
||||
}
|
||||
|
||||
pub(crate) fn covfun_section_name(llmod: &llvm::Module) -> CString {
|
||||
CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
CString::new(llvm::build_byte_buffer(|s| {
|
||||
llvm::LLVMRustCoverageWriteCovfunSectionNameToString(llmod, s);
|
||||
}))
|
||||
.expect("covfun section name should not contain NUL")
|
||||
|
|
@ -34,7 +33,7 @@ pub(crate) fn create_pgo_func_name_var<'ll>(
|
|||
unsafe {
|
||||
llvm::LLVMRustCoverageCreatePGOFuncNameVar(
|
||||
llfn,
|
||||
mangled_fn_name.as_c_char_ptr(),
|
||||
mangled_fn_name.as_ptr(),
|
||||
mangled_fn_name.len(),
|
||||
)
|
||||
}
|
||||
|
|
@ -44,7 +43,7 @@ pub(crate) fn write_filenames_to_buffer(filenames: &[impl AsRef<str>]) -> Vec<u8
|
|||
let (pointers, lengths) = filenames
|
||||
.into_iter()
|
||||
.map(AsRef::as_ref)
|
||||
.map(|s: &str| (s.as_c_char_ptr(), s.len()))
|
||||
.map(|s: &str| (s.as_ptr(), s.len()))
|
||||
.unzip::<_, _, Vec<_>, Vec<_>>();
|
||||
|
||||
llvm::build_byte_buffer(|buffer| unsafe {
|
||||
|
|
@ -89,12 +88,12 @@ pub(crate) fn write_function_mappings_to_buffer(
|
|||
/// Hashes some bytes into a 64-bit hash, via LLVM's `IndexedInstrProf::ComputeHash`,
|
||||
/// as required for parts of the LLVM coverage mapping format.
|
||||
pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 {
|
||||
unsafe { llvm::LLVMRustCoverageHashBytes(bytes.as_c_char_ptr(), bytes.len()) }
|
||||
unsafe { llvm::LLVMRustCoverageHashBytes(bytes.as_ptr(), bytes.len()) }
|
||||
}
|
||||
|
||||
/// Returns LLVM's `coverage::CovMapVersion::CurrentVersion` (CoverageMapping.h)
|
||||
/// as a raw numeric value. For historical reasons, the numeric value is 1 less
|
||||
/// than the number in the version's name, so `Version7` is actually `6u32`.
|
||||
pub(crate) fn mapping_version() -> u32 {
|
||||
unsafe { llvm::LLVMRustCoverageMappingVersion() }
|
||||
llvm::LLVMRustCoverageMappingVersion()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1607,21 +1607,11 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
|
|||
let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref);
|
||||
let typeid = cx.create_metadata(trait_ref_typeid.as_bytes());
|
||||
|
||||
unsafe {
|
||||
let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid];
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
vtable,
|
||||
llvm::MD_type as c_uint,
|
||||
llvm::LLVMMDNodeInContext2(cx.llcx, v.as_ptr(), v.len()),
|
||||
);
|
||||
let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64));
|
||||
let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1);
|
||||
llvm::LLVMGlobalSetMetadata(
|
||||
vtable,
|
||||
llvm::MetadataType::MD_vcall_visibility as c_uint,
|
||||
vcall_visibility_metadata,
|
||||
);
|
||||
}
|
||||
let type_ = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid];
|
||||
cx.global_add_metadata_node(vtable, llvm::MD_type, &type_);
|
||||
|
||||
let vcall_visibility = [llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64))];
|
||||
cx.global_set_metadata_node(vtable, llvm::MD_vcall_visibility, &vcall_visibility);
|
||||
}
|
||||
|
||||
/// Creates debug information for the given vtable, which is for the
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use super::debuginfo::{
|
|||
DITemplateTypeParameter, DIType, DebugEmissionKind, DebugNameTableKind,
|
||||
};
|
||||
use crate::llvm;
|
||||
use crate::llvm::MetadataKindId;
|
||||
|
||||
/// In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`,
|
||||
/// which has a different ABI from Rust or C++ `bool`.
|
||||
|
|
@ -513,31 +514,6 @@ pub(crate) enum FileType {
|
|||
ObjectFile,
|
||||
}
|
||||
|
||||
/// LLVMMetadataType
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
#[expect(dead_code, reason = "Some variants are unused, but are kept to match LLVM-C")]
|
||||
pub(crate) enum MetadataType {
|
||||
MD_dbg = 0,
|
||||
MD_tbaa = 1,
|
||||
MD_prof = 2,
|
||||
MD_fpmath = 3,
|
||||
MD_range = 4,
|
||||
MD_tbaa_struct = 5,
|
||||
MD_invariant_load = 6,
|
||||
MD_alias_scope = 7,
|
||||
MD_noalias = 8,
|
||||
MD_nontemporal = 9,
|
||||
MD_mem_parallel_loop_access = 10,
|
||||
MD_nonnull = 11,
|
||||
MD_unpredictable = 15,
|
||||
MD_align = 17,
|
||||
MD_type = 19,
|
||||
MD_vcall_visibility = 28,
|
||||
MD_noundef = 29,
|
||||
MD_kcfi_type = 36,
|
||||
}
|
||||
|
||||
/// Must match the layout of `LLVMInlineAsmDialect`.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
|
|
@ -1035,16 +1011,6 @@ pub(crate) type GetSymbolsCallback =
|
|||
unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void;
|
||||
pub(crate) type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct MetadataKindId(c_uint);
|
||||
|
||||
impl From<MetadataType> for MetadataKindId {
|
||||
fn from(value: MetadataType) -> Self {
|
||||
Self(value as c_uint)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
// Create and destroy contexts.
|
||||
pub(crate) fn LLVMContextDispose(C: &'static mut Context);
|
||||
|
|
@ -1139,7 +1105,11 @@ unsafe extern "C" {
|
|||
pub(crate) fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
|
||||
pub(crate) fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value);
|
||||
pub(crate) safe fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: MetadataKindId, Node: &'a Value);
|
||||
pub(crate) fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
|
||||
pub(crate) fn LLVMGlobalSetMetadata<'a>(
|
||||
Val: &'a Value,
|
||||
KindID: MetadataKindId,
|
||||
Metadata: &'a Metadata,
|
||||
);
|
||||
pub(crate) safe fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
|
||||
|
||||
// Operations on constants of any type
|
||||
|
|
@ -2059,7 +2029,7 @@ unsafe extern "C" {
|
|||
// Operations on all values
|
||||
pub(crate) fn LLVMRustGlobalAddMetadata<'a>(
|
||||
Val: &'a Value,
|
||||
KindID: c_uint,
|
||||
KindID: MetadataKindId,
|
||||
Metadata: &'a Metadata,
|
||||
);
|
||||
pub(crate) fn LLVMRustIsNonGVFunctionPointerTy(Val: &Value) -> bool;
|
||||
|
|
@ -2256,8 +2226,11 @@ unsafe extern "C" {
|
|||
ConstraintsLen: size_t,
|
||||
) -> bool;
|
||||
|
||||
/// A list of pointer-length strings is passed as two pointer-length slices,
|
||||
/// one slice containing pointers and one slice containing their corresponding
|
||||
/// lengths. The implementation will check that both slices have the same length.
|
||||
pub(crate) fn LLVMRustCoverageWriteFilenamesToBuffer(
|
||||
Filenames: *const *const c_char,
|
||||
Filenames: *const *const c_uchar, // See "PTR_LEN_STR".
|
||||
FilenamesLen: size_t,
|
||||
Lengths: *const size_t,
|
||||
LengthsLen: size_t,
|
||||
|
|
@ -2280,18 +2253,25 @@ unsafe extern "C" {
|
|||
|
||||
pub(crate) fn LLVMRustCoverageCreatePGOFuncNameVar(
|
||||
F: &Value,
|
||||
FuncName: *const c_char,
|
||||
FuncName: *const c_uchar, // See "PTR_LEN_STR".
|
||||
FuncNameLen: size_t,
|
||||
) -> &Value;
|
||||
pub(crate) fn LLVMRustCoverageHashBytes(Bytes: *const c_char, NumBytes: size_t) -> u64;
|
||||
pub(crate) fn LLVMRustCoverageHashBytes(
|
||||
Bytes: *const c_uchar, // See "PTR_LEN_STR".
|
||||
NumBytes: size_t,
|
||||
) -> u64;
|
||||
|
||||
pub(crate) fn LLVMRustCoverageWriteCovmapSectionNameToString(M: &Module, OutStr: &RustString);
|
||||
pub(crate) safe fn LLVMRustCoverageWriteCovmapSectionNameToString(
|
||||
M: &Module,
|
||||
OutStr: &RustString,
|
||||
);
|
||||
pub(crate) safe fn LLVMRustCoverageWriteCovfunSectionNameToString(
|
||||
M: &Module,
|
||||
OutStr: &RustString,
|
||||
);
|
||||
pub(crate) safe fn LLVMRustCoverageWriteCovmapVarNameToString(OutStr: &RustString);
|
||||
|
||||
pub(crate) fn LLVMRustCoverageWriteCovfunSectionNameToString(M: &Module, OutStr: &RustString);
|
||||
|
||||
pub(crate) fn LLVMRustCoverageWriteCovmapVarNameToString(OutStr: &RustString);
|
||||
|
||||
pub(crate) fn LLVMRustCoverageMappingVersion() -> u32;
|
||||
pub(crate) safe fn LLVMRustCoverageMappingVersion() -> u32;
|
||||
pub(crate) fn LLVMRustDebugMetadataVersion() -> u32;
|
||||
pub(crate) fn LLVMRustVersionMajor() -> u32;
|
||||
pub(crate) fn LLVMRustVersionMinor() -> u32;
|
||||
|
|
|
|||
71
compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs
Normal file
71
compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
use libc::c_uint;
|
||||
|
||||
pub(crate) use self::fixed_kinds::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct MetadataKindId(c_uint);
|
||||
|
||||
macro_rules! declare_fixed_metadata_kinds {
|
||||
(
|
||||
$(
|
||||
FIXED_MD_KIND($variant:ident, $value:literal)
|
||||
)*
|
||||
) => {
|
||||
// Use a submodule to group all declarations into one `#[expect(..)]`.
|
||||
#[expect(dead_code)]
|
||||
mod fixed_kinds {
|
||||
use super::MetadataKindId;
|
||||
$(
|
||||
#[expect(non_upper_case_globals)]
|
||||
pub(crate) const $variant: MetadataKindId = MetadataKindId($value);
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Must be kept in sync with the corresponding static assertions in `RustWrapper.cpp`.
|
||||
declare_fixed_metadata_kinds! {
|
||||
FIXED_MD_KIND(MD_dbg, 0)
|
||||
FIXED_MD_KIND(MD_tbaa, 1)
|
||||
FIXED_MD_KIND(MD_prof, 2)
|
||||
FIXED_MD_KIND(MD_fpmath, 3)
|
||||
FIXED_MD_KIND(MD_range, 4)
|
||||
FIXED_MD_KIND(MD_tbaa_struct, 5)
|
||||
FIXED_MD_KIND(MD_invariant_load, 6)
|
||||
FIXED_MD_KIND(MD_alias_scope, 7)
|
||||
FIXED_MD_KIND(MD_noalias, 8)
|
||||
FIXED_MD_KIND(MD_nontemporal, 9)
|
||||
FIXED_MD_KIND(MD_mem_parallel_loop_access, 10)
|
||||
FIXED_MD_KIND(MD_nonnull, 11)
|
||||
FIXED_MD_KIND(MD_dereferenceable, 12)
|
||||
FIXED_MD_KIND(MD_dereferenceable_or_null, 13)
|
||||
FIXED_MD_KIND(MD_make_implicit, 14)
|
||||
FIXED_MD_KIND(MD_unpredictable, 15)
|
||||
FIXED_MD_KIND(MD_invariant_group, 16)
|
||||
FIXED_MD_KIND(MD_align, 17)
|
||||
FIXED_MD_KIND(MD_loop, 18)
|
||||
FIXED_MD_KIND(MD_type, 19)
|
||||
FIXED_MD_KIND(MD_section_prefix, 20)
|
||||
FIXED_MD_KIND(MD_absolute_symbol, 21)
|
||||
FIXED_MD_KIND(MD_associated, 22)
|
||||
FIXED_MD_KIND(MD_callees, 23)
|
||||
FIXED_MD_KIND(MD_irr_loop, 24)
|
||||
FIXED_MD_KIND(MD_access_group, 25)
|
||||
FIXED_MD_KIND(MD_callback, 26)
|
||||
FIXED_MD_KIND(MD_preserve_access_index, 27)
|
||||
FIXED_MD_KIND(MD_vcall_visibility, 28)
|
||||
FIXED_MD_KIND(MD_noundef, 29)
|
||||
FIXED_MD_KIND(MD_annotation, 30)
|
||||
FIXED_MD_KIND(MD_nosanitize, 31)
|
||||
FIXED_MD_KIND(MD_func_sanitize, 32)
|
||||
FIXED_MD_KIND(MD_exclude, 33)
|
||||
FIXED_MD_KIND(MD_memprof, 34)
|
||||
FIXED_MD_KIND(MD_callsite, 35)
|
||||
FIXED_MD_KIND(MD_kcfi_type, 36)
|
||||
FIXED_MD_KIND(MD_pcsections, 37)
|
||||
FIXED_MD_KIND(MD_DIAssignID, 38)
|
||||
FIXED_MD_KIND(MD_coro_outside_frame, 39)
|
||||
FIXED_MD_KIND(MD_mmra, 40)
|
||||
FIXED_MD_KIND(MD_noalias_addrspace, 41)
|
||||
}
|
||||
|
|
@ -11,13 +11,14 @@ use rustc_llvm::RustString;
|
|||
|
||||
pub(crate) use self::CallConv::*;
|
||||
pub(crate) use self::CodeGenOptSize::*;
|
||||
pub(crate) use self::MetadataType::*;
|
||||
pub(crate) use self::ffi::*;
|
||||
pub(crate) use self::metadata_kind::*;
|
||||
use crate::common::AsCCharPtr;
|
||||
|
||||
pub(crate) mod diagnostic;
|
||||
pub(crate) mod enzyme_ffi;
|
||||
mod ffi;
|
||||
mod metadata_kind;
|
||||
|
||||
pub(crate) use self::enzyme_ffi::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -302,26 +302,14 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) {
|
||||
let typeid_metadata = self.create_metadata(typeid);
|
||||
unsafe {
|
||||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
function,
|
||||
llvm::MD_type as c_uint,
|
||||
llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()),
|
||||
)
|
||||
}
|
||||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
self.global_add_metadata_node(function, llvm::MD_type, &v);
|
||||
}
|
||||
|
||||
fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) {
|
||||
let typeid_metadata = self.create_metadata(typeid);
|
||||
unsafe {
|
||||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
llvm::LLVMGlobalSetMetadata(
|
||||
function,
|
||||
llvm::MD_type as c_uint,
|
||||
llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()),
|
||||
)
|
||||
}
|
||||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
self.global_set_metadata_node(function, llvm::MD_type, &v);
|
||||
}
|
||||
|
||||
fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> {
|
||||
|
|
@ -329,32 +317,12 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
|
||||
fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) {
|
||||
let kcfi_type_metadata = self.const_u32(kcfi_typeid);
|
||||
unsafe {
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
function,
|
||||
llvm::MD_kcfi_type as c_uint,
|
||||
llvm::LLVMMDNodeInContext2(
|
||||
self.llcx,
|
||||
&llvm::LLVMValueAsMetadata(kcfi_type_metadata),
|
||||
1,
|
||||
),
|
||||
)
|
||||
}
|
||||
let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))];
|
||||
self.global_add_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata);
|
||||
}
|
||||
|
||||
fn set_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) {
|
||||
let kcfi_type_metadata = self.const_u32(kcfi_typeid);
|
||||
unsafe {
|
||||
llvm::LLVMGlobalSetMetadata(
|
||||
function,
|
||||
llvm::MD_kcfi_type as c_uint,
|
||||
llvm::LLVMMDNodeInContext2(
|
||||
self.llcx,
|
||||
&llvm::LLVMValueAsMetadata(kcfi_type_metadata),
|
||||
1,
|
||||
),
|
||||
)
|
||||
}
|
||||
let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))];
|
||||
self.global_set_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ use rustc_middle::middle::exported_symbols::{
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
|
||||
use rustc_span::sym;
|
||||
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
|
|
@ -1324,37 +1323,7 @@ struct WasmLd<'a> {
|
|||
|
||||
impl<'a> WasmLd<'a> {
|
||||
fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> {
|
||||
// If the atomics feature is enabled for wasm then we need a whole bunch
|
||||
// of flags:
|
||||
//
|
||||
// * `--shared-memory` - the link won't even succeed without this, flags
|
||||
// the one linear memory as `shared`
|
||||
//
|
||||
// * `--max-memory=1G` - when specifying a shared memory this must also
|
||||
// be specified. We conservatively choose 1GB but users should be able
|
||||
// to override this with `-C link-arg`.
|
||||
//
|
||||
// * `--import-memory` - it doesn't make much sense for memory to be
|
||||
// exported in a threaded module because typically you're
|
||||
// sharing memory and instantiating the module multiple times. As a
|
||||
// result if it were exported then we'd just have no sharing.
|
||||
//
|
||||
// On wasm32-unknown-unknown, we also export symbols for glue code to use:
|
||||
// * `--export=*tls*` - when `#[thread_local]` symbols are used these
|
||||
// symbols are how the TLS segments are initialized and configured.
|
||||
let mut wasm_ld = WasmLd { cmd, sess };
|
||||
if sess.target_features.contains(&sym::atomics) {
|
||||
wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
|
||||
if sess.target.os == "unknown" || sess.target.os == "none" {
|
||||
wasm_ld.link_args(&[
|
||||
"--export=__wasm_init_tls",
|
||||
"--export=__tls_size",
|
||||
"--export=__tls_align",
|
||||
"--export=__tls_base",
|
||||
]);
|
||||
}
|
||||
}
|
||||
wasm_ld
|
||||
WasmLd { cmd, sess }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,10 +150,6 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx>
|
|||
{
|
||||
layout.for_variant(self.fx.cx, vidx)
|
||||
}
|
||||
mir::PlaceElem::Subtype(subtype_ty) => {
|
||||
let subtype_ty = self.fx.monomorphize(subtype_ty);
|
||||
self.fx.cx.layout_of(subtype_ty)
|
||||
}
|
||||
_ => {
|
||||
self.locals[place_ref.local] = LocalKind::Memory;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -956,11 +956,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let layout = o.layout.for_variant(bx.cx(), vidx);
|
||||
o = OperandRef { val: o.val, layout }
|
||||
}
|
||||
mir::PlaceElem::Subtype(subtype_ty) => {
|
||||
let subtype_ty = self.monomorphize(subtype_ty);
|
||||
let layout = self.cx.layout_of(subtype_ty);
|
||||
o = OperandRef { val: o.val, layout }
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -347,7 +347,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
mir::ProjectionElem::OpaqueCast(ty) => {
|
||||
bug!("encountered OpaqueCast({ty}) in codegen")
|
||||
}
|
||||
mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
|
||||
mir::ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||
cg_base.project_type(bx, self.monomorphize(ty))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
|
||||
mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => {
|
||||
mir::Rvalue::Cast(
|
||||
mir::CastKind::Transmute | mir::CastKind::Subtype,
|
||||
ref operand,
|
||||
_ty,
|
||||
) => {
|
||||
let src = self.codegen_operand(bx, operand);
|
||||
self.codegen_transmute(bx, src, dest);
|
||||
}
|
||||
|
|
@ -486,7 +490,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bug!("Unsupported cast of {operand:?} to {cast:?}");
|
||||
})
|
||||
}
|
||||
mir::CastKind::Transmute => {
|
||||
mir::CastKind::Transmute | mir::CastKind::Subtype => {
|
||||
self.codegen_transmute_operand(bx, operand, cast)
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -293,7 +293,6 @@ where
|
|||
ProjectionElem::Index(index) if in_local(index) => return true,
|
||||
|
||||
ProjectionElem::Deref
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Field(_, _)
|
||||
| ProjectionElem::OpaqueCast(_)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
CastKind::Transmute => {
|
||||
CastKind::Transmute | CastKind::Subtype => {
|
||||
assert!(src.layout.is_sized());
|
||||
assert!(dest.layout.is_sized());
|
||||
assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely...
|
||||
|
|
|
|||
|
|
@ -395,8 +395,6 @@ where
|
|||
span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
|
||||
}
|
||||
UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?,
|
||||
// We don't want anything happening here, this is here as a dummy.
|
||||
Subtype(_) => base.transmute(base.layout(), self)?,
|
||||
Field(field, _) => self.project_field(base, field)?,
|
||||
Downcast(_, variant) => self.project_downcast(base, variant)?,
|
||||
Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
An attempt to use index on a type which doesn't implement the `std::ops::Index`
|
||||
trait was performed.
|
||||
Attempted to index a value whose type doesn't implement the
|
||||
`std::ops::Index` trait.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
|
@ -7,8 +7,8 @@ Erroneous code example:
|
|||
0u8[2]; // error: cannot index into a value of type `u8`
|
||||
```
|
||||
|
||||
To be able to index into a type it needs to implement the `std::ops::Index`
|
||||
trait. Example:
|
||||
Only values with types that implement the `std::ops::Index` trait
|
||||
can be indexed with square brackets. Example:
|
||||
|
||||
```
|
||||
let v: Vec<u8> = vec![0, 1, 2, 3];
|
||||
|
|
@ -16,3 +16,10 @@ let v: Vec<u8> = vec![0, 1, 2, 3];
|
|||
// The `Vec` type implements the `Index` trait so you can do:
|
||||
println!("{}", v[2]);
|
||||
```
|
||||
|
||||
Tuples and structs are indexed with dot (`.`), not with brackets (`[]`),
|
||||
and tuple element names are their positions:
|
||||
```ignore(pseudo code)
|
||||
// this (pseudo code) expression is true for any tuple:
|
||||
tuple == (tuple.0, tuple.1, ...)
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
An associated type value was specified more than once.
|
||||
An associated item was specified more than once in a trait object.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
|
@ -7,21 +7,15 @@ trait FooTrait {}
|
|||
trait BarTrait {}
|
||||
|
||||
// error: associated type `Item` in trait `Iterator` is specified twice
|
||||
struct Foo<T: Iterator<Item: FooTrait, Item: BarTrait>> { f: T }
|
||||
type Foo = dyn Iterator<Item = u32, Item = u32>;
|
||||
```
|
||||
|
||||
`Item` in trait `Iterator` cannot be specified multiple times for struct `Foo`.
|
||||
To fix this, create a new trait that is a combination of the desired traits and
|
||||
specify the associated type with the new trait.
|
||||
To fix this, remove the duplicate specifier:
|
||||
|
||||
Corrected example:
|
||||
|
||||
```
|
||||
trait FooTrait {}
|
||||
trait BarTrait {}
|
||||
trait FooBarTrait: FooTrait + BarTrait {}
|
||||
|
||||
struct Foo<T: Iterator<Item: FooBarTrait>> { f: T } // ok!
|
||||
type Foo = dyn Iterator<Item = u32>; // ok!
|
||||
```
|
||||
|
||||
For more information about associated types, see [the book][bk-at]. For more
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_ast::attr::{AttributeExt, MarkedAttrs};
|
|||
use rustc_ast::token::MetaVarKind;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::visit::{AssocCtxt, Visitor};
|
||||
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
|
||||
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult};
|
||||
|
|
@ -345,6 +345,21 @@ pub trait AttrProcMacro {
|
|||
annotation: TokenStream,
|
||||
annotated: TokenStream,
|
||||
) -> Result<TokenStream, ErrorGuaranteed>;
|
||||
|
||||
// Default implementation for safe attributes; override if the attribute can be unsafe.
|
||||
fn expand_with_safety<'cx>(
|
||||
&self,
|
||||
ecx: &'cx mut ExtCtxt<'_>,
|
||||
safety: Safety,
|
||||
span: Span,
|
||||
annotation: TokenStream,
|
||||
annotated: TokenStream,
|
||||
) -> Result<TokenStream, ErrorGuaranteed> {
|
||||
if let Safety::Unsafe(span) = safety {
|
||||
ecx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute");
|
||||
}
|
||||
self.expand(ecx, span, annotation, annotated)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> AttrProcMacro for F
|
||||
|
|
|
|||
|
|
@ -812,11 +812,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
_ => item.to_tokens(),
|
||||
};
|
||||
let attr_item = attr.get_normal_item();
|
||||
let safety = attr_item.unsafety;
|
||||
if let AttrArgs::Eq { .. } = attr_item.args {
|
||||
self.cx.dcx().emit_err(UnsupportedKeyValue { span });
|
||||
}
|
||||
let inner_tokens = attr_item.args.inner_tokens();
|
||||
match expander.expand(self.cx, span, inner_tokens, tokens) {
|
||||
match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) {
|
||||
Ok(tok_result) => {
|
||||
let fragment = self.parse_ast_fragment(
|
||||
tok_result,
|
||||
|
|
@ -840,6 +841,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
|
||||
}
|
||||
} else if let SyntaxExtensionKind::LegacyAttr(expander) = ext {
|
||||
// `LegacyAttr` is only used for builtin attribute macros, which have their
|
||||
// safety checked by `check_builtin_meta_item`, so we don't need to check
|
||||
// `unsafety` here.
|
||||
match validate_attr::parse_meta(&self.cx.sess.psess, &attr) {
|
||||
Ok(meta) => {
|
||||
let item_clone = macro_stats.then(|| item.clone());
|
||||
|
|
@ -882,6 +886,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
} else if let SyntaxExtensionKind::NonMacroAttr = ext {
|
||||
if let ast::Safety::Unsafe(span) = attr.get_normal_item().unsafety {
|
||||
self.cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute");
|
||||
}
|
||||
// `-Zmacro-stats` ignores these because they don't do any real expansion.
|
||||
self.cx.expanded_inert_attrs.mark(&attr);
|
||||
item.visit_attrs(|attrs| attrs.insert(pos, attr));
|
||||
|
|
|
|||
|
|
@ -210,8 +210,7 @@ pub(super) fn check_meta_variables(
|
|||
guar.map_or(Ok(()), Err)
|
||||
}
|
||||
|
||||
/// Checks `lhs` as part of the LHS of a macro definition, extends `binders` with new binders, and
|
||||
/// sets `valid` to false in case of errors.
|
||||
/// Checks `lhs` as part of the LHS of a macro definition.
|
||||
///
|
||||
/// Arguments:
|
||||
/// - `psess` is used to emit diagnostics and lints
|
||||
|
|
@ -306,8 +305,7 @@ fn get_binder_info<'a>(
|
|||
binders.get(&name).or_else(|| macros.find_map(|state| state.binders.get(&name)))
|
||||
}
|
||||
|
||||
/// Checks `rhs` as part of the RHS of a macro definition and sets `valid` to false in case of
|
||||
/// errors.
|
||||
/// Checks `rhs` as part of the RHS of a macro definition.
|
||||
///
|
||||
/// Arguments:
|
||||
/// - `psess` is used to emit diagnostics and lints
|
||||
|
|
@ -372,7 +370,7 @@ enum NestedMacroState {
|
|||
}
|
||||
|
||||
/// Checks `tts` as part of the RHS of a macro definition, tries to recognize nested macro
|
||||
/// definitions, and sets `valid` to false in case of errors.
|
||||
/// definitions.
|
||||
///
|
||||
/// Arguments:
|
||||
/// - `psess` is used to emit diagnostics and lints
|
||||
|
|
@ -491,8 +489,7 @@ fn check_nested_occurrences(
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks the body of nested macro, returns where the check stopped, and sets `valid` to false in
|
||||
/// case of errors.
|
||||
/// Checks the body of nested macro, returns where the check stopped.
|
||||
///
|
||||
/// The token trees are checked as long as they look like a list of (LHS) => {RHS} token trees. This
|
||||
/// check is a best-effort to detect a macro definition. It returns the position in `tts` where we
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_ast::token::NtPatKind::*;
|
|||
use rustc_ast::token::TokenKind::*;
|
||||
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{self, DelimSpan, TokenStream};
|
||||
use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
|
||||
use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId, Safety};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
|
||||
|
|
@ -131,6 +131,7 @@ pub(super) enum MacroRule {
|
|||
Func { lhs: Vec<MatcherLoc>, lhs_span: Span, rhs: mbe::TokenTree },
|
||||
/// An attr rule, for use with `#[m]`
|
||||
Attr {
|
||||
unsafe_rule: bool,
|
||||
args: Vec<MatcherLoc>,
|
||||
args_span: Span,
|
||||
body: Vec<MatcherLoc>,
|
||||
|
|
@ -247,8 +248,19 @@ impl TTMacroExpander for MacroRulesMacroExpander {
|
|||
|
||||
impl AttrProcMacro for MacroRulesMacroExpander {
|
||||
fn expand(
|
||||
&self,
|
||||
_cx: &mut ExtCtxt<'_>,
|
||||
_sp: Span,
|
||||
_args: TokenStream,
|
||||
_body: TokenStream,
|
||||
) -> Result<TokenStream, ErrorGuaranteed> {
|
||||
unreachable!("`expand` called on `MacroRulesMacroExpander`, expected `expand_with_safety`")
|
||||
}
|
||||
|
||||
fn expand_with_safety(
|
||||
&self,
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
safety: Safety,
|
||||
sp: Span,
|
||||
args: TokenStream,
|
||||
body: TokenStream,
|
||||
|
|
@ -260,6 +272,7 @@ impl AttrProcMacro for MacroRulesMacroExpander {
|
|||
self.node_id,
|
||||
self.name,
|
||||
self.transparency,
|
||||
safety,
|
||||
args,
|
||||
body,
|
||||
&self.rules,
|
||||
|
|
@ -408,6 +421,7 @@ fn expand_macro_attr(
|
|||
node_id: NodeId,
|
||||
name: Ident,
|
||||
transparency: Transparency,
|
||||
safety: Safety,
|
||||
args: TokenStream,
|
||||
body: TokenStream,
|
||||
rules: &[MacroRule],
|
||||
|
|
@ -429,13 +443,26 @@ fn expand_macro_attr(
|
|||
// Track nothing for the best performance.
|
||||
match try_match_macro_attr(psess, name, &args, &body, rules, &mut NoopTracker) {
|
||||
Ok((i, rule, named_matches)) => {
|
||||
let MacroRule::Attr { rhs, .. } = rule else {
|
||||
let MacroRule::Attr { rhs, unsafe_rule, .. } = rule else {
|
||||
panic!("try_macro_match_attr returned non-attr rule");
|
||||
};
|
||||
let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else {
|
||||
cx.dcx().span_bug(sp, "malformed macro rhs");
|
||||
};
|
||||
|
||||
match (safety, unsafe_rule) {
|
||||
(Safety::Default, false) | (Safety::Unsafe(_), true) => {}
|
||||
(Safety::Default, true) => {
|
||||
cx.dcx().span_err(sp, "unsafe attribute invocation requires `unsafe`");
|
||||
}
|
||||
(Safety::Unsafe(span), false) => {
|
||||
cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute invocation");
|
||||
}
|
||||
(Safety::Safe(span), _) => {
|
||||
cx.dcx().span_bug(span, "unexpected `safe` keyword");
|
||||
}
|
||||
}
|
||||
|
||||
let id = cx.current_expansion.id;
|
||||
let tts = transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id)
|
||||
.map_err(|e| e.emit())?;
|
||||
|
|
@ -681,6 +708,11 @@ pub fn compile_declarative_macro(
|
|||
let mut rules = Vec::new();
|
||||
|
||||
while p.token != token::Eof {
|
||||
let unsafe_rule = p.eat_keyword_noexpect(kw::Unsafe);
|
||||
let unsafe_keyword_span = p.prev_token.span;
|
||||
if unsafe_rule && let Some(guar) = check_no_eof(sess, &p, "expected `attr`") {
|
||||
return dummy_syn_ext(guar);
|
||||
}
|
||||
let (args, is_derive) = if p.eat_keyword_noexpect(sym::attr) {
|
||||
kinds |= MacroKinds::ATTR;
|
||||
if !features.macro_attr() {
|
||||
|
|
@ -705,6 +737,10 @@ pub fn compile_declarative_macro(
|
|||
feature_err(sess, sym::macro_derive, span, "`macro_rules!` derives are unstable")
|
||||
.emit();
|
||||
}
|
||||
if unsafe_rule {
|
||||
sess.dcx()
|
||||
.span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules");
|
||||
}
|
||||
if let Some(guar) = check_no_eof(sess, &p, "expected `()` after `derive`") {
|
||||
return dummy_syn_ext(guar);
|
||||
}
|
||||
|
|
@ -730,6 +766,10 @@ pub fn compile_declarative_macro(
|
|||
(None, true)
|
||||
} else {
|
||||
kinds |= MacroKinds::BANG;
|
||||
if unsafe_rule {
|
||||
sess.dcx()
|
||||
.span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules");
|
||||
}
|
||||
(None, false)
|
||||
};
|
||||
let lhs_tt = p.parse_token_tree();
|
||||
|
|
@ -741,10 +781,10 @@ pub fn compile_declarative_macro(
|
|||
if let Some(guar) = check_no_eof(sess, &p, "expected right-hand side of macro rule") {
|
||||
return dummy_syn_ext(guar);
|
||||
}
|
||||
let rhs_tt = p.parse_token_tree();
|
||||
let rhs_tt = parse_one_tt(rhs_tt, RulePart::Body, sess, node_id, features, edition);
|
||||
check_emission(check_rhs(sess, &rhs_tt));
|
||||
check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs_tt));
|
||||
let rhs = p.parse_token_tree();
|
||||
let rhs = parse_one_tt(rhs, RulePart::Body, sess, node_id, features, edition);
|
||||
check_emission(check_rhs(sess, &rhs));
|
||||
check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs));
|
||||
let lhs_span = lhs_tt.span();
|
||||
// Convert the lhs into `MatcherLoc` form, which is better for doing the
|
||||
// actual matching.
|
||||
|
|
@ -760,11 +800,11 @@ pub fn compile_declarative_macro(
|
|||
};
|
||||
let args = mbe::macro_parser::compute_locs(&delimited.tts);
|
||||
let body_span = lhs_span;
|
||||
rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs: rhs_tt });
|
||||
rules.push(MacroRule::Attr { unsafe_rule, args, args_span, body: lhs, body_span, rhs });
|
||||
} else if is_derive {
|
||||
rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs: rhs_tt });
|
||||
rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs });
|
||||
} else {
|
||||
rules.push(MacroRule::Func { lhs, lhs_span, rhs: rhs_tt });
|
||||
rules.push(MacroRule::Func { lhs, lhs_span, rhs });
|
||||
}
|
||||
if p.token == token::Eof {
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
|
||||
// HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
|
||||
// `async-std` (and `pub async fn` in general).
|
||||
// Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
|
||||
// Since rustdoc doesn't care about the hidden type behind `impl Trait`, just don't look at it!
|
||||
// See https://github.com/rust-lang/rust/issues/75100
|
||||
if tcx.sess.opts.actually_rustdoc {
|
||||
return;
|
||||
|
|
@ -252,7 +252,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Check that the concrete type behind `impl Trait` actually implements `Trait`.
|
||||
/// Check that the hidden type behind `impl Trait` actually implements `Trait`.
|
||||
///
|
||||
/// This is mostly checked at the places that specify the opaque type, but we
|
||||
/// check those cases in the `param_env` of that function, which may have
|
||||
|
|
|
|||
|
|
@ -195,11 +195,10 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Alias(ty::Free, _)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(_) => {
|
||||
| ty::CoroutineWitness(..) => {
|
||||
Err(self.tcx.dcx().delayed_bug("cannot define inherent `impl` for closure types"))
|
||||
}
|
||||
ty::Alias(ty::Free, _) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => {
|
||||
bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty);
|
||||
}
|
||||
// We could bail out here, but that will silence other useful errors.
|
||||
|
|
|
|||
|
|
@ -230,10 +230,12 @@ pub(crate) fn orphan_check_impl(
|
|||
ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Infer(..) => {
|
||||
| ty::CoroutineWitness(..) => {
|
||||
return Err(tcx
|
||||
.dcx()
|
||||
.delayed_bug("cannot define inherent `impl` for closure types"));
|
||||
}
|
||||
ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => {
|
||||
let sp = tcx.def_span(impl_def_id);
|
||||
span_bug!(sp, "weird self type for autotrait impl")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1140,7 +1140,7 @@ fn recover_infer_ret_ty<'tcx>(
|
|||
// recursive function definition to leak out into the fn sig.
|
||||
let mut recovered_ret_ty = None;
|
||||
if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
|
||||
diag.span_suggestion(
|
||||
diag.span_suggestion_verbose(
|
||||
infer_ret_ty.span,
|
||||
"replace with the correct return type",
|
||||
suggestable_ret_ty,
|
||||
|
|
@ -1152,7 +1152,7 @@ fn recover_infer_ret_ty<'tcx>(
|
|||
tcx.param_env(def_id),
|
||||
ret_ty,
|
||||
) {
|
||||
diag.span_suggestion(
|
||||
diag.span_suggestion_verbose(
|
||||
infer_ret_ty.span,
|
||||
"replace with an appropriate return type",
|
||||
sugg,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use tracing::{debug, instrument};
|
|||
|
||||
use super::ItemCtxt;
|
||||
use super::predicates_of::assert_only_contains_predicates_from;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter};
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter};
|
||||
|
||||
/// For associated types we include both bounds written on the type
|
||||
/// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
|
||||
|
|
@ -37,7 +37,14 @@ fn associated_type_bounds<'tcx>(
|
|||
|
||||
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
|
||||
let mut bounds = Vec::new();
|
||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||
icx.lowerer().lower_bounds(
|
||||
item_ty,
|
||||
hir_bounds,
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
|
||||
match filter {
|
||||
PredicateFilter::All
|
||||
|
|
@ -174,21 +181,25 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
|
|||
for (param, var) in std::iter::zip(&generics.own_params, gat_vars) {
|
||||
let existing = match var.kind() {
|
||||
ty::GenericArgKind::Lifetime(re) => {
|
||||
if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() {
|
||||
if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
|
||||
re.kind()
|
||||
{
|
||||
mapping.insert(bv.var, tcx.mk_param_from_def(param))
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() {
|
||||
if let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() {
|
||||
mapping.insert(bv.var, tcx.mk_param_from_def(param))
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
ty::GenericArgKind::Const(ct) => {
|
||||
if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() {
|
||||
if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
|
||||
ct.kind()
|
||||
{
|
||||
mapping.insert(bv.var, tcx.mk_param_from_def(param))
|
||||
} else {
|
||||
return None;
|
||||
|
|
@ -253,7 +264,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> {
|
|||
return ty;
|
||||
}
|
||||
|
||||
if let ty::Bound(binder, old_bound) = *ty.kind()
|
||||
if let ty::Bound(ty::BoundVarIndexKind::Bound(binder), old_bound) = *ty.kind()
|
||||
&& self.binder == binder
|
||||
{
|
||||
let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) {
|
||||
|
|
@ -279,7 +290,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> {
|
|||
}
|
||||
|
||||
fn fold_region(&mut self, re: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
if let ty::ReBound(binder, old_bound) = re.kind()
|
||||
if let ty::ReBound(ty::BoundVarIndexKind::Bound(binder), old_bound) = re.kind()
|
||||
&& self.binder == binder
|
||||
{
|
||||
let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) {
|
||||
|
|
@ -307,7 +318,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> {
|
|||
return ct;
|
||||
}
|
||||
|
||||
if let ty::ConstKind::Bound(binder, old_bound) = ct.kind()
|
||||
if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(binder), old_bound) = ct.kind()
|
||||
&& self.binder == binder
|
||||
{
|
||||
let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) {
|
||||
|
|
@ -347,7 +358,14 @@ fn opaque_type_bounds<'tcx>(
|
|||
ty::print::with_reduced_queries!({
|
||||
let icx = ItemCtxt::new(tcx, opaque_def_id);
|
||||
let mut bounds = Vec::new();
|
||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||
icx.lowerer().lower_bounds(
|
||||
item_ty,
|
||||
hir_bounds,
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
// Implicit bounds are added to opaque types unless a `?Trait` bound is found
|
||||
match filter {
|
||||
PredicateFilter::All
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ use super::item_bounds::explicit_item_bounds_with_filter;
|
|||
use crate::collect::ItemCtxt;
|
||||
use crate::constrained_generic_params as cgp;
|
||||
use crate::delegation::inherit_predicates_for_delegation_item;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason};
|
||||
use crate::hir_ty_lowering::{
|
||||
HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason,
|
||||
};
|
||||
|
||||
/// Returns a list of all type predicates (explicit and implicit) for the definition with
|
||||
/// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus
|
||||
|
|
@ -187,6 +189,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::All,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
icx.lowerer().add_sizedness_bounds(
|
||||
&mut bounds,
|
||||
|
|
@ -289,6 +292,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
&mut bounds,
|
||||
bound_vars,
|
||||
PredicateFilter::All,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
predicates.extend(bounds);
|
||||
}
|
||||
|
|
@ -659,7 +663,14 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
|
|||
|
||||
let self_param_ty = tcx.types.self_param;
|
||||
let mut bounds = Vec::new();
|
||||
icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter);
|
||||
icx.lowerer().lower_bounds(
|
||||
self_param_ty,
|
||||
superbounds,
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
match filter {
|
||||
PredicateFilter::All
|
||||
| PredicateFilter::SelfOnly
|
||||
|
|
@ -984,6 +995,7 @@ impl<'tcx> ItemCtxt<'tcx> {
|
|||
&mut bounds,
|
||||
bound_vars,
|
||||
filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1063,6 +1075,7 @@ pub(super) fn const_conditions<'tcx>(
|
|||
&mut bounds,
|
||||
bound_vars,
|
||||
PredicateFilter::ConstIfConst,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -1083,6 +1096,7 @@ pub(super) fn const_conditions<'tcx>(
|
|||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::ConstIfConst,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ impl<'tcx> TaitConstraintLocator<'tcx> {
|
|||
let tables = tcx.typeck(item_def_id);
|
||||
if let Some(guar) = tables.tainted_by_errors {
|
||||
self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
|
||||
} else if let Some(&hidden_type) = tables.concrete_opaque_types.get(&self.def_id) {
|
||||
} else if let Some(&hidden_type) = tables.hidden_types.get(&self.def_id) {
|
||||
self.insert_found(hidden_type);
|
||||
} else {
|
||||
self.non_defining_use_in_defining_scope(item_def_id);
|
||||
|
|
@ -185,8 +185,8 @@ impl<'tcx> TaitConstraintLocator<'tcx> {
|
|||
}
|
||||
DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(item_def_id) {
|
||||
Err(guar) => self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar)),
|
||||
Ok(concrete_opaque_types) => {
|
||||
if let Some(&hidden_type) = concrete_opaque_types.0.get(&self.def_id) {
|
||||
Ok(hidden_types) => {
|
||||
if let Some(&hidden_type) = hidden_types.0.get(&self.def_id) {
|
||||
debug!(?hidden_type, "found constraint");
|
||||
self.insert_found(hidden_type);
|
||||
} else if let Err(guar) = tcx
|
||||
|
|
@ -247,7 +247,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
|
|||
let tables = tcx.typeck(owner_def_id);
|
||||
if let Some(guar) = tables.tainted_by_errors {
|
||||
Ty::new_error(tcx, guar)
|
||||
} else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) {
|
||||
} else if let Some(hidden_ty) = tables.hidden_types.get(&def_id) {
|
||||
hidden_ty.ty
|
||||
} else {
|
||||
assert!(!tcx.next_trait_solver_globally());
|
||||
|
|
@ -261,8 +261,8 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
|
|||
}
|
||||
}
|
||||
DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(owner_def_id) {
|
||||
Ok(concrete_opaque_types) => {
|
||||
if let Some(hidden_ty) = concrete_opaque_types.0.get(&def_id) {
|
||||
Ok(hidden_types) => {
|
||||
if let Some(hidden_ty) = hidden_types.0.get(&def_id) {
|
||||
hidden_ty.ty
|
||||
} else {
|
||||
let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity();
|
||||
|
|
|
|||
|
|
@ -167,15 +167,20 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
|
|||
// which is `O(nt)` where `t` is the depth of type-parameter constraints,
|
||||
// remembering that `t` should be less than 7 in practice.
|
||||
//
|
||||
// FIXME(hkBst): the big-O bound above would be accurate for the number
|
||||
// of calls to `parameters_for`, which itself is some O(complexity of type).
|
||||
// That would make this potentially cubic instead of merely quadratic...
|
||||
// ...unless we cache those `parameters_for` calls.
|
||||
//
|
||||
// Basically, I iterate over all projections and swap every
|
||||
// "ready" projection to the start of the list, such that
|
||||
// all of the projections before `i` are topologically sorted
|
||||
// and constrain all the parameters in `input_parameters`.
|
||||
//
|
||||
// In the example, `input_parameters` starts by containing `U` - which
|
||||
// is constrained by the trait-ref - and so on the first pass we
|
||||
// In the first example, `input_parameters` starts by containing `U`,
|
||||
// which is constrained by the self type `U`. Then, on the first pass we
|
||||
// observe that `<U as Iterator>::Item = T` is a "ready" projection that
|
||||
// constrains `T` and swap it to front. As it is the sole projection,
|
||||
// constrains `T` and swap it to the front. As it is the sole projection,
|
||||
// no more swaps can take place afterwards, with the result being
|
||||
// * <U as Iterator>::Item = T
|
||||
// * T: Debug
|
||||
|
|
@ -193,33 +198,25 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
|
|||
for j in i..predicates.len() {
|
||||
// Note that we don't have to care about binders here,
|
||||
// as the impl trait ref never contains any late-bound regions.
|
||||
if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() {
|
||||
// Special case: watch out for some kind of sneaky attempt
|
||||
// to project out an associated type defined by this very
|
||||
// trait.
|
||||
let unbound_trait_ref = projection.projection_term.trait_ref(tcx);
|
||||
if Some(unbound_trait_ref) == impl_trait_ref {
|
||||
continue;
|
||||
}
|
||||
if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() &&
|
||||
|
||||
// A projection depends on its input types and determines its output
|
||||
// type. For example, if we have
|
||||
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
|
||||
// Then the projection only applies if `T` is known, but it still
|
||||
// does not determine `U`.
|
||||
let inputs = parameters_for(tcx, projection.projection_term, true);
|
||||
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
|
||||
if !relies_only_on_inputs {
|
||||
continue;
|
||||
}
|
||||
// Special case: watch out for some kind of sneaky attempt to
|
||||
// project out an associated type defined by this very trait.
|
||||
!impl_trait_ref.is_some_and(|t| t == projection.projection_term.trait_ref(tcx)) &&
|
||||
|
||||
// A projection depends on its input types and determines its output
|
||||
// type. For example, if we have
|
||||
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
|
||||
// then the projection only applies if `T` is known, but it still
|
||||
// does not determine `U`.
|
||||
parameters_for(tcx, projection.projection_term, true).iter().all(|p| input_parameters.contains(p))
|
||||
{
|
||||
input_parameters.extend(parameters_for(tcx, projection.term, false));
|
||||
} else {
|
||||
continue;
|
||||
|
||||
predicates.swap(i, j);
|
||||
i += 1;
|
||||
changed = true;
|
||||
}
|
||||
// fancy control flow to bypass borrow checker
|
||||
predicates.swap(i, j);
|
||||
i += 1;
|
||||
changed = true;
|
||||
}
|
||||
debug!(
|
||||
"setup_constraining_predicates: predicates={:?} \
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ use tracing::{debug, instrument};
|
|||
use super::errors::GenericsArgsErrExtend;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{
|
||||
AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason,
|
||||
AssocItemQSelf, FeedConstTy, HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter,
|
||||
RegionInferReason,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
@ -338,6 +339,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
|
||||
predicate_filter: PredicateFilter,
|
||||
overlapping_assoc_constraints: OverlappingAsssocItemConstraints,
|
||||
) where
|
||||
'tcx: 'hir,
|
||||
{
|
||||
|
|
@ -362,6 +364,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
param_ty,
|
||||
bounds,
|
||||
predicate_filter,
|
||||
overlapping_assoc_constraints,
|
||||
);
|
||||
}
|
||||
hir::GenericBound::Outlives(lifetime) => {
|
||||
|
|
@ -402,7 +405,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
constraint: &hir::AssocItemConstraint<'tcx>,
|
||||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
duplicates: &mut FxIndexMap<DefId, Span>,
|
||||
duplicates: Option<&mut FxIndexMap<DefId, Span>>,
|
||||
path_span: Span,
|
||||
predicate_filter: PredicateFilter,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
|
|
@ -458,17 +461,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
)
|
||||
.expect("failed to find associated item");
|
||||
|
||||
duplicates
|
||||
.entry(assoc_item.def_id)
|
||||
.and_modify(|prev_span| {
|
||||
self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
|
||||
span: constraint.span,
|
||||
prev_span: *prev_span,
|
||||
item_name: constraint.ident,
|
||||
def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
|
||||
});
|
||||
})
|
||||
.or_insert(constraint.span);
|
||||
if let Some(duplicates) = duplicates {
|
||||
duplicates
|
||||
.entry(assoc_item.def_id)
|
||||
.and_modify(|prev_span| {
|
||||
self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
|
||||
span: constraint.span,
|
||||
prev_span: *prev_span,
|
||||
item_name: constraint.ident,
|
||||
def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
|
||||
});
|
||||
})
|
||||
.or_insert(constraint.span);
|
||||
}
|
||||
|
||||
let projection_term = if let ty::AssocTag::Fn = assoc_tag {
|
||||
let bound_vars = tcx.late_bound_vars(constraint.hir_id);
|
||||
|
|
@ -600,6 +605,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
bounds,
|
||||
projection_ty.bound_vars(),
|
||||
predicate_filter,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
}
|
||||
PredicateFilter::SelfOnly
|
||||
|
|
@ -915,7 +921,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't
|
|||
ty::Param(param) => {
|
||||
self.params.insert(param.index);
|
||||
}
|
||||
ty::Bound(db, bt) if *db >= self.depth => {
|
||||
ty::Bound(ty::BoundVarIndexKind::Bound(db), bt) if *db >= self.depth => {
|
||||
self.vars.insert(match bt.kind {
|
||||
ty::BoundTyKind::Param(def_id) => def_id,
|
||||
ty::BoundTyKind::Anon => {
|
||||
|
|
@ -938,7 +944,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't
|
|||
ty::ReEarlyParam(param) => {
|
||||
self.params.insert(param.index);
|
||||
}
|
||||
ty::ReBound(db, br) if db >= self.depth => {
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(db), br) if db >= self.depth => {
|
||||
self.vars.insert(match br.kind {
|
||||
ty::BoundRegionKind::Named(def_id) => def_id,
|
||||
ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => {
|
||||
|
|
@ -961,7 +967,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't
|
|||
ty::ConstKind::Param(param) => {
|
||||
self.params.insert(param.index);
|
||||
}
|
||||
ty::ConstKind::Bound(db, _) if db >= self.depth => {
|
||||
ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(db), _) if db >= self.depth => {
|
||||
let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var");
|
||||
return ControlFlow::Break(guar);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ fn is_valid_cmse_inputs<'tcx>(
|
|||
|
||||
// this type is only used for layout computation, which does not rely on regions
|
||||
let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
|
||||
let fn_sig = tcx.erase_and_anonymize_regions(fn_sig);
|
||||
|
||||
for (index, ty) in fn_sig.inputs().iter().enumerate() {
|
||||
let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ use tracing::{debug, instrument};
|
|||
|
||||
use super::HirTyLowerer;
|
||||
use crate::errors::SelfInTypeAlias;
|
||||
use crate::hir_ty_lowering::{GenericArgCountMismatch, PredicateFilter, RegionInferReason};
|
||||
use crate::hir_ty_lowering::{
|
||||
GenericArgCountMismatch, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason,
|
||||
};
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// Lower a trait object type from the HIR to our internal notion of a type.
|
||||
|
|
@ -60,6 +62,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
dummy_self,
|
||||
&mut user_written_bounds,
|
||||
PredicateFilter::SelfOnly,
|
||||
OverlappingAsssocItemConstraints::Forbidden,
|
||||
);
|
||||
if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct {
|
||||
potential_assoc_types.extend(invalid_args);
|
||||
|
|
@ -157,10 +160,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
format!(
|
||||
"conflicting associated type bounds for `{item}` when \
|
||||
expanding trait alias"
|
||||
),
|
||||
format!("conflicting associated type bounds for `{item}`"),
|
||||
)
|
||||
.with_span_label(
|
||||
old_proj_span,
|
||||
|
|
|
|||
|
|
@ -332,6 +332,15 @@ pub(crate) enum GenericArgPosition {
|
|||
MethodCall,
|
||||
}
|
||||
|
||||
/// Whether to allow duplicate associated iten constraints in a trait ref, e.g.
|
||||
/// `Trait<Assoc = Ty, Assoc = Ty>`. This is forbidden in `dyn Trait<...>`
|
||||
/// but allowed everywhere else.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub(crate) enum OverlappingAsssocItemConstraints {
|
||||
Allowed,
|
||||
Forbidden,
|
||||
}
|
||||
|
||||
/// A marker denoting that the generic arguments that were
|
||||
/// provided did not match the respective generic parameters.
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -752,6 +761,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self_ty: Ty<'tcx>,
|
||||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
predicate_filter: PredicateFilter,
|
||||
overlapping_assoc_item_constraints: OverlappingAsssocItemConstraints,
|
||||
) -> GenericArgCountResult {
|
||||
let tcx = self.tcx();
|
||||
|
||||
|
|
@ -908,7 +918,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
let mut dup_constraints = FxIndexMap::default();
|
||||
let mut dup_constraints = (overlapping_assoc_item_constraints
|
||||
== OverlappingAsssocItemConstraints::Forbidden)
|
||||
.then_some(FxIndexMap::default());
|
||||
|
||||
for constraint in trait_segment.args().constraints {
|
||||
// Don't register any associated item constraints for negative bounds,
|
||||
// since we should have emitted an error for them earlier, and they
|
||||
|
|
@ -927,7 +940,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
poly_trait_ref,
|
||||
constraint,
|
||||
bounds,
|
||||
&mut dup_constraints,
|
||||
dup_constraints.as_mut(),
|
||||
constraint.span,
|
||||
predicate_filter,
|
||||
);
|
||||
|
|
@ -2484,6 +2497,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::All,
|
||||
OverlappingAsssocItemConstraints::Allowed,
|
||||
);
|
||||
self.add_sizedness_bounds(
|
||||
&mut bounds,
|
||||
|
|
|
|||
|
|
@ -3551,35 +3551,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
// Try to give some advice about indexing tuples.
|
||||
if let ty::Tuple(types) = base_t.kind() {
|
||||
let mut needs_note = true;
|
||||
// If the index is an integer, we can show the actual
|
||||
// fixed expression:
|
||||
err.help(
|
||||
"tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc.",
|
||||
);
|
||||
// If index is an unsuffixed integer, show the fixed expression:
|
||||
if let ExprKind::Lit(lit) = idx.kind
|
||||
&& let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node
|
||||
&& i.get()
|
||||
< types
|
||||
.len()
|
||||
.try_into()
|
||||
.expect("expected tuple index to be < usize length")
|
||||
&& i.get() < types.len().try_into().expect("tuple length fits in u128")
|
||||
{
|
||||
err.span_suggestion(
|
||||
brackets_span,
|
||||
"to access tuple elements, use",
|
||||
format!("to access tuple element `{i}`, use"),
|
||||
format!(".{i}"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
needs_note = false;
|
||||
} else if let ExprKind::Path(..) = idx.peel_borrows().kind {
|
||||
err.span_label(
|
||||
idx.span,
|
||||
"cannot access tuple elements at a variable index",
|
||||
);
|
||||
}
|
||||
if needs_note {
|
||||
err.help(
|
||||
"to access tuple elements, use tuple indexing \
|
||||
syntax (e.g., `tuple.0`)",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -611,19 +611,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
typeck_results.rvalue_scopes = rvalue_scopes;
|
||||
}
|
||||
|
||||
/// Unify the inference variables corresponding to coroutine witnesses, and save all the
|
||||
/// predicates that were stalled on those inference variables.
|
||||
///
|
||||
/// This process allows to conservatively save all predicates that do depend on the coroutine
|
||||
/// interior types, for later processing by `check_coroutine_obligations`.
|
||||
///
|
||||
/// We must not attempt to select obligations after this method has run, or risk query cycle
|
||||
/// ICE.
|
||||
/// Drain all obligations that are stalled on coroutines defined in this body.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn resolve_coroutine_interiors(&self) {
|
||||
// Try selecting all obligations that are not blocked on inference variables.
|
||||
// Once we start unifying coroutine witnesses, trying to select obligations on them will
|
||||
// trigger query cycle ICEs, as doing so requires MIR.
|
||||
pub(crate) fn drain_stalled_coroutine_obligations(&self) {
|
||||
// Make as much inference progress as possible before
|
||||
// draining the stalled coroutine obligations as this may
|
||||
// change obligations from being stalled on infer vars to
|
||||
// being stalled on a coroutine.
|
||||
self.select_obligations_where_possible(|_| {});
|
||||
|
||||
let ty::TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
|
||||
|
|
|
|||
|
|
@ -243,18 +243,15 @@ fn typeck_with_inspect<'tcx>(
|
|||
|
||||
debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
|
||||
|
||||
// This must be the last thing before `report_ambiguity_errors`.
|
||||
fcx.resolve_coroutine_interiors();
|
||||
|
||||
debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
|
||||
|
||||
// We need to handle opaque types before emitting ambiguity errors as applying
|
||||
// defining uses may guide type inference.
|
||||
if fcx.next_trait_solver() {
|
||||
fcx.handle_opaque_type_uses_next();
|
||||
}
|
||||
|
||||
fcx.select_obligations_where_possible(|_| {});
|
||||
// This must be the last thing before `report_ambiguity_errors` below except `select_obligations_where_possible`.
|
||||
// So don't put anything after this.
|
||||
fcx.drain_stalled_coroutine_obligations();
|
||||
if fcx.infcx.tainted_by_errors().is_none() {
|
||||
fcx.report_ambiguity_errors();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use crate::FnCtxt;
|
|||
|
||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
/// This takes all the opaque type uses during HIR typeck. It first computes
|
||||
/// the concrete hidden type by iterating over all defining uses.
|
||||
/// the hidden type by iterating over all defining uses.
|
||||
///
|
||||
/// A use during HIR typeck is defining if all non-lifetime arguments are
|
||||
/// unique generic parameters and the hidden type does not reference any
|
||||
|
|
@ -35,8 +35,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
}
|
||||
debug!(?opaque_types);
|
||||
|
||||
self.compute_concrete_opaque_types(&opaque_types);
|
||||
self.apply_computed_concrete_opaque_types(&opaque_types);
|
||||
self.compute_definition_site_hidden_types(&opaque_types);
|
||||
self.apply_definition_site_hidden_types(&opaque_types);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ impl<'tcx> UsageKind<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
fn compute_concrete_opaque_types(
|
||||
fn compute_definition_site_hidden_types(
|
||||
&mut self,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
) {
|
||||
|
|
@ -142,7 +142,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.concrete_opaque_types
|
||||
.hidden_types
|
||||
.insert(def_id, OpaqueHiddenType::new_error(tcx, guar));
|
||||
self.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
|
@ -161,7 +161,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
) {
|
||||
match err {
|
||||
NonDefiningUseReason::Tainted(guar) => {
|
||||
self.typeck_results.borrow_mut().concrete_opaque_types.insert(
|
||||
self.typeck_results.borrow_mut().hidden_types.insert(
|
||||
opaque_type_key.def_id,
|
||||
OpaqueHiddenType::new_error(self.tcx, guar),
|
||||
);
|
||||
|
|
@ -197,20 +197,19 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
let prev = self
|
||||
.typeck_results
|
||||
.borrow_mut()
|
||||
.concrete_opaque_types
|
||||
.hidden_types
|
||||
.insert(opaque_type_key.def_id, hidden_type);
|
||||
assert!(prev.is_none());
|
||||
UsageKind::HasDefiningUse
|
||||
}
|
||||
|
||||
fn apply_computed_concrete_opaque_types(
|
||||
fn apply_definition_site_hidden_types(
|
||||
&mut self,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
for &(key, hidden_type) in opaque_types {
|
||||
let expected =
|
||||
*self.typeck_results.borrow_mut().concrete_opaque_types.get(&key.def_id).unwrap();
|
||||
let expected = *self.typeck_results.borrow_mut().hidden_types.get(&key.def_id).unwrap();
|
||||
|
||||
let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args);
|
||||
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
|
||||
|
|
|
|||
|
|
@ -550,13 +550,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
fn visit_opaque_types_next(&mut self) {
|
||||
let mut fcx_typeck_results = self.fcx.typeck_results.borrow_mut();
|
||||
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
|
||||
for hidden_ty in fcx_typeck_results.concrete_opaque_types.values() {
|
||||
for hidden_ty in fcx_typeck_results.hidden_types.values() {
|
||||
assert!(!hidden_ty.has_infer());
|
||||
}
|
||||
|
||||
assert_eq!(self.typeck_results.concrete_opaque_types.len(), 0);
|
||||
self.typeck_results.concrete_opaque_types =
|
||||
mem::take(&mut fcx_typeck_results.concrete_opaque_types);
|
||||
assert_eq!(self.typeck_results.hidden_types.len(), 0);
|
||||
self.typeck_results.hidden_types = mem::take(&mut fcx_typeck_results.hidden_types);
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
|
|
@ -588,7 +587,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
hidden_type.span,
|
||||
DefiningScopeKind::HirTypeck,
|
||||
) {
|
||||
self.typeck_results.concrete_opaque_types.insert(
|
||||
self.typeck_results.hidden_types.insert(
|
||||
opaque_type_key.def_id,
|
||||
ty::OpaqueHiddenType::new_error(tcx, err.report(self.fcx)),
|
||||
);
|
||||
|
|
@ -600,16 +599,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
DefiningScopeKind::HirTypeck,
|
||||
);
|
||||
|
||||
if let Some(prev) = self
|
||||
.typeck_results
|
||||
.concrete_opaque_types
|
||||
.insert(opaque_type_key.def_id, hidden_type)
|
||||
if let Some(prev) =
|
||||
self.typeck_results.hidden_types.insert(opaque_type_key.def_id, hidden_type)
|
||||
{
|
||||
let entry = &mut self
|
||||
.typeck_results
|
||||
.concrete_opaque_types
|
||||
.get_mut(&opaque_type_key.def_id)
|
||||
.unwrap();
|
||||
let entry =
|
||||
&mut self.typeck_results.hidden_types.get_mut(&opaque_type_key.def_id).unwrap();
|
||||
if prev.ty != hidden_type.ty {
|
||||
if let Some(guar) = self.typeck_results.tainted_by_errors {
|
||||
entry.ty = Ty::new_error(tcx, guar);
|
||||
|
|
@ -628,7 +622,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
|
||||
let recursive_opaques: Vec<_> = self
|
||||
.typeck_results
|
||||
.concrete_opaque_types
|
||||
.hidden_types
|
||||
.iter()
|
||||
.filter(|&(&def_id, hidden_ty)| {
|
||||
hidden_ty
|
||||
|
|
@ -636,7 +630,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
.visit_with(&mut HasRecursiveOpaque {
|
||||
def_id,
|
||||
seen: Default::default(),
|
||||
opaques: &self.typeck_results.concrete_opaque_types,
|
||||
opaques: &self.typeck_results.hidden_types,
|
||||
tcx,
|
||||
})
|
||||
.is_break()
|
||||
|
|
@ -651,7 +645,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
.with_code(E0720)
|
||||
.emit();
|
||||
self.typeck_results
|
||||
.concrete_opaque_types
|
||||
.hidden_types
|
||||
.insert(def_id, OpaqueHiddenType { span, ty: Ty::new_error(tcx, guar) });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,8 +303,6 @@ struct Canonicalizer<'cx, 'tcx> {
|
|||
sub_root_lookup_table: SsoHashMap<ty::TyVid, usize>,
|
||||
canonicalize_mode: &'cx dyn CanonicalizeMode,
|
||||
needs_canonical_flags: TypeFlags,
|
||||
|
||||
binder_index: ty::DebruijnIndex,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
||||
|
|
@ -312,24 +310,12 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.binder_index.shift_in(1);
|
||||
let t = t.super_fold_with(self);
|
||||
self.binder_index.shift_out(1);
|
||||
t
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match r.kind() {
|
||||
ty::ReBound(index, ..) => {
|
||||
if index >= self.binder_index {
|
||||
bug!("escaping late-bound region during canonicalization");
|
||||
} else {
|
||||
r
|
||||
}
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(_), ..) => r,
|
||||
|
||||
ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => {
|
||||
bug!("canonicalized bound var found during canonicalization");
|
||||
}
|
||||
|
||||
ty::ReStatic
|
||||
|
|
@ -403,12 +389,10 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t)
|
||||
}
|
||||
|
||||
ty::Bound(debruijn, _) => {
|
||||
if debruijn >= self.binder_index {
|
||||
bug!("escaping bound type during canonicalization")
|
||||
} else {
|
||||
t
|
||||
}
|
||||
ty::Bound(ty::BoundVarIndexKind::Bound(_), _) => t,
|
||||
|
||||
ty::Bound(ty::BoundVarIndexKind::Canonical, _) => {
|
||||
bug!("canonicalized bound var found during canonicalization");
|
||||
}
|
||||
|
||||
ty::Closure(..)
|
||||
|
|
@ -479,12 +463,11 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
|
||||
bug!("encountered a fresh const during canonicalization")
|
||||
}
|
||||
ty::ConstKind::Bound(debruijn, _) => {
|
||||
if debruijn >= self.binder_index {
|
||||
bug!("escaping bound const during canonicalization")
|
||||
} else {
|
||||
return ct;
|
||||
}
|
||||
ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(_), _) => {
|
||||
return ct;
|
||||
}
|
||||
ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, _) => {
|
||||
bug!("canonicalized bound var found during canonicalization");
|
||||
}
|
||||
ty::ConstKind::Placeholder(placeholder) => {
|
||||
return self
|
||||
|
|
@ -569,7 +552,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
query_state,
|
||||
indices: FxHashMap::default(),
|
||||
sub_root_lookup_table: Default::default(),
|
||||
binder_index: ty::INNERMOST,
|
||||
};
|
||||
if canonicalizer.query_state.var_values.spilled() {
|
||||
canonicalizer.indices = canonicalizer
|
||||
|
|
@ -751,8 +733,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
r: ty::Region<'tcx>,
|
||||
) -> ty::Region<'tcx> {
|
||||
let var = self.canonical_var(var_kind, r.into());
|
||||
let br = ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon };
|
||||
ty::Region::new_bound(self.cx(), self.binder_index, br)
|
||||
ty::Region::new_canonical_bound(self.cx(), var)
|
||||
}
|
||||
|
||||
/// Given a type variable `ty_var` of the given kind, first check
|
||||
|
|
@ -766,8 +747,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
) -> Ty<'tcx> {
|
||||
debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var)));
|
||||
let var = self.canonical_var(var_kind, ty_var.into());
|
||||
let bt = ty::BoundTy { var, kind: ty::BoundTyKind::Anon };
|
||||
Ty::new_bound(self.tcx, self.binder_index, bt)
|
||||
Ty::new_canonical_bound(self.tcx, var)
|
||||
}
|
||||
|
||||
/// Given a type variable `const_var` of the given kind, first check
|
||||
|
|
@ -783,7 +763,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
!self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var))
|
||||
);
|
||||
let var = self.canonical_var(var_kind, ct_var.into());
|
||||
let bc = ty::BoundConst { var };
|
||||
ty::Const::new_bound(self.tcx, self.binder_index, bc)
|
||||
ty::Const::new_canonical_bound(self.tcx, var)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_middle::ty::{
|
|||
self, DelayedMap, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
|
||||
TypeVisitableExt, TypeVisitor,
|
||||
};
|
||||
use rustc_type_ir::TypeVisitable;
|
||||
use rustc_type_ir::{TypeFlags, TypeVisitable};
|
||||
|
||||
use crate::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
|
||||
|
|
@ -66,7 +66,6 @@ where
|
|||
|
||||
value.fold_with(&mut CanonicalInstantiator {
|
||||
tcx,
|
||||
current_index: ty::INNERMOST,
|
||||
var_values: var_values.var_values,
|
||||
cache: Default::default(),
|
||||
})
|
||||
|
|
@ -79,12 +78,9 @@ struct CanonicalInstantiator<'tcx> {
|
|||
// The values that the bound vars are are being instantiated with.
|
||||
var_values: ty::GenericArgsRef<'tcx>,
|
||||
|
||||
/// As with `BoundVarReplacer`, represents the index of a binder *just outside*
|
||||
/// the ones we have visited.
|
||||
current_index: ty::DebruijnIndex,
|
||||
|
||||
// Instantiation is a pure function of `DebruijnIndex` and `Ty`.
|
||||
cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>,
|
||||
// Because we use `ty::BoundVarIndexKind::Canonical`, we can cache
|
||||
// based only on the entire ty, not worrying about a `DebruijnIndex`
|
||||
cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
|
||||
|
|
@ -92,29 +88,19 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
|
|||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
t: ty::Binder<'tcx, T>,
|
||||
) -> ty::Binder<'tcx, T> {
|
||||
self.current_index.shift_in(1);
|
||||
let t = t.super_fold_with(self);
|
||||
self.current_index.shift_out(1);
|
||||
t
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *t.kind() {
|
||||
ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
|
||||
ty::Bound(ty::BoundVarIndexKind::Canonical, bound_ty) => {
|
||||
self.var_values[bound_ty.var.as_usize()].expect_ty()
|
||||
}
|
||||
_ => {
|
||||
if !t.has_vars_bound_at_or_above(self.current_index) {
|
||||
if !t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
|
||||
t
|
||||
} else if let Some(&t) = self.cache.get(&(self.current_index, t)) {
|
||||
} else if let Some(&t) = self.cache.get(&t) {
|
||||
t
|
||||
} else {
|
||||
let res = t.super_fold_with(self);
|
||||
assert!(self.cache.insert((self.current_index, t), res));
|
||||
assert!(self.cache.insert(t, res));
|
||||
res
|
||||
}
|
||||
}
|
||||
|
|
@ -123,7 +109,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
|
|||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match r.kind() {
|
||||
ty::ReBound(debruijn, br) if debruijn == self.current_index => {
|
||||
ty::ReBound(ty::BoundVarIndexKind::Canonical, br) => {
|
||||
self.var_values[br.var.as_usize()].expect_region()
|
||||
}
|
||||
_ => r,
|
||||
|
|
@ -132,7 +118,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
|
|||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
|
||||
ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bound_const) => {
|
||||
self.var_values[bound_const.var.as_usize()].expect_const()
|
||||
}
|
||||
_ => ct.super_fold_with(self),
|
||||
|
|
@ -140,22 +126,14 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
|
|||
}
|
||||
|
||||
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
||||
if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
|
||||
if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p }
|
||||
}
|
||||
|
||||
fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
|
||||
if !c.has_vars_bound_at_or_above(self.current_index) {
|
||||
if !c.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
|
||||
return c;
|
||||
}
|
||||
|
||||
// Since instantiation is a function of `DebruijnIndex`, we don't want
|
||||
// to have to cache more copies of clauses when we're inside of binders.
|
||||
// Since we currently expect to only have clauses in the outermost
|
||||
// debruijn index, we just fold if we're inside of a binder.
|
||||
if self.current_index > ty::INNERMOST {
|
||||
return c.super_fold_with(self);
|
||||
}
|
||||
|
||||
// Our cache key is `(clauses, var_values)`, but we also don't care about
|
||||
// var values that aren't named in the clauses, since they can change without
|
||||
// affecting the output. Since `ParamEnv`s are cached first, we compute the
|
||||
|
|
@ -185,45 +163,29 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
|
|||
fn highest_var_in_clauses<'tcx>(c: ty::Clauses<'tcx>) -> usize {
|
||||
struct HighestVarInClauses {
|
||||
max_var: usize,
|
||||
current_index: ty::DebruijnIndex,
|
||||
}
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HighestVarInClauses {
|
||||
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
t: &ty::Binder<'tcx, T>,
|
||||
) -> Self::Result {
|
||||
self.current_index.shift_in(1);
|
||||
let t = t.super_visit_with(self);
|
||||
self.current_index.shift_out(1);
|
||||
t
|
||||
}
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) {
|
||||
if let ty::Bound(debruijn, bound_ty) = *t.kind()
|
||||
&& debruijn == self.current_index
|
||||
{
|
||||
if let ty::Bound(ty::BoundVarIndexKind::Canonical, bound_ty) = *t.kind() {
|
||||
self.max_var = self.max_var.max(bound_ty.var.as_usize());
|
||||
} else if t.has_vars_bound_at_or_above(self.current_index) {
|
||||
} else if t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
|
||||
t.super_visit_with(self);
|
||||
}
|
||||
}
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) {
|
||||
if let ty::ReBound(debruijn, bound_region) = r.kind()
|
||||
&& debruijn == self.current_index
|
||||
{
|
||||
if let ty::ReBound(ty::BoundVarIndexKind::Canonical, bound_region) = r.kind() {
|
||||
self.max_var = self.max_var.max(bound_region.var.as_usize());
|
||||
}
|
||||
}
|
||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) {
|
||||
if let ty::ConstKind::Bound(debruijn, bound_const) = ct.kind()
|
||||
&& debruijn == self.current_index
|
||||
{
|
||||
if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bound_const) = ct.kind() {
|
||||
self.max_var = self.max_var.max(bound_const.var.as_usize());
|
||||
} else if ct.has_vars_bound_at_or_above(self.current_index) {
|
||||
} else if ct.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
|
||||
ct.super_visit_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut visitor = HighestVarInClauses { max_var: 0, current_index: ty::INNERMOST };
|
||||
let mut visitor = HighestVarInClauses { max_var: 0 };
|
||||
c.visit_with(&mut visitor);
|
||||
visitor.max_var
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,28 +440,28 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
// and only use it for placeholders. We need to handle the
|
||||
// `sub_root` of type inference variables which would make this
|
||||
// more involved. They are also a lot rarer than region variables.
|
||||
if let ty::Bound(debruijn, b) = *result_value.kind()
|
||||
if let ty::Bound(index_kind, b) = *result_value.kind()
|
||||
&& !matches!(
|
||||
query_response.variables[b.var.as_usize()],
|
||||
CanonicalVarKind::Ty { .. }
|
||||
)
|
||||
{
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
// We only allow a `Canonical` index in generic parameters.
|
||||
assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
|
||||
opt_values[b.var] = Some(*original_value);
|
||||
}
|
||||
}
|
||||
GenericArgKind::Lifetime(result_value) => {
|
||||
if let ty::ReBound(debruijn, b) = result_value.kind() {
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
if let ty::ReBound(index_kind, b) = result_value.kind() {
|
||||
// We only allow a `Canonical` index in generic parameters.
|
||||
assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
|
||||
opt_values[b.var] = Some(*original_value);
|
||||
}
|
||||
}
|
||||
GenericArgKind::Const(result_value) => {
|
||||
if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() {
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
if let ty::ConstKind::Bound(index_kind, b) = result_value.kind() {
|
||||
// We only allow a `Canonical` index in generic parameters.
|
||||
assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
|
||||
opt_values[b.var] = Some(*original_value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,23 +131,6 @@ pub struct InferCtxtInner<'tcx> {
|
|||
/// `$0: 'static`. This will get checked later by regionck. (We
|
||||
/// can't generally check these things right away because we have
|
||||
/// to wait until types are resolved.)
|
||||
///
|
||||
/// These are stored in a map keyed to the id of the innermost
|
||||
/// enclosing fn body / static initializer expression. This is
|
||||
/// because the location where the obligation was incurred can be
|
||||
/// relevant with respect to which sublifetime assumptions are in
|
||||
/// place. The reason that we store under the fn-id, and not
|
||||
/// something more fine-grained, is so that it is easier for
|
||||
/// regionck to be sure that it has found *all* the region
|
||||
/// obligations (otherwise, it's easy to fail to walk to a
|
||||
/// particular node-id).
|
||||
///
|
||||
/// Before running `resolve_regions_and_report_errors`, the creator
|
||||
/// of the inference context is expected to invoke
|
||||
/// [`InferCtxt::process_registered_region_obligations`]
|
||||
/// for each body-id in this map, which will process the
|
||||
/// obligations within. This is expected to be done 'late enough'
|
||||
/// that all type inference variables have been bound and so forth.
|
||||
region_obligations: Vec<TypeOutlivesConstraint<'tcx>>,
|
||||
|
||||
/// The outlives bounds that we assume must hold about placeholders that
|
||||
|
|
|
|||
|
|
@ -170,6 +170,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
std::mem::take(&mut self.inner.borrow_mut().region_obligations)
|
||||
}
|
||||
|
||||
pub fn clone_registered_region_obligations(&self) -> Vec<TypeOutlivesConstraint<'tcx>> {
|
||||
self.inner.borrow().region_obligations.clone()
|
||||
}
|
||||
|
||||
pub fn register_region_assumption(&self, assumption: ty::ArgOutlivesPredicate<'tcx>) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
inner.undo_log.push(UndoLog::PushRegionAssumption);
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ pub fn extract_verify_if_eq<'tcx>(
|
|||
let verify_if_eq = verify_if_eq_b.skip_binder();
|
||||
m.relate(verify_if_eq.ty, test_ty).ok()?;
|
||||
|
||||
if let ty::RegionKind::ReBound(depth, br) = verify_if_eq.bound.kind() {
|
||||
assert!(depth == ty::INNERMOST);
|
||||
if let ty::RegionKind::ReBound(index_kind, br) = verify_if_eq.bound.kind() {
|
||||
assert!(matches!(index_kind, ty::BoundVarIndexKind::Bound(ty::INNERMOST)));
|
||||
match m.map.get(&br) {
|
||||
Some(&r) => Some(r),
|
||||
None => {
|
||||
|
|
@ -156,7 +156,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx>
|
|||
pattern: ty::Region<'tcx>,
|
||||
value: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
if let ty::RegionKind::ReBound(depth, br) = pattern.kind()
|
||||
if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(depth), br) = pattern.kind()
|
||||
&& depth == self.pattern_depth
|
||||
{
|
||||
self.bind(br, value)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::any::Any;
|
||||
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
|
@ -6,13 +7,20 @@ use std::{env, thread};
|
|||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr_parsing::{ShouldEmit, validate_attr};
|
||||
use rustc_codegen_ssa::back::archive::ArArchiveBuilderBuilder;
|
||||
use rustc_codegen_ssa::back::link::link_binary;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_errors::LintBuffer;
|
||||
use rustc_metadata::{DylibError, load_symbol_from_dylib};
|
||||
use rustc_middle::ty::CurrentGcx;
|
||||
use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple};
|
||||
use rustc_metadata::{DylibError, EncodedMetadata, load_symbol_from_dylib};
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::{CurrentGcx, TyCtxt};
|
||||
use rustc_session::config::{
|
||||
Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple,
|
||||
};
|
||||
use rustc_session::output::{CRATE_TYPES, categorize_crate_type};
|
||||
use rustc_session::{EarlyDiagCtxt, Session, filesearch, lint};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
|
|
@ -316,12 +324,13 @@ pub fn get_codegen_backend(
|
|||
let backend = backend_name
|
||||
.or(target.default_codegen_backend.as_deref())
|
||||
.or(option_env!("CFG_DEFAULT_CODEGEN_BACKEND"))
|
||||
.unwrap_or("llvm");
|
||||
.unwrap_or("dummy");
|
||||
|
||||
match backend {
|
||||
filename if filename.contains('.') => {
|
||||
load_backend_from_dylib(early_dcx, filename.as_ref())
|
||||
}
|
||||
"dummy" => || Box::new(DummyCodegenBackend),
|
||||
#[cfg(feature = "llvm")]
|
||||
"llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
|
||||
backend_name => get_codegen_sysroot(early_dcx, sysroot, backend_name),
|
||||
|
|
@ -334,6 +343,63 @@ pub fn get_codegen_backend(
|
|||
unsafe { load() }
|
||||
}
|
||||
|
||||
struct DummyCodegenBackend;
|
||||
|
||||
impl CodegenBackend for DummyCodegenBackend {
|
||||
fn locale_resource(&self) -> &'static str {
|
||||
""
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"dummy"
|
||||
}
|
||||
|
||||
fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> {
|
||||
Box::new(CodegenResults {
|
||||
modules: vec![],
|
||||
allocator_module: None,
|
||||
crate_info: CrateInfo::new(tcx, String::new()),
|
||||
})
|
||||
}
|
||||
|
||||
fn join_codegen(
|
||||
&self,
|
||||
ongoing_codegen: Box<dyn Any>,
|
||||
_sess: &Session,
|
||||
_outputs: &OutputFilenames,
|
||||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
(*ongoing_codegen.downcast().unwrap(), FxIndexMap::default())
|
||||
}
|
||||
|
||||
fn link(
|
||||
&self,
|
||||
sess: &Session,
|
||||
codegen_results: CodegenResults,
|
||||
metadata: EncodedMetadata,
|
||||
outputs: &OutputFilenames,
|
||||
) {
|
||||
// JUSTIFICATION: TyCtxt no longer available here
|
||||
#[allow(rustc::bad_opt_access)]
|
||||
if sess.opts.crate_types.iter().any(|&crate_type| crate_type != CrateType::Rlib) {
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
sess.dcx().fatal(format!(
|
||||
"crate type {} not supported by the dummy codegen backend",
|
||||
sess.opts.crate_types[0],
|
||||
));
|
||||
}
|
||||
|
||||
link_binary(
|
||||
sess,
|
||||
&ArArchiveBuilderBuilder,
|
||||
codegen_results,
|
||||
metadata,
|
||||
outputs,
|
||||
self.name(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// This is used for rustdoc, but it uses similar machinery to codegen backend
|
||||
// loading, so we leave the code here. It is potentially useful for other tools
|
||||
// that want to invoke the rustc binary while linking to rustc as well.
|
||||
|
|
|
|||
|
|
@ -1824,3 +1824,55 @@ extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() {
|
|||
return 6; // Default fallback depth
|
||||
}
|
||||
#endif
|
||||
|
||||
// Statically assert that the fixed metadata kind IDs declared in
|
||||
// `metadata_kind.rs` match the ones actually used by LLVM.
|
||||
#define FIXED_MD_KIND(VARIANT, VALUE) \
|
||||
static_assert(::llvm::LLVMContext::VARIANT == VALUE);
|
||||
// Must be kept in sync with the corresponding list in `metadata_kind.rs`.
|
||||
FIXED_MD_KIND(MD_dbg, 0)
|
||||
FIXED_MD_KIND(MD_tbaa, 1)
|
||||
FIXED_MD_KIND(MD_prof, 2)
|
||||
FIXED_MD_KIND(MD_fpmath, 3)
|
||||
FIXED_MD_KIND(MD_range, 4)
|
||||
FIXED_MD_KIND(MD_tbaa_struct, 5)
|
||||
FIXED_MD_KIND(MD_invariant_load, 6)
|
||||
FIXED_MD_KIND(MD_alias_scope, 7)
|
||||
FIXED_MD_KIND(MD_noalias, 8)
|
||||
FIXED_MD_KIND(MD_nontemporal, 9)
|
||||
FIXED_MD_KIND(MD_mem_parallel_loop_access, 10)
|
||||
FIXED_MD_KIND(MD_nonnull, 11)
|
||||
FIXED_MD_KIND(MD_dereferenceable, 12)
|
||||
FIXED_MD_KIND(MD_dereferenceable_or_null, 13)
|
||||
FIXED_MD_KIND(MD_make_implicit, 14)
|
||||
FIXED_MD_KIND(MD_unpredictable, 15)
|
||||
FIXED_MD_KIND(MD_invariant_group, 16)
|
||||
FIXED_MD_KIND(MD_align, 17)
|
||||
FIXED_MD_KIND(MD_loop, 18)
|
||||
FIXED_MD_KIND(MD_type, 19)
|
||||
FIXED_MD_KIND(MD_section_prefix, 20)
|
||||
FIXED_MD_KIND(MD_absolute_symbol, 21)
|
||||
FIXED_MD_KIND(MD_associated, 22)
|
||||
FIXED_MD_KIND(MD_callees, 23)
|
||||
FIXED_MD_KIND(MD_irr_loop, 24)
|
||||
FIXED_MD_KIND(MD_access_group, 25)
|
||||
FIXED_MD_KIND(MD_callback, 26)
|
||||
FIXED_MD_KIND(MD_preserve_access_index, 27)
|
||||
FIXED_MD_KIND(MD_vcall_visibility, 28)
|
||||
FIXED_MD_KIND(MD_noundef, 29)
|
||||
FIXED_MD_KIND(MD_annotation, 30)
|
||||
FIXED_MD_KIND(MD_nosanitize, 31)
|
||||
FIXED_MD_KIND(MD_func_sanitize, 32)
|
||||
FIXED_MD_KIND(MD_exclude, 33)
|
||||
FIXED_MD_KIND(MD_memprof, 34)
|
||||
FIXED_MD_KIND(MD_callsite, 35)
|
||||
FIXED_MD_KIND(MD_kcfi_type, 36)
|
||||
FIXED_MD_KIND(MD_pcsections, 37)
|
||||
FIXED_MD_KIND(MD_DIAssignID, 38)
|
||||
FIXED_MD_KIND(MD_coro_outside_frame, 39)
|
||||
FIXED_MD_KIND(MD_mmra, 40)
|
||||
FIXED_MD_KIND(MD_noalias_addrspace, 41)
|
||||
// If some fixed metadata kinds are not present and consistent in all supported
|
||||
// LLVM versions, it's fine to omit them from this list; in that case Rust-side
|
||||
// code cannot declare them as fixed IDs and must look them up by name instead.
|
||||
#undef FIXED_MD_KIND
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ macro_rules! arena_types {
|
|||
rustc_middle::mir::Body<'tcx>
|
||||
>,
|
||||
[decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>,
|
||||
[decode] borrowck_result: rustc_middle::mir::ConcreteOpaqueTypes<'tcx>,
|
||||
[decode] borrowck_result: rustc_middle::mir::DefinitionSiteHiddenTypes<'tcx>,
|
||||
[] resolver: rustc_data_structures::steal::Steal<(
|
||||
rustc_middle::ty::ResolverAstLowering,
|
||||
std::sync::Arc<rustc_ast::Crate>,
|
||||
|
|
|
|||
|
|
@ -1274,7 +1274,6 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
|
|||
for &elem in projection.iter().rev() {
|
||||
match elem {
|
||||
ProjectionElem::OpaqueCast(_)
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Downcast(_, _)
|
||||
| ProjectionElem::Field(_, _) => {
|
||||
write!(fmt, "(")?;
|
||||
|
|
@ -1300,9 +1299,6 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
|
|||
ProjectionElem::OpaqueCast(ty) => {
|
||||
write!(fmt, " as {ty})")?;
|
||||
}
|
||||
ProjectionElem::Subtype(ty) => {
|
||||
write!(fmt, " as subtype {ty})")?;
|
||||
}
|
||||
ProjectionElem::Downcast(Some(name), _index) => {
|
||||
write!(fmt, " as {name})")?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,11 +84,10 @@ impl Debug for CoroutineLayout<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// All the opaque types that are restricted to concrete types
|
||||
/// by this function. Unlike the value in `TypeckResults`, this has
|
||||
/// unerased regions.
|
||||
/// All the opaque types that have had their hidden type fully computed.
|
||||
/// Unlike the value in `TypeckResults`, this has unerased regions.
|
||||
#[derive(Default, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct ConcreteOpaqueTypes<'tcx>(pub FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>);
|
||||
pub struct DefinitionSiteHiddenTypes<'tcx>(pub FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>);
|
||||
|
||||
/// The result of the `mir_const_qualif` query.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -222,7 +222,6 @@ impl<'tcx> PlaceTy<'tcx> {
|
|||
fty,
|
||||
)),
|
||||
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)),
|
||||
ProjectionElem::Subtype(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)),
|
||||
|
||||
// FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
|
||||
ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||
|
|
@ -244,7 +243,6 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
Self::Field(_, _)
|
||||
| Self::Index(_)
|
||||
| Self::OpaqueCast(_)
|
||||
| Self::Subtype(_)
|
||||
| Self::ConstantIndex { .. }
|
||||
| Self::Subslice { .. }
|
||||
| Self::Downcast(_, _)
|
||||
|
|
@ -259,7 +257,6 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
Self::Deref | Self::Index(_) => false,
|
||||
Self::Field(_, _)
|
||||
| Self::OpaqueCast(_)
|
||||
| Self::Subtype(_)
|
||||
| Self::ConstantIndex { .. }
|
||||
| Self::Subslice { .. }
|
||||
| Self::Downcast(_, _)
|
||||
|
|
@ -286,7 +283,6 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
| Self::Field(_, _) => true,
|
||||
Self::ConstantIndex { from_end: true, .. }
|
||||
| Self::Index(_)
|
||||
| Self::Subtype(_)
|
||||
| Self::OpaqueCast(_)
|
||||
| Self::Subslice { .. } => false,
|
||||
|
||||
|
|
@ -319,7 +315,6 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
ProjectionElem::Subslice { from, to, from_end }
|
||||
}
|
||||
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(t(ty)),
|
||||
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(t(ty)),
|
||||
ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(t(ty)),
|
||||
ProjectionElem::Index(val) => ProjectionElem::Index(v(val)?),
|
||||
})
|
||||
|
|
@ -706,7 +701,8 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
| CastKind::PtrToPtr
|
||||
| CastKind::PointerCoercion(_, _)
|
||||
| CastKind::PointerWithExposedProvenance
|
||||
| CastKind::Transmute,
|
||||
| CastKind::Transmute
|
||||
| CastKind::Subtype,
|
||||
_,
|
||||
_,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1275,18 +1275,6 @@ pub enum ProjectionElem<V, T> {
|
|||
/// A transmute from an unsafe binder to the type that it wraps. This is a projection
|
||||
/// of a place, so it doesn't necessarily constitute a move out of the binder.
|
||||
UnwrapUnsafeBinder(T),
|
||||
|
||||
/// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
|
||||
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
|
||||
/// explicit during optimizations and codegen.
|
||||
///
|
||||
/// This projection doesn't impact the runtime behavior of the program except for potentially changing
|
||||
/// some type metadata of the interpreter or codegen backend.
|
||||
///
|
||||
/// This goal is achieved with mir_transform pass `Subtyper`, which runs right after
|
||||
/// borrowchecker, as we only care about subtyping that can affect trait selection and
|
||||
/// `TypeId`.
|
||||
Subtype(T),
|
||||
}
|
||||
|
||||
/// Alias for projections as they appear in places, where the base is a place
|
||||
|
|
@ -1513,6 +1501,18 @@ pub enum CastKind {
|
|||
/// MIR is well-formed if the input and output types have different sizes,
|
||||
/// but running a transmute between differently-sized types is UB.
|
||||
Transmute,
|
||||
|
||||
/// A `Subtype` cast is applied to any `StatementKind::Assign` where
|
||||
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
|
||||
/// explicit during optimizations and codegen.
|
||||
///
|
||||
/// This cast doesn't impact the runtime behavior of the program except for potentially changing
|
||||
/// some type metadata of the interpreter or codegen backend.
|
||||
///
|
||||
/// This goal is achieved with mir_transform pass `Subtyper`, which runs right after
|
||||
/// borrowchecker, as we only care about subtyping that can affect trait selection and
|
||||
/// `TypeId`.
|
||||
Subtype,
|
||||
}
|
||||
|
||||
/// Represents how a [`CastKind::PointerCoercion`] was constructed.
|
||||
|
|
|
|||
|
|
@ -1166,11 +1166,6 @@ macro_rules! visit_place_fns {
|
|||
self.visit_ty(&mut new_ty, TyContext::Location(location));
|
||||
if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
|
||||
}
|
||||
PlaceElem::Subtype(ty) => {
|
||||
let mut new_ty = ty;
|
||||
self.visit_ty(&mut new_ty, TyContext::Location(location));
|
||||
if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
|
||||
}
|
||||
PlaceElem::UnwrapUnsafeBinder(ty) => {
|
||||
let mut new_ty = ty;
|
||||
self.visit_ty(&mut new_ty, TyContext::Location(location));
|
||||
|
|
@ -1244,7 +1239,6 @@ macro_rules! visit_place_fns {
|
|||
) {
|
||||
match elem {
|
||||
ProjectionElem::OpaqueCast(ty)
|
||||
| ProjectionElem::Subtype(ty)
|
||||
| ProjectionElem::Field(_, ty)
|
||||
| ProjectionElem::UnwrapUnsafeBinder(ty) => {
|
||||
self.visit_ty(ty, TyContext::Location(location));
|
||||
|
|
|
|||
|
|
@ -1244,7 +1244,7 @@ rustc_queries! {
|
|||
|
||||
/// Borrow-checks the given typeck root, e.g. functions, const/static items,
|
||||
/// and its children, e.g. closures, inline consts.
|
||||
query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> {
|
||||
query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::DefinitionSiteHiddenTypes<'tcx>, ErrorGuaranteed> {
|
||||
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,15 @@ impl<'tcx> Const<'tcx> {
|
|||
debruijn: ty::DebruijnIndex,
|
||||
bound_const: ty::BoundConst,
|
||||
) -> Const<'tcx> {
|
||||
Const::new(tcx, ty::ConstKind::Bound(debruijn, bound_const))
|
||||
Const::new(tcx, ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Const<'tcx> {
|
||||
Const::new(
|
||||
tcx,
|
||||
ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, ty::BoundConst { var }),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -180,6 +188,10 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
|
|||
Const::new_bound(tcx, debruijn, ty::BoundConst { var })
|
||||
}
|
||||
|
||||
fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self {
|
||||
Const::new_canonical_bound(tcx, var)
|
||||
}
|
||||
|
||||
fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self {
|
||||
Const::new_placeholder(tcx, placeholder)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1110,6 +1110,15 @@ const NUM_PREINTERNED_FRESH_TYS: u32 = 20;
|
|||
const NUM_PREINTERNED_FRESH_INT_TYS: u32 = 3;
|
||||
const NUM_PREINTERNED_FRESH_FLOAT_TYS: u32 = 3;
|
||||
const NUM_PREINTERNED_ANON_BOUND_TYS_I: u32 = 3;
|
||||
|
||||
// From general profiling of the *max vars during canonicalization* of a value:
|
||||
// - about 90% of the time, there are no canonical vars
|
||||
// - about 9% of the time, there is only one canonical var
|
||||
// - there are rarely more than 3-5 canonical vars (with exceptions in particularly pathological cases)
|
||||
// This may not match the number of bound vars found in `for`s.
|
||||
// Given that this is all heap interned, it seems likely that interning fewer
|
||||
// vars here won't make an appreciable difference. Though, if we were to inline the data (in an array),
|
||||
// we may want to consider reducing the number for canonicalized vars down to 4 or so.
|
||||
const NUM_PREINTERNED_ANON_BOUND_TYS_V: u32 = 20;
|
||||
|
||||
// This number may seem high, but it is reached in all but the smallest crates.
|
||||
|
|
@ -1160,9 +1169,14 @@ pub struct CommonTypes<'tcx> {
|
|||
pub fresh_float_tys: Vec<Ty<'tcx>>,
|
||||
|
||||
/// Pre-interned values of the form:
|
||||
/// `Bound(DebruijnIndex(i), BoundTy { var: v, kind: BoundTyKind::Anon})`
|
||||
/// `Bound(BoundVarIndexKind::Bound(DebruijnIndex(i)), BoundTy { var: v, kind: BoundTyKind::Anon})`
|
||||
/// for small values of `i` and `v`.
|
||||
pub anon_bound_tys: Vec<Vec<Ty<'tcx>>>,
|
||||
|
||||
// Pre-interned values of the form:
|
||||
// `Bound(BoundVarIndexKind::Canonical, BoundTy { var: v, kind: BoundTyKind::Anon })`
|
||||
// for small values of `v`.
|
||||
pub anon_canonical_bound_tys: Vec<Ty<'tcx>>,
|
||||
}
|
||||
|
||||
pub struct CommonLifetimes<'tcx> {
|
||||
|
|
@ -1176,9 +1190,14 @@ pub struct CommonLifetimes<'tcx> {
|
|||
pub re_vars: Vec<Region<'tcx>>,
|
||||
|
||||
/// Pre-interned values of the form:
|
||||
/// `ReBound(DebruijnIndex(i), BoundRegion { var: v, kind: BoundRegionKind::Anon })`
|
||||
/// `ReBound(BoundVarIndexKind::Bound(DebruijnIndex(i)), BoundRegion { var: v, kind: BoundRegionKind::Anon })`
|
||||
/// for small values of `i` and `v`.
|
||||
pub anon_re_bounds: Vec<Vec<Region<'tcx>>>,
|
||||
|
||||
// Pre-interned values of the form:
|
||||
// `ReBound(BoundVarIndexKind::Canonical, BoundRegion { var: v, kind: BoundRegionKind::Anon })`
|
||||
// for small values of `v`.
|
||||
pub anon_re_canonical_bounds: Vec<Region<'tcx>>,
|
||||
}
|
||||
|
||||
pub struct CommonConsts<'tcx> {
|
||||
|
|
@ -1211,7 +1230,7 @@ impl<'tcx> CommonTypes<'tcx> {
|
|||
(0..NUM_PREINTERNED_ANON_BOUND_TYS_V)
|
||||
.map(|v| {
|
||||
mk(ty::Bound(
|
||||
ty::DebruijnIndex::from(i),
|
||||
ty::BoundVarIndexKind::Bound(ty::DebruijnIndex::from(i)),
|
||||
ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon },
|
||||
))
|
||||
})
|
||||
|
|
@ -1219,6 +1238,15 @@ impl<'tcx> CommonTypes<'tcx> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
let anon_canonical_bound_tys = (0..NUM_PREINTERNED_ANON_BOUND_TYS_V)
|
||||
.map(|v| {
|
||||
mk(ty::Bound(
|
||||
ty::BoundVarIndexKind::Canonical,
|
||||
ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon },
|
||||
))
|
||||
})
|
||||
.collect();
|
||||
|
||||
CommonTypes {
|
||||
unit: mk(Tuple(List::empty())),
|
||||
bool: mk(Bool),
|
||||
|
|
@ -1250,6 +1278,7 @@ impl<'tcx> CommonTypes<'tcx> {
|
|||
fresh_int_tys,
|
||||
fresh_float_tys,
|
||||
anon_bound_tys,
|
||||
anon_canonical_bound_tys,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1270,7 +1299,7 @@ impl<'tcx> CommonLifetimes<'tcx> {
|
|||
(0..NUM_PREINTERNED_ANON_RE_BOUNDS_V)
|
||||
.map(|v| {
|
||||
mk(ty::ReBound(
|
||||
ty::DebruijnIndex::from(i),
|
||||
ty::BoundVarIndexKind::Bound(ty::DebruijnIndex::from(i)),
|
||||
ty::BoundRegion {
|
||||
var: ty::BoundVar::from(v),
|
||||
kind: ty::BoundRegionKind::Anon,
|
||||
|
|
@ -1281,11 +1310,21 @@ impl<'tcx> CommonLifetimes<'tcx> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
let anon_re_canonical_bounds = (0..NUM_PREINTERNED_ANON_RE_BOUNDS_V)
|
||||
.map(|v| {
|
||||
mk(ty::ReBound(
|
||||
ty::BoundVarIndexKind::Canonical,
|
||||
ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BoundRegionKind::Anon },
|
||||
))
|
||||
})
|
||||
.collect();
|
||||
|
||||
CommonLifetimes {
|
||||
re_static: mk(ty::ReStatic),
|
||||
re_erased: mk(ty::ReErased),
|
||||
re_vars,
|
||||
anon_re_bounds,
|
||||
anon_re_canonical_bounds,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,9 @@ where
|
|||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *t.kind() {
|
||||
ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
|
||||
ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty)
|
||||
if debruijn == self.current_index =>
|
||||
{
|
||||
let ty = self.delegate.replace_ty(bound_ty);
|
||||
debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST));
|
||||
ty::shift_vars(self.tcx, ty, self.current_index.as_u32())
|
||||
|
|
@ -146,9 +148,11 @@ where
|
|||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match r.kind() {
|
||||
ty::ReBound(debruijn, br) if debruijn == self.current_index => {
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
|
||||
if debruijn == self.current_index =>
|
||||
{
|
||||
let region = self.delegate.replace_region(br);
|
||||
if let ty::ReBound(debruijn1, br) = region.kind() {
|
||||
if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn1), br) = region.kind() {
|
||||
// If the callback returns a bound region,
|
||||
// that region should always use the INNERMOST
|
||||
// debruijn index. Then we adjust it to the
|
||||
|
|
@ -165,7 +169,9 @@ where
|
|||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
|
||||
ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)
|
||||
if debruijn == self.current_index =>
|
||||
{
|
||||
let ct = self.delegate.replace_const(bound_const);
|
||||
debug_assert!(!ct.has_vars_bound_above(ty::INNERMOST));
|
||||
ty::shift_vars(self.tcx, ct, self.current_index.as_u32())
|
||||
|
|
|
|||
|
|
@ -2664,7 +2664,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
|
|||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
let name = &mut self.name;
|
||||
let region = match r.kind() {
|
||||
ty::ReBound(db, br) if db >= self.current_index => {
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(db), br) if db >= self.current_index => {
|
||||
*self.region_map.entry(br).or_insert_with(|| name(Some(db), self.current_index, br))
|
||||
}
|
||||
ty::RePlaceholder(ty::PlaceholderRegion {
|
||||
|
|
@ -2687,7 +2687,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
|
|||
}
|
||||
_ => return r,
|
||||
};
|
||||
if let ty::ReBound(debruijn1, br) = region.kind() {
|
||||
if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn1), br) = region.kind() {
|
||||
assert_eq!(debruijn1, ty::INNERMOST);
|
||||
ty::Region::new_bound(self.tcx, self.current_index, br)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ impl<'tcx> rustc_type_ir::Flags for Region<'tcx> {
|
|||
|
||||
fn outer_exclusive_binder(&self) -> ty::DebruijnIndex {
|
||||
match self.kind() {
|
||||
ty::ReBound(debruijn, _) => debruijn.shifted_in(1),
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) => debruijn.shifted_in(1),
|
||||
_ => ty::INNERMOST,
|
||||
}
|
||||
}
|
||||
|
|
@ -59,7 +59,20 @@ impl<'tcx> Region<'tcx> {
|
|||
{
|
||||
re
|
||||
} else {
|
||||
tcx.intern_region(ty::ReBound(debruijn, bound_region))
|
||||
tcx.intern_region(ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), bound_region))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Region<'tcx> {
|
||||
// Use a pre-interned one when possible.
|
||||
if let Some(re) = tcx.lifetimes.anon_re_canonical_bounds.get(var.as_usize()).copied() {
|
||||
re
|
||||
} else {
|
||||
tcx.intern_region(ty::ReBound(
|
||||
ty::BoundVarIndexKind::Canonical,
|
||||
ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon },
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +135,12 @@ impl<'tcx> Region<'tcx> {
|
|||
pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> {
|
||||
match kind {
|
||||
ty::ReEarlyParam(region) => Region::new_early_param(tcx, region),
|
||||
ty::ReBound(debruijn, region) => Region::new_bound(tcx, debruijn, region),
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), region) => {
|
||||
Region::new_bound(tcx, debruijn, region)
|
||||
}
|
||||
ty::ReBound(ty::BoundVarIndexKind::Canonical, region) => {
|
||||
Region::new_canonical_bound(tcx, region.var)
|
||||
}
|
||||
ty::ReLateParam(ty::LateParamRegion { scope, kind }) => {
|
||||
Region::new_late_param(tcx, scope, kind)
|
||||
}
|
||||
|
|
@ -148,6 +166,10 @@ impl<'tcx> rustc_type_ir::inherent::Region<TyCtxt<'tcx>> for Region<'tcx> {
|
|||
Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon })
|
||||
}
|
||||
|
||||
fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self {
|
||||
Region::new_canonical_bound(tcx, var)
|
||||
}
|
||||
|
||||
fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Self {
|
||||
Region::new_placeholder(tcx, placeholder)
|
||||
}
|
||||
|
|
@ -223,7 +245,7 @@ impl<'tcx> Region<'tcx> {
|
|||
#[inline]
|
||||
pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool {
|
||||
match self.kind() {
|
||||
ty::ReBound(debruijn, _) => debruijn >= index,
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) => debruijn >= index,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -254,7 +276,11 @@ impl<'tcx> Region<'tcx> {
|
|||
ty::ReStatic => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
}
|
||||
ty::ReBound(..) => {
|
||||
ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => {
|
||||
flags = flags | TypeFlags::HAS_RE_BOUND;
|
||||
flags = flags | TypeFlags::HAS_CANONICAL_BOUND;
|
||||
}
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(..), _) => {
|
||||
flags = flags | TypeFlags::HAS_RE_BOUND;
|
||||
}
|
||||
ty::ReErased => {
|
||||
|
|
|
|||
|
|
@ -487,7 +487,23 @@ impl<'tcx> Ty<'tcx> {
|
|||
{
|
||||
ty
|
||||
} else {
|
||||
Ty::new(tcx, Bound(index, bound_ty))
|
||||
Ty::new(tcx, Bound(ty::BoundVarIndexKind::Bound(index), bound_ty))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: BoundVar) -> Ty<'tcx> {
|
||||
// Use a pre-interned one when possible.
|
||||
if let Some(ty) = tcx.types.anon_canonical_bound_tys.get(var.as_usize()).copied() {
|
||||
ty
|
||||
} else {
|
||||
Ty::new(
|
||||
tcx,
|
||||
Bound(
|
||||
ty::BoundVarIndexKind::Canonical,
|
||||
ty::BoundTy { var, kind: ty::BoundTyKind::Anon },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -952,6 +968,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
|
|||
Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
|
||||
}
|
||||
|
||||
fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Self {
|
||||
Ty::new_canonical_bound(tcx, var)
|
||||
}
|
||||
|
||||
fn new_alias(
|
||||
interner: TyCtxt<'tcx>,
|
||||
kind: ty::AliasTyKind,
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ pub struct TypeckResults<'tcx> {
|
|||
/// We also store the type here, so that the compiler can use it as a hint
|
||||
/// for figuring out hidden types, even if they are only set in dead code
|
||||
/// (which doesn't show up in MIR).
|
||||
pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
|
||||
pub hidden_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
|
||||
|
||||
/// Tracks the minimum captures required for a closure;
|
||||
/// see `MinCaptureInformationMap` for more details.
|
||||
|
|
@ -250,7 +250,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||
coercion_casts: Default::default(),
|
||||
used_trait_imports: Default::default(),
|
||||
tainted_by_errors: None,
|
||||
concrete_opaque_types: Default::default(),
|
||||
hidden_types: Default::default(),
|
||||
closure_min_captures: Default::default(),
|
||||
closure_fake_reads: Default::default(),
|
||||
rvalue_scopes: Default::default(),
|
||||
|
|
@ -798,8 +798,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
|
|||
match arg.kind() {
|
||||
GenericArgKind::Type(ty) => match ty.kind() {
|
||||
ty::Bound(debruijn, b) => {
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(*debruijn, ty::INNERMOST);
|
||||
// We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters.
|
||||
assert_eq!(*debruijn, ty::BoundVarIndexKind::Canonical);
|
||||
cvar == b.var
|
||||
}
|
||||
_ => false,
|
||||
|
|
@ -807,8 +807,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
|
|||
|
||||
GenericArgKind::Lifetime(r) => match r.kind() {
|
||||
ty::ReBound(debruijn, b) => {
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
// We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::BoundVarIndexKind::Canonical);
|
||||
cvar == b.var
|
||||
}
|
||||
_ => false,
|
||||
|
|
@ -816,8 +816,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
|
|||
|
||||
GenericArgKind::Const(ct) => match ct.kind() {
|
||||
ty::ConstKind::Bound(debruijn, b) => {
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
// We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::BoundVarIndexKind::Canonical);
|
||||
cvar == b.var
|
||||
}
|
||||
_ => false,
|
||||
|
|
|
|||
|
|
@ -78,7 +78,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
|
||||
match r.kind() {
|
||||
ty::ReBound(debruijn, _) if debruijn < self.outer_index => {
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
|
||||
if debruijn < self.outer_index =>
|
||||
{
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -205,7 +207,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
|
|||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) {
|
||||
if let ty::ReBound(debruijn, br) = r.kind() {
|
||||
if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) = r.kind() {
|
||||
if debruijn == self.current_index {
|
||||
self.regions.insert(br.kind);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ fn convert_to_hir_projections_and_truncate_for_capture(
|
|||
}
|
||||
ProjectionElem::UnwrapUnsafeBinder(_) => HirProjectionKind::UnwrapUnsafeBinder,
|
||||
// These do not affect anything, they just make sure we know the right type.
|
||||
ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue,
|
||||
ProjectionElem::OpaqueCast(_) => continue,
|
||||
ProjectionElem::Index(..)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. } => {
|
||||
|
|
@ -802,7 +802,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
ProjectionElem::Field(..)
|
||||
| ProjectionElem::Downcast(..)
|
||||
| ProjectionElem::OpaqueCast(..)
|
||||
| ProjectionElem::Subtype(..)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::UnwrapUnsafeBinder(_) => (),
|
||||
|
|
|
|||
|
|
@ -227,11 +227,8 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
|||
ProjectionElem::UnwrapUnsafeBinder(_) => {}
|
||||
// `OpaqueCast`:Only transmutes the type, so no moves there.
|
||||
// `Downcast` :Only changes information about a `Place` without moving.
|
||||
// `Subtype` :Only transmutes the type, so moves.
|
||||
// So it's safe to skip these.
|
||||
ProjectionElem::OpaqueCast(_)
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Downcast(_, _) => (),
|
||||
ProjectionElem::OpaqueCast(_) | ProjectionElem::Downcast(_, _) => (),
|
||||
}
|
||||
let elem_ty = PlaceTy::from_ty(place_ty).projection_ty(tcx, elem).ty;
|
||||
if !(self.filter)(elem_ty) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use rustc_ast::InlineAsmOptions;
|
|||
use rustc_middle::mir::*;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self, TyCtxt, layout};
|
||||
use rustc_span::sym;
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
|
||||
/// A pass that runs which is targeted at ensuring that codegen guarantees about
|
||||
|
|
@ -33,6 +34,19 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
|
|||
return;
|
||||
}
|
||||
|
||||
// Represent whether this compilation target fundamentally doesn't
|
||||
// support unwinding at all at an ABI level. If this the target has no
|
||||
// support for unwinding then cleanup actions, for example, are all
|
||||
// unnecessary and can be considered unreachable.
|
||||
//
|
||||
// Currently this is only true for wasm targets on panic=abort when the
|
||||
// `exception-handling` target feature is disabled. In such a
|
||||
// configuration it's illegal to emit exception-related instructions so
|
||||
// it's not possible to unwind.
|
||||
let target_supports_unwinding = !(tcx.sess.target.is_like_wasm
|
||||
&& tcx.sess.panic_strategy() == PanicStrategy::Abort
|
||||
&& !tcx.asm_target_features(def_id).contains(&sym::exception_handling));
|
||||
|
||||
// Here we test for this function itself whether its ABI allows
|
||||
// unwinding or not.
|
||||
let body_ty = tcx.type_of(def_id).skip_binder();
|
||||
|
|
@ -54,12 +68,18 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
|
|||
let Some(terminator) = &mut block.terminator else { continue };
|
||||
let span = terminator.source_info.span;
|
||||
|
||||
// If we see an `UnwindResume` terminator inside a function that cannot unwind, we need
|
||||
// to replace it with `UnwindTerminate`.
|
||||
if let TerminatorKind::UnwindResume = &terminator.kind
|
||||
&& !body_can_unwind
|
||||
{
|
||||
terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi);
|
||||
// If we see an `UnwindResume` terminator inside a function then:
|
||||
//
|
||||
// * If the target doesn't support unwinding at all, then this is an
|
||||
// unreachable block.
|
||||
// * If the body cannot unwind, we need to replace it with
|
||||
// `UnwindTerminate`.
|
||||
if let TerminatorKind::UnwindResume = &terminator.kind {
|
||||
if !target_supports_unwinding {
|
||||
terminator.kind = TerminatorKind::Unreachable;
|
||||
} else if !body_can_unwind {
|
||||
terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi);
|
||||
}
|
||||
}
|
||||
|
||||
if block.is_cleanup {
|
||||
|
|
@ -93,8 +113,9 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
|
|||
_ => continue,
|
||||
};
|
||||
|
||||
if !call_can_unwind {
|
||||
// If this function call can't unwind, then there's no need for it
|
||||
if !call_can_unwind || !target_supports_unwinding {
|
||||
// If this function call can't unwind, or if the target doesn't
|
||||
// support unwinding at all, then there's no need for it
|
||||
// to have a landing pad. This means that we can remove any cleanup
|
||||
// registered for it (and turn it into `UnwindAction::Unreachable`).
|
||||
let cleanup = block.terminator_mut().unwind_mut().unwrap();
|
||||
|
|
|
|||
|
|
@ -40,8 +40,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
|
|||
.new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span);
|
||||
let new_place = Place::from(temp);
|
||||
self.patcher.add_assign(location, new_place, rvalue.clone());
|
||||
let subtyped = new_place.project_deeper(&[ProjectionElem::Subtype(place_ty)], self.tcx);
|
||||
*rvalue = Rvalue::Use(Operand::Move(subtyped));
|
||||
*rvalue = Rvalue::Cast(CastKind::Subtype, Operand::Move(new_place), place_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
FlatSet::Top => FlatSet::Top,
|
||||
}
|
||||
}
|
||||
Rvalue::Cast(CastKind::Transmute, operand, _) => {
|
||||
Rvalue::Cast(CastKind::Transmute | CastKind::Subtype, operand, _) => {
|
||||
match self.eval_operand(operand, state) {
|
||||
FlatSet::Elem(op) => self.wrap_immediate(*op),
|
||||
FlatSet::Bottom => FlatSet::Bottom,
|
||||
|
|
|
|||
|
|
@ -656,7 +656,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
let res = self.ecx.float_to_float_or_int(&value, ty).discard_err()?;
|
||||
res.into()
|
||||
}
|
||||
CastKind::Transmute => {
|
||||
CastKind::Transmute | CastKind::Subtype => {
|
||||
let value = self.evaluated[value].as_ref()?;
|
||||
// `offset` for immediates generally only supports projections that match the
|
||||
// type of the immediate. However, as a HACK, we exploit that it can also do
|
||||
|
|
@ -788,7 +788,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
ProjectionElem::Subslice { from, to, from_end }
|
||||
}
|
||||
ProjectionElem::OpaqueCast(_) => ProjectionElem::OpaqueCast(()),
|
||||
ProjectionElem::Subtype(_) => ProjectionElem::Subtype(()),
|
||||
ProjectionElem::UnwrapUnsafeBinder(_) => ProjectionElem::UnwrapUnsafeBinder(()),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -637,7 +637,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?;
|
||||
res.into()
|
||||
}
|
||||
CastKind::Transmute => {
|
||||
CastKind::Transmute | CastKind::Subtype => {
|
||||
let value = self.eval_operand(value)?;
|
||||
let to = self.ecx.layout_of(to).ok()?;
|
||||
// `offset` for immediates only supports scalar/scalar-pair ABIs,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ use tracing::debug;
|
|||
/// once with `apply`. This is useful for MIR transformation passes.
|
||||
pub(crate) struct MirPatch<'tcx> {
|
||||
term_patch_map: FxHashMap<BasicBlock, TerminatorKind<'tcx>>,
|
||||
/// Set of statements that should be replaced by `Nop`.
|
||||
nop_statements: Vec<Location>,
|
||||
new_blocks: Vec<BasicBlockData<'tcx>>,
|
||||
new_statements: Vec<(Location, StatementKind<'tcx>)>,
|
||||
new_locals: Vec<LocalDecl<'tcx>>,
|
||||
|
|
@ -33,6 +35,7 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
pub(crate) fn new(body: &Body<'tcx>) -> Self {
|
||||
let mut result = MirPatch {
|
||||
term_patch_map: Default::default(),
|
||||
nop_statements: vec![],
|
||||
new_blocks: vec![],
|
||||
new_statements: vec![],
|
||||
new_locals: vec![],
|
||||
|
|
@ -212,6 +215,15 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
self.term_patch_map.insert(block, new);
|
||||
}
|
||||
|
||||
/// Mark given statement to be replaced by a `Nop`.
|
||||
///
|
||||
/// This method only works on statements from the initial body, and cannot be used to remove
|
||||
/// statements from `add_statement` or `add_assign`.
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn nop_statement(&mut self, loc: Location) {
|
||||
self.nop_statements.push(loc);
|
||||
}
|
||||
|
||||
/// Queues the insertion of a statement at a given location. The statement
|
||||
/// currently at that location, and all statements that follow, are shifted
|
||||
/// down. If multiple statements are queued for addition at the same
|
||||
|
|
@ -257,11 +269,8 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
bbs.extend(self.new_blocks);
|
||||
body.local_decls.extend(self.new_locals);
|
||||
|
||||
// The order in which we patch terminators does not change the result.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
for (src, patch) in self.term_patch_map {
|
||||
debug!("MirPatch: patching block {:?}", src);
|
||||
bbs[src].terminator_mut().kind = patch;
|
||||
for loc in self.nop_statements {
|
||||
bbs[loc.block].statements[loc.statement_index].make_nop();
|
||||
}
|
||||
|
||||
let mut new_statements = self.new_statements;
|
||||
|
|
@ -285,6 +294,17 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
.insert(loc.statement_index, Statement::new(source_info, stmt));
|
||||
delta += 1;
|
||||
}
|
||||
|
||||
// The order in which we patch terminators does not change the result.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
for (src, patch) in self.term_patch_map {
|
||||
debug!("MirPatch: patching block {:?}", src);
|
||||
let bb = &mut bbs[src];
|
||||
if let TerminatorKind::Unreachable = patch {
|
||||
bb.statements.clear();
|
||||
}
|
||||
bb.terminator_mut().kind = patch;
|
||||
}
|
||||
}
|
||||
|
||||
fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo {
|
||||
|
|
|
|||
|
|
@ -292,7 +292,6 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
match elem {
|
||||
// Recurse directly.
|
||||
ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::UnwrapUnsafeBinder(_) => {}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::trace;
|
||||
|
||||
use crate::patch::MirPatch;
|
||||
|
||||
pub(super) enum SimplifyConstCondition {
|
||||
AfterConstProp,
|
||||
Final,
|
||||
|
|
@ -19,8 +21,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
|
|||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
trace!("Running SimplifyConstCondition on {:?}", body.source);
|
||||
let typing_env = body.typing_env(tcx);
|
||||
'blocks: for block in body.basic_blocks_mut() {
|
||||
for stmt in block.statements.iter_mut() {
|
||||
let mut patch = MirPatch::new(body);
|
||||
|
||||
'blocks: for (bb, block) in body.basic_blocks.iter_enumerated() {
|
||||
for (statement_index, stmt) in block.statements.iter().enumerate() {
|
||||
// Simplify `assume` of a known value: either a NOP or unreachable.
|
||||
if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind
|
||||
&& let NonDivergingIntrinsic::Assume(discr) = intrinsic
|
||||
|
|
@ -28,17 +32,16 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
|
|||
&& let Some(constant) = c.const_.try_eval_bool(tcx, typing_env)
|
||||
{
|
||||
if constant {
|
||||
stmt.make_nop();
|
||||
patch.nop_statement(Location { block: bb, statement_index });
|
||||
} else {
|
||||
block.statements.clear();
|
||||
block.terminator_mut().kind = TerminatorKind::Unreachable;
|
||||
patch.patch_terminator(bb, TerminatorKind::Unreachable);
|
||||
continue 'blocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let terminator = block.terminator_mut();
|
||||
terminator.kind = match terminator.kind {
|
||||
let terminator = block.terminator();
|
||||
let terminator = match terminator.kind {
|
||||
TerminatorKind::SwitchInt {
|
||||
discr: Operand::Constant(ref c), ref targets, ..
|
||||
} => {
|
||||
|
|
@ -58,7 +61,9 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
|
|||
},
|
||||
_ => continue,
|
||||
};
|
||||
patch.patch_terminator(bb, terminator);
|
||||
}
|
||||
patch.apply(body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -814,22 +814,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ProjectionElem::Subtype(ty) => {
|
||||
if !util::sub_types(
|
||||
self.tcx,
|
||||
self.typing_env,
|
||||
ty,
|
||||
place_ref.ty(&self.body.local_decls, self.tcx).ty,
|
||||
) {
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"Failed subtyping {ty} and {}",
|
||||
place_ref.ty(&self.body.local_decls, self.tcx).ty
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
ProjectionElem::UnwrapUnsafeBinder(unwrapped_ty) => {
|
||||
let binder_ty = place_ref.ty(&self.body.local_decls, self.tcx);
|
||||
let ty::UnsafeBinder(binder_ty) = *binder_ty.ty.kind() else {
|
||||
|
|
@ -1331,6 +1315,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
CastKind::Subtype => {
|
||||
if !util::sub_types(self.tcx, self.typing_env, op_ty, *target_type) {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Failed subtyping {op_ty} and {target_type}"),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Rvalue::NullaryOp(NullOp::OffsetOf(indices), container) => {
|
||||
|
|
|
|||
|
|
@ -74,12 +74,10 @@ pub(super) struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner
|
|||
/// we set the `sub_root` of the second variable to the position of the first.
|
||||
/// Otherwise the `sub_root` of each type variable is just its own position.
|
||||
sub_root_lookup_table: HashMap<ty::TyVid, usize>,
|
||||
binder_index: ty::DebruijnIndex,
|
||||
|
||||
/// We only use the debruijn index during lookup. We don't need to
|
||||
/// track the `variables` as each generic arg only results in a single
|
||||
/// bound variable regardless of how many times it is encountered.
|
||||
cache: HashMap<(ty::DebruijnIndex, I::Ty), I::Ty>,
|
||||
/// We can simply cache based on the ty itself, because we use
|
||||
/// `ty::BoundVarIndexKind::Canonical`.
|
||||
cache: HashMap<I::Ty, I::Ty>,
|
||||
}
|
||||
|
||||
impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
||||
|
|
@ -97,7 +95,6 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
variable_lookup_table: Default::default(),
|
||||
sub_root_lookup_table: Default::default(),
|
||||
var_kinds: Vec::new(),
|
||||
binder_index: ty::INNERMOST,
|
||||
|
||||
cache: Default::default(),
|
||||
};
|
||||
|
|
@ -141,12 +138,10 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
variable_lookup_table: Default::default(),
|
||||
sub_root_lookup_table: Default::default(),
|
||||
var_kinds: Vec::new(),
|
||||
binder_index: ty::INNERMOST,
|
||||
|
||||
cache: Default::default(),
|
||||
};
|
||||
let param_env = param_env.fold_with(&mut env_canonicalizer);
|
||||
debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST);
|
||||
debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
|
||||
CanonicalParamEnvCacheEntry {
|
||||
param_env,
|
||||
|
|
@ -175,12 +170,10 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
variable_lookup_table: Default::default(),
|
||||
sub_root_lookup_table: Default::default(),
|
||||
var_kinds: Vec::new(),
|
||||
binder_index: ty::INNERMOST,
|
||||
|
||||
cache: Default::default(),
|
||||
};
|
||||
let param_env = param_env.fold_with(&mut env_canonicalizer);
|
||||
debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST);
|
||||
debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
|
||||
(param_env, env_canonicalizer.variable_lookup_table, env_canonicalizer.var_kinds)
|
||||
}
|
||||
|
|
@ -212,7 +205,6 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
variable_lookup_table,
|
||||
sub_root_lookup_table: Default::default(),
|
||||
var_kinds,
|
||||
binder_index: ty::INNERMOST,
|
||||
|
||||
// We do not reuse the cache as it may contain entries whose canonicalized
|
||||
// value contains `'static`. While we could alternatively handle this by
|
||||
|
|
@ -409,7 +401,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
|
||||
let var = self.get_or_insert_bound_var(t, kind);
|
||||
|
||||
Ty::new_anon_bound(self.cx(), self.binder_index, var)
|
||||
Ty::new_canonical_bound(self.cx(), var)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -418,16 +410,6 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
|
|||
self.delegate.cx()
|
||||
}
|
||||
|
||||
fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
|
||||
where
|
||||
T: TypeFoldable<I>,
|
||||
{
|
||||
self.binder_index.shift_in(1);
|
||||
let t = t.super_fold_with(self);
|
||||
self.binder_index.shift_out(1);
|
||||
t
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: I::Region) -> I::Region {
|
||||
let kind = match r.kind() {
|
||||
ty::ReBound(..) => return r,
|
||||
|
|
@ -491,15 +473,15 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
|
|||
|
||||
let var = self.get_or_insert_bound_var(r, kind);
|
||||
|
||||
Region::new_anon_bound(self.cx(), self.binder_index, var)
|
||||
Region::new_canonical_bound(self.cx(), var)
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
|
||||
if let Some(&ty) = self.cache.get(&(self.binder_index, t)) {
|
||||
if let Some(&ty) = self.cache.get(&t) {
|
||||
ty
|
||||
} else {
|
||||
let res = self.inner_fold_ty(t);
|
||||
let old = self.cache.insert((self.binder_index, t), res);
|
||||
let old = self.cache.insert(t, res);
|
||||
assert_eq!(old, None);
|
||||
res
|
||||
}
|
||||
|
|
@ -552,7 +534,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
|
|||
|
||||
let var = self.get_or_insert_bound_var(c, kind);
|
||||
|
||||
Const::new_anon_bound(self.cx(), self.binder_index, var)
|
||||
Const::new_canonical_bound(self.cx(), var)
|
||||
}
|
||||
|
||||
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
|
||||
|
|
|
|||
|
|
@ -165,25 +165,25 @@ where
|
|||
// and only use it for placeholders. We need to handle the
|
||||
// `sub_root` of type inference variables which would make this
|
||||
// more involved. They are also a lot rarer than region variables.
|
||||
if let ty::Bound(debruijn, b) = t.kind()
|
||||
if let ty::Bound(index_kind, b) = t.kind()
|
||||
&& !matches!(
|
||||
response.variables.get(b.var().as_usize()).unwrap(),
|
||||
CanonicalVarKind::Ty { .. }
|
||||
)
|
||||
{
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
|
||||
opt_values[b.var()] = Some(*original_value);
|
||||
}
|
||||
}
|
||||
ty::GenericArgKind::Lifetime(r) => {
|
||||
if let ty::ReBound(debruijn, br) = r.kind() {
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
if let ty::ReBound(index_kind, br) = r.kind() {
|
||||
assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
|
||||
opt_values[br.var()] = Some(*original_value);
|
||||
}
|
||||
}
|
||||
ty::GenericArgKind::Const(c) => {
|
||||
if let ty::ConstKind::Bound(debruijn, bv) = c.kind() {
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
if let ty::ConstKind::Bound(index_kind, bv) = c.kind() {
|
||||
assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
|
||||
opt_values[bv.var()] = Some(*original_value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ where
|
|||
|
||||
fn fold_region(&mut self, r: I::Region) -> I::Region {
|
||||
match r.kind() {
|
||||
ty::ReBound(debruijn, _)
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
|
||||
if debruijn.as_usize()
|
||||
>= self.current_index.as_usize() + self.universe_indices.len() =>
|
||||
{
|
||||
|
|
@ -99,7 +99,9 @@ where
|
|||
self.universe_indices
|
||||
);
|
||||
}
|
||||
ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
|
||||
ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
|
||||
if debruijn >= self.current_index =>
|
||||
{
|
||||
let universe = self.universe_for(debruijn);
|
||||
let p = PlaceholderLike::new(universe, br);
|
||||
self.mapped_regions.insert(p, br);
|
||||
|
|
@ -111,7 +113,7 @@ where
|
|||
|
||||
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
|
||||
match t.kind() {
|
||||
ty::Bound(debruijn, _)
|
||||
ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
|
||||
if debruijn.as_usize() + 1
|
||||
> self.current_index.as_usize() + self.universe_indices.len() =>
|
||||
{
|
||||
|
|
@ -120,7 +122,9 @@ where
|
|||
self.universe_indices
|
||||
);
|
||||
}
|
||||
ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
|
||||
ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty)
|
||||
if debruijn >= self.current_index =>
|
||||
{
|
||||
let universe = self.universe_for(debruijn);
|
||||
let p = PlaceholderLike::new(universe, bound_ty);
|
||||
self.mapped_types.insert(p, bound_ty);
|
||||
|
|
@ -133,7 +137,7 @@ where
|
|||
|
||||
fn fold_const(&mut self, ct: I::Const) -> I::Const {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Bound(debruijn, _)
|
||||
ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
|
||||
if debruijn.as_usize() + 1
|
||||
> self.current_index.as_usize() + self.universe_indices.len() =>
|
||||
{
|
||||
|
|
@ -142,7 +146,9 @@ where
|
|||
self.universe_indices
|
||||
);
|
||||
}
|
||||
ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
|
||||
ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)
|
||||
if debruijn >= self.current_index =>
|
||||
{
|
||||
let universe = self.universe_for(debruijn);
|
||||
let p = PlaceholderLike::new(universe, bound_const);
|
||||
self.mapped_consts.insert(p, bound_const);
|
||||
|
|
|
|||
|
|
@ -473,7 +473,10 @@ where
|
|||
// fails to reach a fixpoint but ends up getting an error after
|
||||
// running for some additional step.
|
||||
//
|
||||
// cc trait-system-refactor-initiative#105
|
||||
// FIXME(@lcnr): While I believe an error here to be possible, we
|
||||
// currently don't have any test which actually triggers it. @lqd
|
||||
// created a minimization for an ICE in typenum, but that one no
|
||||
// longer fails here. cc trait-system-refactor-initiative#105.
|
||||
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
|
||||
let certainty = Certainty::Maybe { cause, opaque_types_jank: OpaqueTypesJank::AllGood };
|
||||
self.probe_trait_candidate(source)
|
||||
|
|
|
|||
|
|
@ -664,7 +664,7 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>(
|
|||
pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
|
||||
cx: I,
|
||||
self_ty: I::Ty,
|
||||
) -> Result<(ty::Binder<I, (I::FnInputTys, I::Ty)>, I::FunctionId, I::GenericArgs), NoSolution> {
|
||||
) -> Result<(ty::Binder<I, (I::Ty, I::Ty)>, I::FunctionId, I::GenericArgs), NoSolution> {
|
||||
match self_ty.kind() {
|
||||
ty::FnDef(def_id, args) => {
|
||||
let sig = cx.fn_sig(def_id);
|
||||
|
|
@ -673,7 +673,8 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
|
|||
&& cx.fn_is_const(def_id)
|
||||
{
|
||||
Ok((
|
||||
sig.instantiate(cx, args).map_bound(|sig| (sig.inputs(), sig.output())),
|
||||
sig.instantiate(cx, args)
|
||||
.map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())),
|
||||
def_id,
|
||||
args,
|
||||
))
|
||||
|
|
|
|||
|
|
@ -234,12 +234,12 @@ where
|
|||
let self_ty = goal.predicate.self_ty();
|
||||
let (inputs_and_output, def_id, args) =
|
||||
structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?;
|
||||
let (inputs, output) = ecx.instantiate_binder_with_infer(inputs_and_output);
|
||||
|
||||
// A built-in `Fn` impl only holds if the output is sized.
|
||||
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||
let output_is_sized_pred = inputs_and_output.map_bound(|(_, output)| {
|
||||
ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output])
|
||||
});
|
||||
let output_is_sized_pred =
|
||||
ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]);
|
||||
let requirements = cx
|
||||
.const_conditions(def_id.into())
|
||||
.iter_instantiated(cx, args)
|
||||
|
|
@ -251,15 +251,12 @@ where
|
|||
})
|
||||
.chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]);
|
||||
|
||||
let pred = inputs_and_output
|
||||
.map_bound(|(inputs, _)| {
|
||||
ty::TraitRef::new(
|
||||
cx,
|
||||
goal.predicate.def_id(),
|
||||
[goal.predicate.self_ty(), Ty::new_tup(cx, inputs.as_slice())],
|
||||
)
|
||||
})
|
||||
.to_host_effect_clause(cx, goal.predicate.constness);
|
||||
let pred = ty::Binder::dummy(ty::TraitRef::new(
|
||||
cx,
|
||||
goal.predicate.def_id(),
|
||||
[goal.predicate.self_ty(), inputs],
|
||||
))
|
||||
.to_host_effect_clause(cx, goal.predicate.constness);
|
||||
|
||||
Self::probe_and_consider_implied_clause(
|
||||
ecx,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue