Merge pull request #4615 from rust-lang/rustup-2025-10-03

Automatic Rustup
This commit is contained in:
Oli Scherer 2025-10-03 06:26:54 +00:00 committed by GitHub
commit 179da5da69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
503 changed files with 9957 additions and 4879 deletions

View file

@ -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.

View file

@ -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> {

View file

@ -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)
}
(

View file

@ -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")
}
}

View file

@ -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,
},

View file

@ -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);
}
_ => {}

View file

@ -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),
},
};

View file

@ -192,7 +192,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
[
..,
ProjectionElem::Index(_)
| ProjectionElem::Subtype(_)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }

View file

@ -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(_) => {

View file

@ -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(..),

View file

@ -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 => {

View file

@ -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.
///

View file

@ -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,

View file

@ -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,
);
}

View file

@ -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")
}
}
}
}

View file

@ -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) => {

View file

@ -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,

View file

@ -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

View file

@ -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)
}

View file

@ -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> {

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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) };
}
}

View file

@ -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()
}

View file

@ -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

View file

@ -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;

View 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)
}

View file

@ -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::*;

View file

@ -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);
}
}

View file

@ -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 }
}
}

View file

@ -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;

View file

@ -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,
}
}

View file

@ -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))
}

View file

@ -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)
}
};

View file

@ -293,7 +293,6 @@ where
ProjectionElem::Index(index) if in_local(index) => return true,
ProjectionElem::Deref
| ProjectionElem::Subtype(_)
| ProjectionElem::Field(_, _)
| ProjectionElem::OpaqueCast(_)
| ProjectionElem::ConstantIndex { .. }

View file

@ -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...

View file

@ -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(),

View file

@ -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, ...)
```

View file

@ -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

View file

@ -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

View file

@ -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));

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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.

View file

@ -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")
}

View file

@ -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,

View file

@ -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

View file

@ -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,
);
}

View file

@ -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();

View file

@ -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={:?} \

View file

@ -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);
}

View file

@ -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))?;

View file

@ -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,

View file

@ -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,

View file

@ -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`)",
);
}
}

View file

@ -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()

View file

@ -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();
}

View file

@ -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);

View file

@ -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) });
}
}

View file

@ -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)
}
}

View file

@ -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
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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);

View file

@ -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)

View file

@ -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.

View file

@ -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

View file

@ -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>,

View file

@ -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})")?;
}

View file

@ -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.
///

View file

@ -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,
_,
_,
)

View file

@ -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.

View file

@ -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));

View file

@ -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) }
}

View file

@ -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)
}

View file

@ -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,
}
}
}

View file

@ -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())

View file

@ -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 {

View file

@ -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 => {

View file

@ -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,

View file

@ -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,

View file

@ -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);
}

View file

@ -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(_) => (),

View file

@ -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) {

View file

@ -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();

View file

@ -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);
}
}
}

View file

@ -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,

View file

@ -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(()),
};

View file

@ -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,

View file

@ -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 {

View file

@ -292,7 +292,6 @@ impl<'tcx> Validator<'_, 'tcx> {
match elem {
// Recurse directly.
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subtype(_)
| ProjectionElem::Subslice { .. }
| ProjectionElem::UnwrapUnsafeBinder(_) => {}

View file

@ -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 {

View file

@ -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) => {

View file

@ -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 {

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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)

View file

@ -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,
))

View file

@ -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