Merge ref 'cf1817bc6ecd' from rust-lang/rust

Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: rust-lang/rust@cf1817bc6e
Filtered ref: rust-lang/rustc-dev-guide@df639463eb
Upstream diff: https://github.com/rust-lang/rust/compare/84c11900724736a2b9afac4822031d78a9ed8e86...cf1817bc6ecd2d14ca492247c804bad31948dd56

This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
The rustc-josh-sync Cronjob Bot
2026-04-22 10:00:56 +00:00
240 changed files with 5532 additions and 4457 deletions
+5 -5
View File
@@ -258,11 +258,11 @@ Greg V <greg@unrelenting.technology>
Gregor Peach <gregorpeach@gmail.com>
Grzegorz Bartoszek <grzegorz.bartoszek@thaumatec.com>
Guanqun Lu <guanqun.lu@gmail.com>
Guillaume Gomez <guillaume1.gomez@gmail.com>
Guillaume Gomez <guillaume1.gomez@gmail.com> ggomez <ggomez@ggo.ifr.lan>
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <ggomez@ggo.ifr.lan>
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <guillaume.gomez@huawei.com>
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <contact@guillaume-gomez.fr>
Guillaume Gomez <contact@guillaume-gomez.fr>
Guillaume Gomez <contact@guillaume-gomez.fr> Guillaume Gomez <guillaume1.gomez@gmail.com>
Guillaume Gomez <contact@guillaume-gomez.fr> ggomez <ggomez@ggo.ifr.lan>
Guillaume Gomez <contact@guillaume-gomez.fr> Guillaume Gomez <ggomez@ggo.ifr.lan>
Guillaume Gomez <contact@guillaume-gomez.fr> Guillaume Gomez <guillaume.gomez@huawei.com>
gnzlbg <gonzalobg88@gmail.com> <gnzlbg@users.noreply.github.com>
hamidreza kalbasi <hamidrezakalbasi@protonmail.com>
Hanna Kruppe <hanna.kruppe@gmail.com> <robin.kruppe@gmail.com>
+15 -2
View File
@@ -1,13 +1,16 @@
use std::mem;
use std::sync::Arc;
use rustc_abi::ExternAbi;
use rustc_ast::visit::AssocCtxt;
use rustc_ast::*;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::steal::Steal;
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
use rustc_hir::attrs::{AttributeKind, EiiImplResolution};
use rustc_hir::def::{DefKind, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId, LocalDefIdMap};
use rustc_hir::definitions::PerParentDisambiguatorState;
use rustc_hir::{
self as hir, HirId, ImplItemImplKind, LifetimeSource, PredicateOrigin, Target, find_attr,
};
@@ -48,11 +51,21 @@ fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir
}
}
/// Default disambiguators are used during default lowering, when we lower
/// AST owners in a loop we can use the whole map, in contrast delayed lowering
/// lowers each AST owner separately, so we use readonly disambiguators map
/// with `Steal`s to get disambiguators.
pub(super) enum Disambiguators {
Default(LocalDefIdMap<PerParentDisambiguatorState>),
Delayed(Arc<LocalDefIdMap<Steal<PerParentDisambiguatorState>>>),
}
pub(super) struct ItemLowerer<'a, 'hir, R> {
pub(super) tcx: TyCtxt<'hir>,
pub(super) resolver: &'a mut R,
pub(super) ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
pub(super) owners: Owners<'a, 'hir>,
pub(super) disambiguators: &'a mut Disambiguators,
}
/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
@@ -80,7 +93,7 @@ fn with_lctx(
owner: NodeId,
f: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::OwnerNode<'hir>,
) {
let mut lctx = LoweringContext::new(self.tcx, self.resolver);
let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.disambiguators);
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
for (def_id, info) in lctx.children {
+26 -19
View File
@@ -70,7 +70,7 @@
use tracing::{debug, instrument, trace};
use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
use crate::item::Owners;
use crate::item::{Disambiguators, Owners};
macro_rules! arena_vec {
($this:expr; $($x:expr),*) => (
@@ -94,7 +94,8 @@ macro_rules! arena_vec {
struct LoweringContext<'a, 'hir, R> {
tcx: TyCtxt<'hir>,
resolver: &'a mut R,
disambiguator: PerParentDisambiguatorState,
disambiguators: &'a mut Disambiguators,
current_disambiguator: PerParentDisambiguatorState,
/// Used to allocate HIR nodes.
arena: &'hir hir::Arena<'hir>,
@@ -154,12 +155,13 @@ struct LoweringContext<'a, 'hir, R> {
}
impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R) -> Self {
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R, disambiguators: &'a mut Disambiguators) -> Self {
let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
Self {
tcx,
resolver,
disambiguator: Default::default(),
disambiguators,
current_disambiguator: Default::default(),
arena: tcx.hir_arena,
// HirId handling.
@@ -302,10 +304,6 @@ fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate
fn next_node_id(&mut self) -> NodeId {
next_node_id(&mut self.next_node_id)
}
fn steal_or_create_disambiguator(&self, parent: LocalDefId) -> PerParentDisambiguatorState {
self.base.steal_or_create_disambiguator(parent)
}
}
fn next_node_id(current_id: &mut NodeId) -> NodeId {
@@ -408,10 +406,6 @@ fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate
fn next_node_id(&mut self) -> NodeId {
next_node_id(&mut self.next_node_id)
}
fn steal_or_create_disambiguator(&self, parent: LocalDefId) -> PerParentDisambiguatorState {
self.per_parent_disambiguators.get(&parent).map(|s| s.steal()).unwrap_or_default()
}
}
/// How relaxed bounds `?Trait` should be treated.
@@ -632,11 +626,13 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
tcx.definitions_untracked().def_index_count(),
);
let mut disambiguators = Disambiguators::Default(resolver.disambiguators.steal());
let mut lowerer = item::ItemLowerer {
tcx,
resolver: &mut resolver,
ast_index: &ast_index,
owners: Owners::IndexVec(&mut owners),
disambiguators: &mut disambiguators,
};
let mut delayed_ids: FxIndexSet<LocalDefId> = Default::default();
@@ -655,7 +651,11 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
let opt_hir_hash =
if tcx.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
let delayed_resolver = Steal::new((resolver, krate));
let Disambiguators::Default(disambiguators) = disambiguators else { unreachable!() };
let delayed_disambigs =
Arc::new(disambiguators.into_items().map(|(id, d)| (id, Steal::new(d))).collect());
let delayed_resolver = Steal::new((resolver, krate, delayed_disambigs));
mid_hir::Crate::new(owners, delayed_ids, delayed_resolver, opt_hir_hash)
}
@@ -663,7 +663,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let krate = tcx.hir_crate(());
let (resolver, krate) = &*krate.delayed_resolver.borrow();
let (resolver, krate, delayed_disambigs) = &*krate.delayed_resolver.borrow();
// FIXME!!!(fn_delegation): make ast index lifetime same as resolver,
// as it is too bad to reindex whole crate on each delegation lowering.
@@ -677,12 +677,12 @@ pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
};
let mut map = Default::default();
let mut lowerer = item::ItemLowerer {
tcx,
resolver: &mut resolver,
ast_index: &ast_index,
owners: Owners::Map(&mut map),
disambiguators: &mut Disambiguators::Delayed(Arc::clone(delayed_disambigs)),
};
lowerer.lower_node(def_id);
@@ -740,7 +740,7 @@ fn create_def(
let def_id = self
.tcx
.at(span)
.create_def(parent, name, def_kind, None, &mut self.disambiguator)
.create_def(parent, name, def_kind, None, &mut self.current_disambiguator)
.def_id();
debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
@@ -780,9 +780,16 @@ fn with_hir_id_owner(
f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>,
) {
let owner_id = self.owner_id(owner);
let def_id = owner_id.def_id;
let new_disambig = self.resolver.steal_or_create_disambiguator(owner_id.def_id);
let disambiguator = std::mem::replace(&mut self.disambiguator, new_disambig);
let new_disambig = match &mut self.disambiguators {
Disambiguators::Default(map) => map.remove(&def_id),
Disambiguators::Delayed(map) => map.get(&def_id).map(Steal::steal),
};
let new_disambig = new_disambig.unwrap_or_else(|| PerParentDisambiguatorState::new(def_id));
let disambiguator = std::mem::replace(&mut self.current_disambiguator, new_disambig);
let current_attrs = std::mem::take(&mut self.attrs);
let current_bodies = std::mem::take(&mut self.bodies);
let current_define_opaque = std::mem::take(&mut self.define_opaque);
@@ -817,7 +824,7 @@ fn with_hir_id_owner(
assert!(self.impl_trait_bounds.is_empty());
let info = self.make_owner_info(item);
self.disambiguator = disambiguator;
self.current_disambiguator = disambiguator;
self.attrs = current_attrs;
self.bodies = current_bodies;
self.define_opaque = current_define_opaque;
+16 -16
View File
@@ -208,7 +208,7 @@ fn with_impl_trait(&mut self, outer_span: Option<Span>, f: impl FnOnce(&mut Self
}
// Mirrors `visit::walk_ty`, but tracks relevant state.
fn walk_ty(&mut self, t: &'a Ty) {
fn walk_ty(&mut self, t: &Ty) {
match &t.kind {
TyKind::ImplTrait(_, bounds) => {
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t));
@@ -731,7 +731,7 @@ fn check_foreign_item_ascii_only(&self, ident: Ident) {
/// C-variadics must be:
/// - Non-const
/// - Either foreign, or free and `unsafe extern "C"` semantically
fn check_c_variadic_type(&self, fk: FnKind<'a>, attrs: &'a AttrVec) {
fn check_c_variadic_type(&self, fk: FnKind<'_>, attrs: &AttrVec) {
// `...` is already rejected when it is not the final parameter.
let variadic_param = match fk.decl().inputs.last() {
Some(param) if matches!(param.ty.kind, TyKind::CVarArgs) => param,
@@ -806,7 +806,7 @@ fn check_c_variadic_type(&self, fk: FnKind<'a>, attrs: &'a AttrVec) {
fn check_c_variadic_abi(
&self,
abi: ExternAbi,
attrs: &'a AttrVec,
attrs: &AttrVec,
dotdotdot_span: Span,
sig: &FnSig,
) {
@@ -976,7 +976,7 @@ fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
});
}
fn visit_ty_common(&mut self, ty: &'a Ty) {
fn visit_ty_common(&mut self, ty: &Ty) {
match &ty.kind {
TyKind::FnPtr(bfty) => {
self.check_fn_ptr_safety(bfty.decl_span, bfty.safety);
@@ -1039,13 +1039,13 @@ fn handle_missing_abi(&mut self, span: Span, id: NodeId) {
}
// Used within `visit_item` for item kinds where we don't call `visit::walk_item`.
fn visit_attrs_vis(&mut self, attrs: &'a AttrVec, vis: &'a Visibility) {
fn visit_attrs_vis(&mut self, attrs: &AttrVec, vis: &Visibility) {
walk_list!(self, visit_attribute, attrs);
self.visit_vis(vis);
}
// Used within `visit_item` for item kinds where we don't call `visit::walk_item`.
fn visit_attrs_vis_ident(&mut self, attrs: &'a AttrVec, vis: &'a Visibility, ident: &'a Ident) {
fn visit_attrs_vis_ident(&mut self, attrs: &AttrVec, vis: &Visibility, ident: &Ident) {
walk_list!(self, visit_attribute, attrs);
self.visit_vis(vis);
self.visit_ident(ident);
@@ -1125,17 +1125,17 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara
}
}
impl<'a> Visitor<'a> for AstValidator<'a> {
impl Visitor<'_> for AstValidator<'_> {
fn visit_attribute(&mut self, attr: &Attribute) {
validate_attr::check_attr(&self.sess.psess, attr);
}
fn visit_ty(&mut self, ty: &'a Ty) {
fn visit_ty(&mut self, ty: &Ty) {
self.visit_ty_common(ty);
self.walk_ty(ty)
}
fn visit_item(&mut self, item: &'a Item) {
fn visit_item(&mut self, item: &Item) {
if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) {
self.has_proc_macro_decls = true;
}
@@ -1477,7 +1477,7 @@ fn visit_item(&mut self, item: &'a Item) {
self.lint_node_id = previous_lint_node_id;
}
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
fn visit_foreign_item(&mut self, fi: &ForeignItem) {
match &fi.kind {
ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
@@ -1527,7 +1527,7 @@ fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
}
// Mirrors `visit::walk_generic_args`, but tracks relevant state.
fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
fn visit_generic_args(&mut self, generic_args: &GenericArgs) {
match generic_args {
GenericArgs::AngleBracketed(data) => {
self.check_generic_args_before_constraints(data);
@@ -1557,7 +1557,7 @@ fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
}
}
fn visit_generics(&mut self, generics: &'a Generics) {
fn visit_generics(&mut self, generics: &Generics) {
let mut prev_param_default = None;
for param in &generics.params {
match param.kind {
@@ -1613,7 +1613,7 @@ fn visit_generics(&mut self, generics: &'a Generics) {
}
}
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
fn visit_param_bound(&mut self, bound: &GenericBound, ctxt: BoundKind) {
match bound {
GenericBound::Trait(trait_ref) => {
match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) {
@@ -1671,7 +1671,7 @@ fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
visit::walk_param_bound(self, bound)
}
fn visit_fn(&mut self, fk: FnKind<'a>, attrs: &AttrVec, span: Span, id: NodeId) {
fn visit_fn(&mut self, fk: FnKind<'_>, attrs: &AttrVec, span: Span, id: NodeId) {
// Only associated `fn`s can have `self` parameters.
let self_semantic = match fk.ctxt() {
Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
@@ -1784,7 +1784,7 @@ fn visit_fn(&mut self, fk: FnKind<'a>, attrs: &AttrVec, span: Span, id: NodeId)
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
}
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
fn visit_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
if let Some(ident) = item.kind.ident()
&& attr::contains_name(&item.attrs, sym::no_mangle)
{
@@ -1931,7 +1931,7 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
}
}
fn visit_anon_const(&mut self, anon_const: &'a AnonConst) {
fn visit_anon_const(&mut self, anon_const: &AnonConst) {
self.with_tilde_const(
Some(TildeConstReason::AnonConst { span: anon_const.value.span }),
|this| visit::walk_anon_const(this, anon_const),
@@ -1,10 +1,11 @@
use rustc_errors::Diagnostic;
use rustc_hir::attrs::{CrateType, WindowsSubsystemKind};
use rustc_hir::lints::AttributeLintKind;
use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES;
use rustc_span::Symbol;
use rustc_span::edit_distance::find_best_match_for_name;
use super::prelude::*;
use crate::errors::{UnknownCrateTypes, UnknownCrateTypesSuggestion};
pub(crate) struct CrateNameParser;
@@ -65,13 +66,17 @@ fn extend(
crate_type,
None,
);
cx.emit_lint(
let span = n.value_span;
cx.emit_dyn_lint(
UNKNOWN_CRATE_TYPES,
AttributeLintKind::CrateTypeUnknown {
span: n.value_span,
suggested: candidate,
move |dcx, level| {
UnknownCrateTypes {
sugg: candidate
.map(|s| UnknownCrateTypesSuggestion { span, snippet: s }),
}
.into_diag(dcx, level)
},
n.value_span,
span,
);
}
return None;
@@ -1,11 +1,15 @@
use rustc_errors::Diagnostic;
use rustc_feature::{AttributeTemplate, template};
use rustc_hir::Target;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLintKind;
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_session::lint::builtin::{
MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES,
};
use rustc_span::{Symbol, sym};
use crate::attributes::{OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::errors::IncorrectDoNotRecommendLocation;
use crate::parser::ArgParser;
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
@@ -13,18 +17,32 @@
impl<S: Stage> SingleAttributeParser<S> for DoNotRecommendParser {
const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Checked in check_attr.
// "Allowed" on any target, noop on all but trait impls
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let attr_span = cx.attr_span;
if !matches!(args, ArgParser::NoArgs) {
cx.emit_lint(
cx.emit_dyn_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::DoNotRecommendDoesNotExpectArgs,
|dcx, level| crate::errors::DoNotRecommendDoesNotExpectArgs.into_diag(dcx, level),
attr_span,
);
}
if !matches!(cx.target, Target::Impl { of_trait: true }) {
let target_span = cx.target_span;
cx.emit_dyn_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level| {
IncorrectDoNotRecommendLocation { target_span }.into_diag(dcx, level)
},
attr_span,
);
return None;
}
Some(AttributeKind::DoNotRecommend { attr_span })
}
}
@@ -1,8 +1,10 @@
use rustc_errors::Diagnostic;
use rustc_hir::attrs::diagnostic::Directive;
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
use crate::attributes::diagnostic::*;
use crate::attributes::prelude::*;
use crate::errors::DiagnosticOnConstOnlyForTraitImpls;
#[derive(Default)]
pub(crate) struct OnConstParser {
span: Option<Span>,
@@ -21,6 +23,21 @@ impl<S: Stage> AttributeParser<S> for OnConstParser {
let span = cx.attr_span;
this.span = Some(span);
// FIXME(mejrs) no constness field on `Target`,
// so non-constness is still checked in check_attr.rs
if !matches!(cx.target, Target::Impl { of_trait: true }) {
let target_span = cx.target_span;
cx.emit_dyn_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level| {
DiagnosticOnConstOnlyForTraitImpls { target_span }.into_diag(dcx, level)
},
span,
);
return;
}
let mode = Mode::DiagnosticOnConst;
let Some(items) = parse_list(cx, args, mode) else { return };
@@ -32,7 +49,8 @@ impl<S: Stage> AttributeParser<S> for OnConstParser {
},
)];
//FIXME Still checked in `check_attr.rs`
// "Allowed" on all targets; noop on anything but non-const trait impls;
// this linted on in parser.
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
@@ -1,10 +1,13 @@
use rustc_errors::Diagnostic;
use rustc_feature::template;
use rustc_hir::attrs::AttributeKind;
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
use rustc_span::sym;
use crate::attributes::diagnostic::*;
use crate::attributes::prelude::*;
use crate::context::{AcceptContext, Stage};
use crate::errors::DiagnosticOnMoveOnlyForAdt;
use crate::parser::ArgParser;
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
@@ -29,6 +32,15 @@ fn parse<'sess, S: Stage>(
let span = cx.attr_span;
self.span = Some(span);
if !matches!(cx.target, Target::Enum | Target::Struct | Target::Union) {
cx.emit_dyn_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level| DiagnosticOnMoveOnlyForAdt.into_diag(dcx, level),
span,
);
return;
}
let Some(items) = parse_list(cx, args, mode) else { return };
if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
@@ -44,6 +56,8 @@ impl<S: Stage> AttributeParser<S> for OnMoveParser {
this.parse(cx, args, Mode::DiagnosticOnMove);
},
)];
// "Allowed" for all targets but noop if used on not-adt.
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
@@ -1,7 +1,10 @@
use rustc_errors::Diagnostic;
use rustc_hir::attrs::diagnostic::Directive;
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
use crate::attributes::diagnostic::*;
use crate::attributes::prelude::*;
use crate::errors::DiagnosticOnUnimplementedOnlyForTraits;
#[derive(Default)]
pub(crate) struct OnUnimplementedParser {
@@ -19,11 +22,12 @@ fn parse<'sess, S: Stage>(
let span = cx.attr_span;
self.span = Some(span);
// If target is not a trait, returning early will make `finalize` emit a
// `AttributeKind::OnUnimplemented {span, directive: None }`, to prevent it being
// accidentally used on non-trait items like trait aliases.
if !matches!(cx.target, Target::Trait) {
// Lint later emitted in check_attr
cx.emit_dyn_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level| DiagnosticOnUnimplementedOnlyForTraits.into_diag(dcx, level),
span,
);
return;
}
@@ -1,7 +1,11 @@
use rustc_errors::Diagnostic;
use rustc_hir::attrs::diagnostic::Directive;
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
use crate::ShouldEmit;
use crate::attributes::diagnostic::*;
use crate::attributes::prelude::*;
use crate::errors::DiagnosticOnUnknownOnlyForImports;
#[derive(Default)]
pub(crate) struct OnUnknownParser {
@@ -25,6 +29,22 @@ fn parse<'sess, S: Stage>(
let span = cx.attr_span;
self.span = Some(span);
// At early parsing we get passed `Target::Crate` regardless of the item we're on.
// Only do target checking if we're late.
let early = matches!(cx.stage.should_emit(), ShouldEmit::Nothing);
if !early && !matches!(cx.target, Target::Use) {
let target_span = cx.target_span;
cx.emit_dyn_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
move |dcx, level| {
DiagnosticOnUnknownOnlyForImports { target_span }.into_diag(dcx, level)
},
span,
);
return;
}
let Some(items) = parse_list(cx, args, mode) else { return };
if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
@@ -41,7 +61,7 @@ impl<S: Stage> AttributeParser<S> for OnUnknownParser {
this.parse(cx, args, Mode::DiagnosticOnUnknown);
},
)];
//FIXME attribute is not parsed for non-use statements but diagnostics are issued in `check_attr.rs`
// "Allowed" for all targets, but noop for all but use statements.
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
@@ -14,8 +14,9 @@
use super::{AcceptMapping, AttributeParser};
use crate::context::{AcceptContext, FinalizeContext, Stage};
use crate::errors::{
DocAliasDuplicated, DocAutoCfgExpectsHideOrShow, DocAutoCfgHideShowExpectsList,
DocAutoCfgHideShowUnexpectedItem, DocAutoCfgWrongLiteral, DocUnknownAny, DocUnknownInclude,
AttrCrateLevelOnly, DocAliasDuplicated, DocAutoCfgExpectsHideOrShow,
DocAutoCfgHideShowExpectsList, DocAutoCfgHideShowUnexpectedItem, DocAutoCfgWrongLiteral,
DocTestLiteral, DocTestTakesList, DocTestUnknown, DocUnknownAny, DocUnknownInclude,
DocUnknownPasses, DocUnknownPlugins, DocUnknownSpotlight, IllFormedAttributeInput,
};
use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser};
@@ -67,9 +68,9 @@ fn check_attr_not_crate_level<S: Stage>(
/// Checks that an attribute is used at the crate level. Returns `true` if valid.
fn check_attr_crate_level<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, span: Span) -> bool {
if cx.shared.target != Target::Crate {
cx.emit_lint(
cx.emit_dyn_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::AttrCrateLevelOnly,
|dcx, level| AttrCrateLevelOnly.into_diag(dcx, level),
span,
);
return false;
@@ -216,16 +217,16 @@ fn parse_single_test_doc_attr_item<S: Stage>(
}
}
Some(name) => {
cx.emit_lint(
cx.emit_dyn_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::DocTestUnknown { name },
move |dcx, level| DocTestUnknown { name }.into_diag(dcx, level),
path.span(),
);
}
None => {
cx.emit_lint(
cx.emit_dyn_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::DocTestLiteral,
|dcx, level| DocTestLiteral.into_diag(dcx, level),
path.span(),
);
}
@@ -587,9 +588,9 @@ macro_rules! string_arg_and_crate_level {
Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args),
Some(sym::test) => {
let Some(list) = args.list() else {
cx.emit_lint(
cx.emit_dyn_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::DocTestTakesList,
|dcx, level| DocTestTakesList.into_diag(dcx, level),
args.span().unwrap_or(path.span()),
);
return;
+69
View File
@@ -252,3 +252,72 @@ pub(crate) struct DocUnknownAny {
#[derive(Diagnostic)]
#[diag("expected boolean for `#[doc(auto_cfg = ...)]`")]
pub(crate) struct DocAutoCfgWrongLiteral;
#[derive(Diagnostic)]
#[diag("`#[doc(test(...)]` takes a list of attributes")]
pub(crate) struct DocTestTakesList;
#[derive(Diagnostic)]
#[diag("unknown `doc(test)` attribute `{$name}`")]
pub(crate) struct DocTestUnknown {
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag("`#![doc(test(...)]` does not take a literal")]
pub(crate) struct DocTestLiteral;
#[derive(Diagnostic)]
#[diag("this attribute can only be applied at the crate level")]
#[note(
"read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information"
)]
pub(crate) struct AttrCrateLevelOnly;
#[derive(Diagnostic)]
#[diag("`#[diagnostic::do_not_recommend]` does not expect any arguments")]
pub(crate) struct DoNotRecommendDoesNotExpectArgs;
#[derive(Diagnostic)]
#[diag("invalid `crate_type` value")]
pub(crate) struct UnknownCrateTypes {
#[subdiagnostic]
pub sugg: Option<UnknownCrateTypesSuggestion>,
}
#[derive(Subdiagnostic)]
#[suggestion("did you mean", code = r#""{snippet}""#, applicability = "maybe-incorrect")]
pub(crate) struct UnknownCrateTypesSuggestion {
#[primary_span]
pub span: Span,
pub snippet: Symbol,
}
#[derive(Diagnostic)]
#[diag("`#[diagnostic::on_const]` can only be applied to non-const trait implementations")]
pub(crate) struct DiagnosticOnConstOnlyForTraitImpls {
#[label("not a trait implementation")]
pub target_span: Span,
}
#[derive(Diagnostic)]
#[diag("`#[diagnostic::on_move]` can only be applied to enums, structs or unions")]
pub(crate) struct DiagnosticOnMoveOnlyForAdt;
#[derive(Diagnostic)]
#[diag("`#[diagnostic::on_unimplemented]` can only be applied to trait definitions")]
pub(crate) struct DiagnosticOnUnimplementedOnlyForTraits;
#[derive(Diagnostic)]
#[diag("`#[diagnostic::on_unknown]` can only be applied to `use` statements")]
pub(crate) struct DiagnosticOnUnknownOnlyForImports {
#[label("not an import")]
pub target_span: Span,
}
#[derive(Diagnostic)]
#[diag("`#[diagnostic::do_not_recommend]` can only be placed on trait implementations")]
pub(crate) struct IncorrectDoNotRecommendLocation {
#[label("not a trait implementation")]
pub target_span: Span,
}
@@ -177,7 +177,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) {
| ty::Coroutine(def_id, args) => self.visit_closure_args(def_id, args),
ty::Alias(ty::AliasTy { kind, args, .. })
if let Some(variances) = self.cx().opt_alias_variances(kind, kind.def_id()) =>
if let Some(variances) = self.cx().opt_alias_variances(kind) =>
{
// Skip lifetime parameters that are not captured, since they do
// not need member constraints registered for them; we'll erase
@@ -501,7 +501,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, RegionVid> {
}
ty::Alias(ty::AliasTy { kind, args, .. })
if let Some(variances) = tcx.opt_alias_variances(kind, kind.def_id()) =>
if let Some(variances) = tcx.opt_alias_variances(kind) =>
{
let args = tcx.mk_args_from_iter(std::iter::zip(variances, args.iter()).map(
|(&v, s)| {
+5 -2
View File
@@ -144,9 +144,12 @@ fn fat_lto(
for module in modules {
match module {
FatLtoInput::InMemory(m) => in_memory.push(m),
FatLtoInput::Serialized { name, buffer } => {
FatLtoInput::Serialized { name, bitcode_path } => {
info!("pushing serialized module {:?}", name);
serialized_modules.push((buffer, CString::new(name).unwrap()));
serialized_modules.push((
SerializedModule::from_file(&bitcode_path),
CString::new(name).unwrap(),
));
}
}
}
+8 -3
View File
@@ -223,9 +223,12 @@ fn fat_lto(
for module in modules {
match module {
FatLtoInput::InMemory(m) => in_memory.push(m),
FatLtoInput::Serialized { name, buffer } => {
FatLtoInput::Serialized { name, bitcode_path } => {
info!("pushing serialized module {:?}", name);
serialized_modules.push((buffer, CString::new(name).unwrap()));
serialized_modules.push((
SerializedModule::from_file(&bitcode_path),
CString::new(name).unwrap(),
));
}
}
}
@@ -396,7 +399,9 @@ fn thin_lto(
for (i, module) in modules.into_iter().enumerate() {
let (name, buffer) = match module {
ThinLtoInput::Red { name, buffer } => (name, buffer),
ThinLtoInput::Green { wp, buffer } => (wp.cgu_name, buffer),
ThinLtoInput::Green { wp, bitcode_path } => {
(wp.cgu_name, SerializedModule::from_file(&bitcode_path))
}
};
info!("local module: {} - {}", i, name);
let cname = CString::new(name.as_bytes()).unwrap();
@@ -1,4 +1,6 @@
use std::ffi::CString;
use std::fs;
use std::path::Path;
use std::sync::Arc;
use rustc_data_structures::memmap::Mmap;
@@ -49,6 +51,19 @@ pub enum SerializedModule<M: ModuleBufferMethods> {
}
impl<M: ModuleBufferMethods> SerializedModule<M> {
pub fn from_file(bc_path: &Path) -> Self {
let file = fs::File::open(&bc_path).unwrap_or_else(|e| {
panic!("failed to open LTO bitcode file `{}`: {}", bc_path.display(), e)
});
let mmap = unsafe {
Mmap::map(file).unwrap_or_else(|e| {
panic!("failed to mmap LTO bitcode file `{}`: {}", bc_path.display(), e)
})
};
SerializedModule::FromUncompressedFile(mmap)
}
pub fn data(&self) -> &[u8] {
match *self {
SerializedModule::Local(ref m) => m.data(),
+23 -35
View File
@@ -8,7 +8,6 @@
use rustc_abi::Size;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::jobserver::{self, Acquired};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard};
use rustc_errors::emitter::Emitter;
use rustc_errors::{
@@ -35,9 +34,8 @@
use rustc_target::spec::{MergeFunctions, SanitizerSet};
use tracing::debug;
use super::link::{self, ensure_removed};
use super::lto::{self, SerializedModule};
use crate::back::lto::check_lto_allowed;
use crate::back::link::{self, ensure_removed};
use crate::back::lto::{self, SerializedModule, check_lto_allowed};
use crate::errors::ErrorCreatingRemarkDir;
use crate::traits::*;
use crate::{
@@ -774,13 +772,13 @@ pub(crate) enum WorkItemResult<B: WriteBackendMethods> {
}
pub enum FatLtoInput<B: WriteBackendMethods> {
Serialized { name: String, buffer: SerializedModule<B::ModuleBuffer> },
Serialized { name: String, bitcode_path: PathBuf },
InMemory(ModuleCodegen<B::Module>),
}
pub enum ThinLtoInput<B: WriteBackendMethods> {
Red { name: String, buffer: SerializedModule<B::ModuleBuffer> },
Green { wp: WorkProduct, buffer: SerializedModule<B::ModuleBuffer> },
Green { wp: WorkProduct, bitcode_path: PathBuf },
}
/// Actual LTO type we end up choosing based on multiple factors.
@@ -866,7 +864,7 @@ fn execute_optimize_work_item<B: WriteBackendMethods>(
});
WorkItemResult::NeedsFatLto(FatLtoInput::Serialized {
name: module.name,
buffer: SerializedModule::Local(buffer),
bitcode_path: path,
})
}
None => WorkItemResult::NeedsFatLto(FatLtoInput::InMemory(module)),
@@ -1166,10 +1164,7 @@ pub(crate) enum Message<B: WriteBackendMethods> {
/// Similar to `CodegenDone`, but for reusing a pre-LTO artifact
/// Sent from the main thread.
AddImportOnlyModule {
module_data: SerializedModule<B::ModuleBuffer>,
work_product: WorkProduct,
},
AddImportOnlyModule { bitcode_path: PathBuf, work_product: WorkProduct },
/// The frontend has finished generating everything for all codegen units.
/// Sent from the main thread.
@@ -1729,10 +1724,10 @@ enum CodegenState {
}
}
Message::AddImportOnlyModule { module_data, work_product } => {
Message::AddImportOnlyModule { bitcode_path, work_product } => {
assert_eq!(codegen_state, Ongoing);
assert_eq!(main_thread_state, MainThreadState::Codegenning);
lto_import_only_modules.push((module_data, work_product));
lto_import_only_modules.push((bitcode_path, work_product));
main_thread_state = MainThreadState::Idle;
}
}
@@ -1758,8 +1753,8 @@ enum CodegenState {
needs_fat_lto.push(FatLtoInput::InMemory(allocator_module));
}
for (module, wp) in lto_import_only_modules {
needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module })
for (bitcode_path, wp) in lto_import_only_modules {
needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, bitcode_path })
}
return Ok(MaybeLtoModules::FatLto {
@@ -1772,8 +1767,8 @@ enum CodegenState {
assert!(compiled_modules.is_empty());
assert!(needs_fat_lto.is_empty());
for (buffer, wp) in lto_import_only_modules {
needs_thin_lto.push(ThinLtoInput::Green { wp, buffer })
for (bitcode_path, wp) in lto_import_only_modules {
needs_thin_lto.push(ThinLtoInput::Green { wp, bitcode_path })
}
if cgcx.lto == Lto::ThinLocal {
@@ -2133,14 +2128,14 @@ fn drop(&mut self) {
}
pub struct OngoingCodegen<B: WriteBackendMethods> {
pub backend: B,
pub output_filenames: Arc<OutputFilenames>,
backend: B,
output_filenames: Arc<OutputFilenames>,
// Field order below is intended to terminate the coordinator thread before two fields below
// drop and prematurely close channels used by coordinator thread. See `Coordinator`'s
// `Drop` implementation for more info.
pub coordinator: Coordinator<B>,
pub codegen_worker_receive: Receiver<CguMessage>,
pub shared_emitter_main: SharedEmitterMain,
pub(crate) coordinator: Coordinator<B>,
codegen_worker_receive: Receiver<CguMessage>,
shared_emitter_main: SharedEmitterMain,
}
impl<B: WriteBackendMethods> OngoingCodegen<B> {
@@ -2285,20 +2280,13 @@ pub(crate) fn submit_pre_lto_module_to_llvm<B: WriteBackendMethods>(
module: CachedModuleCodegen,
) {
let filename = pre_lto_bitcode_filename(&module.name);
let bc_path = in_incr_comp_dir_sess(tcx.sess, &filename);
let file = fs::File::open(&bc_path)
.unwrap_or_else(|e| panic!("failed to open bitcode file `{}`: {}", bc_path.display(), e));
let mmap = unsafe {
Mmap::map(file).unwrap_or_else(|e| {
panic!("failed to mmap bitcode file `{}`: {}", bc_path.display(), e)
})
};
let bitcode_path = in_incr_comp_dir_sess(tcx.sess, &filename);
// Schedule the module to be loaded
drop(coordinator.sender.send(Message::AddImportOnlyModule::<B> {
module_data: SerializedModule::FromUncompressedFile(mmap),
work_product: module.source,
}));
drop(
coordinator
.sender
.send(Message::AddImportOnlyModule::<B> { bitcode_path, work_product: module.source }),
);
}
fn pre_lto_bitcode_filename(module_name: &str) -> String {
@@ -16,8 +16,11 @@
use hir::def::DefKind;
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_hir as hir;
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
use rustc_hir::def_id::LocalDefIdMap;
use rustc_hir::definitions::{
DefPathData, PerParentDisambiguatorState, PerParentDisambiguatorsMap,
};
use rustc_hir::{self as hir};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir::interpret::{
AllocBytes, ConstAllocation, CtfeProvenance, InterpResult, Provenance,
@@ -105,7 +108,7 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>(
ecx: &mut InterpCx<'tcx, M>,
alloc_id: AllocId,
mutability: Mutability,
disambiguator: Option<&mut DisambiguatorState>,
disambiguators: Option<&mut LocalDefIdMap<PerParentDisambiguatorState>>,
) -> Result<impl Iterator<Item = CtfeProvenance> + 'tcx, InternError> {
trace!("intern_shallow {:?}", alloc_id);
// remove allocation
@@ -129,7 +132,7 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>(
static_id,
alloc_id,
alloc,
disambiguator.expect("disambiguator needed"),
disambiguators.expect("disambiguators needed"),
);
} else {
ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
@@ -144,7 +147,7 @@ fn intern_as_new_static<'tcx>(
static_id: LocalDefId,
alloc_id: AllocId,
alloc: ConstAllocation<'tcx>,
disambiguator: &mut DisambiguatorState,
disambiguators: &mut LocalDefIdMap<PerParentDisambiguatorState>,
) {
// `intern_const_alloc_recursive` is called once per static and it contains the `DisambiguatorState`.
// The `<static_id>::{{nested}}` path is thus unique to `intern_const_alloc_recursive` and the
@@ -155,7 +158,8 @@ fn intern_as_new_static<'tcx>(
None,
DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true },
Some(DefPathData::NestedStatic),
disambiguator,
//FIXME(oli-obk): cleanup (https://github.com/rust-lang/rust/pull/155547#discussion_r3110792640)
disambiguators.get_or_create(static_id),
);
tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());
@@ -205,7 +209,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>(
intern_kind: InternKind,
ret: &MPlaceTy<'tcx>,
) -> Result<(), InternError> {
let mut disambiguator = DisambiguatorState::new();
let mut disambiguators = Default::default();
// We are interning recursively, and for mutability we are distinguishing the "root" allocation
// that we are starting in, and all other allocations that we are encountering recursively.
@@ -250,7 +254,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>(
prepare_alloc(*ecx.tcx, *kind, alloc, base_mutability)?;
alloc.provenance().ptrs().iter().map(|&(_, prov)| prov).collect()
} else {
intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguator))?.collect()
intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguators))?.collect()
};
// We need to distinguish "has just been interned" from "was already in `tcx`",
// so we track this in a separate set.
@@ -332,7 +336,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>(
// okay with losing some potential for immutability here. This can anyway only affect
// `static mut`.
just_interned.insert(alloc_id);
let next = intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguator))?;
let next = intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguators))?;
todo.extend(next);
}
if found_bad_mutable_ptr {
@@ -1,81 +1,157 @@
use std::{mem, ptr};
use smallvec::{Array, SmallVec};
use smallvec::SmallVec;
use thin_vec::ThinVec;
pub trait FlatMapInPlace<T>: Sized {
pub trait FlatMapInPlace<T> {
/// `f` turns each element into 0..many elements. This function will consume the existing
/// elements in a vec-like structure and replace them with any number of new elements — fewer,
/// more, or the same number — as efficiently as possible.
fn flat_map_in_place<F, I>(&mut self, f: F)
where
F: FnMut(T) -> I,
I: IntoIterator<Item = T>;
}
// The implementation of this method is syntactically identical for all the
// different vector types.
macro_rules! flat_map_in_place {
($vec:ident $( where T: $bound:path)?) => {
fn flat_map_in_place<F, I>(&mut self, mut f: F)
where
F: FnMut(T) -> I,
I: IntoIterator<Item = T>,
{
struct LeakGuard<'a, T $(: $bound)?>(&'a mut $vec<T>);
// Blanket impl for all vec-like types that impl `FlatMapInPlaceVec`.
impl<V: FlatMapInPlaceVec> FlatMapInPlace<V::Elem> for V {
fn flat_map_in_place<F, I>(&mut self, mut f: F)
where
F: FnMut(V::Elem) -> I,
I: IntoIterator<Item = V::Elem>,
{
struct LeakGuard<'a, V: FlatMapInPlaceVec>(&'a mut V);
impl<'a, T $(: $bound)?> Drop for LeakGuard<'a, T> {
fn drop(&mut self) {
unsafe {
self.0.set_len(0); // make sure we just leak elements in case of panic
}
impl<'a, V: FlatMapInPlaceVec> Drop for LeakGuard<'a, V> {
fn drop(&mut self) {
unsafe {
// Leak all elements in case of panic.
self.0.set_len(0);
}
}
let this = LeakGuard(self);
let mut read_i = 0;
let mut write_i = 0;
unsafe {
while read_i < this.0.len() {
// move the read_i'th item out of the vector and map it
// to an iterator
let e = ptr::read(this.0.as_ptr().add(read_i));
let iter = f(e).into_iter();
read_i += 1;
for e in iter {
if write_i < read_i {
ptr::write(this.0.as_mut_ptr().add(write_i), e);
write_i += 1;
} else {
// If this is reached we ran out of space
// in the middle of the vector.
// However, the vector is in a valid state here,
// so we just do a somewhat inefficient insert.
this.0.insert(write_i, e);
read_i += 1;
write_i += 1;
}
}
}
// write_i tracks the number of actually written new items.
this.0.set_len(write_i);
// The ThinVec is in a sane state again. Prevent the LeakGuard from leaking the data.
mem::forget(this);
}
}
};
let guard = LeakGuard(self);
let mut read_i = 0;
let mut write_i = 0;
unsafe {
while read_i < guard.0.len() {
// Move the read_i'th item out of the vector and map it to an iterator.
let e = ptr::read(guard.0.as_ptr().add(read_i));
let iter = f(e).into_iter();
read_i += 1;
for e in iter {
if write_i < read_i {
ptr::write(guard.0.as_mut_ptr().add(write_i), e);
write_i += 1;
} else {
// If this is reached we ran out of space in the middle of the vector.
// However, the vector is in a valid state here, so we just do a somewhat
// inefficient insert.
guard.0.insert(write_i, e);
read_i += 1;
write_i += 1;
}
}
}
// `write_i` tracks the number of actually written new items.
guard.0.set_len(write_i);
// `vec` is in a sane state again. Prevent the LeakGuard from leaking the data.
mem::forget(guard);
}
}
}
impl<T> FlatMapInPlace<T> for Vec<T> {
flat_map_in_place!(Vec);
// A vec-like type must implement these operations to support `flat_map_in_place`.
pub trait FlatMapInPlaceVec {
type Elem;
fn len(&self) -> usize;
unsafe fn set_len(&mut self, len: usize);
fn as_ptr(&self) -> *const Self::Elem;
fn as_mut_ptr(&mut self) -> *mut Self::Elem;
fn insert(&mut self, idx: usize, elem: Self::Elem);
}
impl<T, A: Array<Item = T>> FlatMapInPlace<T> for SmallVec<A> {
flat_map_in_place!(SmallVec where T: Array);
impl<T> FlatMapInPlaceVec for Vec<T> {
type Elem = T;
fn len(&self) -> usize {
self.len()
}
unsafe fn set_len(&mut self, len: usize) {
unsafe {
self.set_len(len);
}
}
fn as_ptr(&self) -> *const Self::Elem {
self.as_ptr()
}
fn as_mut_ptr(&mut self) -> *mut Self::Elem {
self.as_mut_ptr()
}
fn insert(&mut self, idx: usize, elem: Self::Elem) {
self.insert(idx, elem);
}
}
impl<T> FlatMapInPlace<T> for ThinVec<T> {
flat_map_in_place!(ThinVec);
impl<T> FlatMapInPlaceVec for ThinVec<T> {
type Elem = T;
fn len(&self) -> usize {
self.len()
}
unsafe fn set_len(&mut self, len: usize) {
unsafe {
self.set_len(len);
}
}
fn as_ptr(&self) -> *const Self::Elem {
self.as_slice().as_ptr()
}
fn as_mut_ptr(&mut self) -> *mut Self::Elem {
self.as_mut_slice().as_mut_ptr()
}
fn insert(&mut self, idx: usize, elem: Self::Elem) {
self.insert(idx, elem);
}
}
impl<T, const N: usize> FlatMapInPlaceVec for SmallVec<[T; N]> {
type Elem = T;
fn len(&self) -> usize {
self.len()
}
unsafe fn set_len(&mut self, len: usize) {
unsafe {
self.set_len(len);
}
}
fn as_ptr(&self) -> *const Self::Elem {
self.as_ptr()
}
fn as_mut_ptr(&mut self) -> *mut Self::Elem {
self.as_mut_ptr()
}
fn insert(&mut self, idx: usize, elem: Self::Elem) {
self.insert(idx, elem);
}
}
+27 -36
View File
@@ -7,11 +7,12 @@
use std::fmt::{self, Write};
use std::hash::Hash;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::unord::UnordMap;
use rustc_hashes::Hash64;
use rustc_index::IndexVec;
use rustc_macros::{BlobDecodable, Decodable, Encodable};
use rustc_macros::{BlobDecodable, Decodable, Encodable, extension};
use rustc_span::def_id::LocalDefIdMap;
use rustc_span::{Symbol, kw, sym};
use tracing::{debug, instrument};
@@ -97,45 +98,28 @@ pub fn enumerated_keys_and_path_hashes(
}
}
pub trait Disambiguator {
fn entry(&mut self, parent: LocalDefId, data: DefPathData) -> &mut u32;
}
#[derive(Debug, Default, Clone)]
pub struct PerParentDisambiguatorState {
next: UnordMap<DefPathData, u32>,
#[cfg(debug_assertions)]
parent: Option<LocalDefId>,
next: FxHashMap<DefPathData, u32>,
}
impl Disambiguator for PerParentDisambiguatorState {
#[inline]
fn entry(&mut self, _: LocalDefId, data: DefPathData) -> &mut u32 {
self.next.entry(data).or_insert(0)
impl PerParentDisambiguatorState {
#[inline(always)]
pub fn new(_parent: LocalDefId) -> PerParentDisambiguatorState {
PerParentDisambiguatorState {
#[cfg(debug_assertions)]
parent: Some(_parent),
next: Default::default(),
}
}
}
#[derive(Debug, Default, Clone)]
pub struct DisambiguatorState {
next: UnordMap<(LocalDefId, DefPathData), u32>,
}
impl Disambiguator for DisambiguatorState {
#[inline]
fn entry(&mut self, parent: LocalDefId, data: DefPathData) -> &mut u32 {
self.next.entry((parent, data)).or_insert(0)
}
}
impl DisambiguatorState {
pub const fn new() -> Self {
Self { next: Default::default() }
}
/// Creates a `DisambiguatorState` where the next allocated `(LocalDefId, DefPathData)` pair
/// will have `index` as the disambiguator.
pub fn with(def_id: LocalDefId, data: DefPathData, index: u32) -> Self {
let mut this = Self::new();
this.next.insert((def_id, data), index);
this
#[extension(pub trait PerParentDisambiguatorsMap)]
impl LocalDefIdMap<PerParentDisambiguatorState> {
fn get_or_create(&mut self, parent: LocalDefId) -> &mut PerParentDisambiguatorState {
self.entry(parent).or_insert_with(|| PerParentDisambiguatorState::new(parent))
}
}
@@ -408,7 +392,7 @@ pub fn create_def(
&mut self,
parent: LocalDefId,
data: DefPathData,
disambiguator: &mut impl Disambiguator,
disambiguator: &mut PerParentDisambiguatorState,
) -> LocalDefId {
// We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a
// reference to `Definitions` and we're already holding a mutable reference.
@@ -422,7 +406,14 @@ pub fn create_def(
// Find the next free disambiguator for this key.
let disambiguator = {
let next_disamb = disambiguator.entry(parent, data);
#[cfg(debug_assertions)]
debug_assert_eq!(
parent,
disambiguator.parent.expect("must be set"),
"provided parent and parent in disambiguator must be the same"
);
let next_disamb = disambiguator.next.entry(data).or_insert(0);
let disambiguator = *next_disamb;
*next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
disambiguator
@@ -2735,7 +2735,7 @@ fn param_env_with_gat_bounds<'tcx>(
_ => predicates.push(
ty::Binder::bind_with_vars(
ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(
projection_term: ty::AliasTerm::new_from_def_id(
tcx,
trait_ty.def_id,
rebased_args,
+2 -2
View File
@@ -370,10 +370,10 @@ fn bounds_from_generic_predicates<'tcx>(
let mut projections_str = vec![];
for projection in &projections {
let p = projection.skip_binder();
if bound == tcx.parent(p.projection_term.def_id)
if bound == tcx.parent(p.projection_term.def_id())
&& p.projection_term.self_ty() == ty
{
let name = tcx.item_name(p.projection_term.def_id);
let name = tcx.item_name(p.projection_term.def_id());
projections_str.push(format!("{} = {}", name, p.term));
}
}
@@ -1655,7 +1655,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result {
.map_bound(|pred| {
pred.term.as_const().map(|ct| {
let assoc_const_ty = tcx
.type_of(pred.projection_term.def_id)
.type_of(pred.projection_term.def_id())
.instantiate(tcx, pred.projection_term.args)
.skip_norm_wip();
ty::ClauseKind::ConstArgHasType(ct, assoc_const_ty)
@@ -14,7 +14,8 @@
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
use rustc_hir::def_id::LocalDefIdMap;
use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorsMap};
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
use rustc_hir::{
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node,
@@ -30,6 +31,7 @@
use tracing::{debug, debug_span, instrument};
use crate::errors;
use crate::hir::definitions::PerParentDisambiguatorState;
#[extension(trait RegionExt)]
impl ResolvedArg {
@@ -64,7 +66,7 @@ fn shifted(self, amount: u32) -> ResolvedArg {
struct BoundVarContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
rbv: &'a mut ResolveBoundVars<'tcx>,
disambiguator: &'a mut DisambiguatorState,
disambiguators: &'a mut LocalDefIdMap<PerParentDisambiguatorState>,
scope: ScopeRef<'a, 'tcx>,
opaque_capture_errors: RefCell<Option<OpaqueHigherRankedLifetimeCaptureErrors>>,
}
@@ -259,7 +261,7 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou
tcx,
rbv: &mut rbv,
scope: &Scope::Root { opt_parent_item: None },
disambiguator: &mut DisambiguatorState::new(),
disambiguators: &mut Default::default(),
opaque_capture_errors: RefCell::new(None),
};
match tcx.hir_owner_node(local_def_id) {
@@ -1104,12 +1106,12 @@ fn with<F>(&mut self, wrap_scope: Scope<'_, 'tcx>, f: F)
where
F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>),
{
let BoundVarContext { tcx, rbv, disambiguator, .. } = self;
let BoundVarContext { tcx, rbv, disambiguators, .. } = self;
let nested_errors = RefCell::new(self.opaque_capture_errors.borrow_mut().take());
let mut this = BoundVarContext {
tcx: *tcx,
rbv,
disambiguator,
disambiguators,
scope: &wrap_scope,
opaque_capture_errors: nested_errors,
};
@@ -1523,7 +1525,7 @@ fn remap_opaque_captures(
None,
DefKind::LifetimeParam,
Some(DefPathData::OpaqueLifetime(ident.name)),
self.disambiguator,
self.disambiguators.get_or_create(opaque_def_id),
);
feed.def_span(ident.span);
feed.def_ident_span(Some(ident.span));
@@ -526,7 +526,7 @@ pub(super) fn lower_assoc_item_constraint(
);
debug!(?alias_args);
ty::AliasTerm::new_from_args(tcx, assoc_item.def_id, alias_args)
ty::AliasTerm::new_from_def_id(tcx, assoc_item.def_id, alias_args)
})
};
@@ -543,7 +543,7 @@ pub(super) fn lower_assoc_item_constraint(
hir::Term::Ty(ty) => self.lower_ty(ty).into(),
hir::Term::Const(ct) => {
let ty = projection_term.map_bound(|alias| {
tcx.type_of(alias.def_id).instantiate(tcx, alias.args).skip_norm_wip()
tcx.type_of(alias.def_id()).instantiate(tcx, alias.args).skip_norm_wip()
});
let ty = check_assoc_const_binding_type(
self,
@@ -1364,7 +1364,7 @@ fn probe_single_bound_for_assoc_item<I>(
&item_segment,
trait_ref.args,
);
ty::AliasTerm::new_from_args(
ty::AliasTerm::new_from_def_id(
tcx,
assoc_item.def_id,
alias_args,
@@ -1374,7 +1374,7 @@ fn probe_single_bound_for_assoc_item<I>(
// FIXME(mgca): code duplication with other places we lower
// the rhs' of associated const bindings
let ty = projection_term.map_bound(|alias| {
tcx.type_of(alias.def_id)
tcx.type_of(alias.def_id())
.instantiate(tcx, alias.args)
.skip_norm_wip()
});
+2 -2
View File
@@ -1057,11 +1057,11 @@ fn deduce_future_output_from_projection(
// The `Future` trait has only one associated item, `Output`,
// so check that this is what we see.
let output_assoc_item = self.tcx.associated_item_def_ids(trait_def_id)[0];
if output_assoc_item != predicate.projection_term.def_id {
if output_assoc_item != predicate.projection_term.def_id() {
span_bug!(
cause_span,
"projecting associated item `{:?}` from future, which is not Output `{:?}`",
predicate.projection_term.def_id,
predicate.projection_term.kind,
output_assoc_item,
);
}
+6
View File
@@ -173,6 +173,12 @@ pub(crate) enum ExpectedReturnTypeLabel<'tcx> {
span: Span,
expected: Ty<'tcx>,
},
#[label("expected a single type implementing `{$trait_name}` because of return type")]
ImplTrait {
#[primary_span]
span: Span,
trait_name: String,
},
}
#[derive(Diagnostic)]
@@ -931,6 +931,42 @@ pub(in super::super) fn suggest_missing_return_type(
}
hir::FnRetTy::Return(hir_ty) => {
if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind
&& let [hir::GenericBound::Trait(trait_ref)] = op_ty.bounds
&& !trait_ref
.trait_ref
.path
.segments
.last()
.and_then(|seg| seg.args)
.map_or(false, |args| !args.constraints.is_empty())
{
// Use the path to get the trait name string
let trait_name = trait_ref
.trait_ref
.path
.segments
.iter()
.map(|seg| seg.ident.as_str())
.collect::<Vec<_>>()
.join("::");
err.subdiagnostic(errors::ExpectedReturnTypeLabel::ImplTrait {
span: hir_ty.span,
trait_name,
});
if let Some(ret_coercion_span) = self.ret_coercion_span.get() {
let expected_name = expected.to_string();
err.span_label(
ret_coercion_span,
format!("return type resolved to be `{expected_name}`"),
);
}
self.try_suggest_return_impl_trait(err, expected, found, fn_id);
self.try_note_caller_chooses_ty_for_ty_param(err, expected, found);
return true;
} else if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind
// FIXME: account for RPITIT.
&& let [hir::GenericBound::Trait(trait_ref)] = op_ty.bounds
&& let Some(hir::PathSegment { args: Some(generic_args), .. }) =
@@ -95,7 +95,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) {
} else {
// Skip lifetime parameters that are not captured, since they do
// not need to be live.
let variances = tcx.opt_alias_variances(kind, kind.def_id());
let variances = tcx.opt_alias_variances(kind);
for (idx, s) in args.iter().enumerate() {
if variances.map(|variances| variances[idx]) != Some(ty::Bivariant) {
@@ -485,7 +485,7 @@ fn alias_ty_must_outlive(
&& (alias_ty.has_infer_regions() || matches!(kind, ty::Opaque { .. }))
{
debug!("no declared bounds");
let opt_variances = self.tcx.opt_alias_variances(kind, kind.def_id());
let opt_variances = self.tcx.opt_alias_variances(kind);
self.args_must_outlive(alias_ty.args, origin, region, opt_variances);
return;
}
+1 -1
View File
@@ -22,7 +22,7 @@ pub fn projection_term_to_infer(
) -> Term<'tcx> {
debug_assert!(!self.next_trait_solver());
let span = self.tcx.def_span(alias_term.def_id);
let span = self.tcx.def_span(alias_term.def_id());
let infer_var = if alias_term.kind(self.tcx).is_type() {
self.next_ty_var(span).into()
} else {
@@ -184,11 +184,12 @@ fn instantiate_var<R: PredicateEmittingRelation<Self>>(
relation.register_predicates([ty::PredicateKind::AliasRelate(lhs, rhs, direction)]);
} else {
let Some(source_alias) = source_term.to_alias_term() else {
let Some(source_alias) = source_term.to_alias_term(self.tcx) else {
bug!("generalized `{source_term:?} to infer, not an alias");
};
match source_alias.kind(self.tcx) {
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
ty::AliasTermKind::ProjectionTy { .. }
| ty::AliasTermKind::ProjectionConst { .. } => {
// FIXME: This does not handle subtyping correctly, we could
// instead create a new inference variable `?normalized_source`, emitting
// `Projection(normalized_source, ?ty_normalized)` and
@@ -199,14 +200,14 @@ fn instantiate_var<R: PredicateEmittingRelation<Self>>(
}]);
}
// The old solver only accepts projection predicates for associated types.
ty::AliasTermKind::InherentTy
| ty::AliasTermKind::FreeTy
| ty::AliasTermKind::OpaqueTy => {
ty::AliasTermKind::InherentTy { .. }
| ty::AliasTermKind::FreeTy { .. }
| ty::AliasTermKind::OpaqueTy { .. } => {
return Err(TypeError::CyclicTy(source_term.expect_type()));
}
ty::AliasTermKind::InherentConst
| ty::AliasTermKind::FreeConst
| ty::AliasTermKind::UnevaluatedConst => {
ty::AliasTermKind::InherentConst { .. }
| ty::AliasTermKind::FreeConst { .. }
| ty::AliasTermKind::UnevaluatedConst { .. } => {
return Err(TypeError::CyclicConst(source_term.expect_const()));
}
}
@@ -755,7 +756,8 @@ fn consts(
// path), as doing this new No path breaks some GCE things. I expect GCE to be
// ripped out soon so this shouldn't matter soon.
StructurallyRelateAliases::No if !self.cx().features().generic_const_exprs() => {
self.generalize_alias_term(uv.into()).map(|v| v.expect_const())
self.generalize_alias_term(ty::AliasTerm::from_unevaluated_const(self.cx(), uv))
.map(|v| v.expect_const())
}
_ => {
let ty::UnevaluatedConst { def, args } = uv;
@@ -43,27 +43,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
.into_diag(dcx, level)
}
&AttributeLintKind::DocTestTakesList => lints::DocTestTakesList.into_diag(dcx, level),
&AttributeLintKind::DocTestUnknown { name } => {
lints::DocTestUnknown { name }.into_diag(dcx, level)
}
&AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.into_diag(dcx, level),
&AttributeLintKind::AttrCrateLevelOnly => {
lints::AttrCrateLevelOnly.into_diag(dcx, level)
}
&AttributeLintKind::DoNotRecommendDoesNotExpectArgs => {
lints::DoNotRecommendDoesNotExpectArgs.into_diag(dcx, level)
}
&AttributeLintKind::CrateTypeUnknown { span, suggested } => lints::UnknownCrateTypes {
sugg: suggested.map(|s| lints::UnknownCrateTypesSuggestion { span, snippet: s }),
}
.into_diag(dcx, level),
&AttributeLintKind::MalformedDoc => lints::MalformedDoc.into_diag(dcx, level),
&AttributeLintKind::ExpectedNoArgs => lints::ExpectedNoArgs.into_diag(dcx, level),
-40
View File
@@ -3303,46 +3303,6 @@ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
)]
pub(crate) struct ExpectedNameValue;
#[derive(Diagnostic)]
#[diag("`#[doc(test(...)]` takes a list of attributes")]
pub(crate) struct DocTestTakesList;
#[derive(Diagnostic)]
#[diag("unknown `doc(test)` attribute `{$name}`")]
pub(crate) struct DocTestUnknown {
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag("`#![doc(test(...)]` does not take a literal")]
pub(crate) struct DocTestLiteral;
#[derive(Diagnostic)]
#[diag("this attribute can only be applied at the crate level")]
#[note(
"read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information"
)]
pub(crate) struct AttrCrateLevelOnly;
#[derive(Diagnostic)]
#[diag("`#[diagnostic::do_not_recommend]` does not expect any arguments")]
pub(crate) struct DoNotRecommendDoesNotExpectArgs;
#[derive(Diagnostic)]
#[diag("invalid `crate_type` value")]
pub(crate) struct UnknownCrateTypes {
#[subdiagnostic]
pub sugg: Option<UnknownCrateTypesSuggestion>,
}
#[derive(Subdiagnostic)]
#[suggestion("did you mean", code = r#""{snippet}""#, applicability = "maybe-incorrect")]
pub(crate) struct UnknownCrateTypesSuggestion {
#[primary_span]
pub span: Span,
pub snippet: Symbol,
}
#[derive(Diagnostic)]
#[diag("positional format arguments are not allowed here")]
#[help(
@@ -132,7 +132,7 @@ fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, AmbigArg>
let proj_ty = Ty::new_projection_from_args(
cx.tcx,
proj.projection_term.def_id,
proj.projection_term.def_id(),
proj.projection_term.args,
);
// For every instance of the projection type in the bounds,
@@ -149,7 +149,7 @@ fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, AmbigArg>
// with `impl Send: OtherTrait`.
for (assoc_pred, assoc_pred_span) in cx
.tcx
.explicit_item_bounds(proj.projection_term.def_id)
.explicit_item_bounds(proj.projection_term.def_id())
.iter_instantiated_copied(cx.tcx, proj.projection_term.args)
.map(Unnormalized::skip_norm_wip)
{
+300 -173
View File
@@ -192,6 +192,7 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
fn check_arg_for_power_alignment<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
let tcx = cx.tcx;
assert!(tcx.sess.target.os == Os::Aix);
// Structs (under repr(C)) follow the power alignment rule if:
// - the first field of the struct is a floating-point type that
// is greater than 4-bytes, or
@@ -273,6 +274,17 @@ enum FfiResult<'tcx> {
/// in the `FfiResult` is final.
type PartialFfiResult<'tcx> = Option<FfiResult<'tcx>>;
/// What type indirection points to a given type.
#[derive(Clone, Copy)]
enum IndirectionKind {
/// Box (valid non-null pointer, owns pointee).
Box,
/// Ref (valid non-null pointer, borrows pointee).
Ref,
/// Raw pointer (not necessarily non-null or valid. no info on ownership).
RawPtr,
}
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct VisitorState: u8 {
@@ -359,6 +371,35 @@ fn can_expect_ty_params(self) -> bool {
}
}
bitflags! {
/// Data that summarises how an "outer type" surrounds its inner type(s)
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct OuterTyData: u8 {
/// To show that there is no outer type, the current type is directly used by a `static`
/// variable or a function/FnPtr
const NO_OUTER_TY = 0b01;
/// For NO_OUTER_TY cases, show that we are being directly used by a FnPtr specifically
/// FIXME(ctypes): this is only used for "bad behaviour" reproduced for compatibility's sake
const NO_OUTER_TY_FNPTR = 0b10;
}
}
impl OuterTyData {
/// Get the proper data for a given outer type.
fn from_ty<'tcx>(ty: Ty<'tcx>) -> Self {
match ty.kind() {
ty::FnPtr(..) => Self::NO_OUTER_TY | Self::NO_OUTER_TY_FNPTR,
ty::RawPtr(..)
| ty::Ref(..)
| ty::Adt(..)
| ty::Tuple(..)
| ty::Array(..)
| ty::Slice(_) => Self::empty(),
k @ _ => bug!("unexpected outer type {:?} of kind {:?}", ty, k),
}
}
}
/// Visitor used to recursively traverse MIR types and evaluate FFI-safety.
/// It uses ``check_*`` methods as entrypoints to be called elsewhere,
/// and ``visit_*`` methods to recurse.
@@ -378,21 +419,94 @@ fn new(cx: &'a LateContext<'tcx>, base_ty: Ty<'tcx>, base_fn_mode: CItemKind) ->
Self { cx, base_ty, base_fn_mode, cache: FxHashSet::default() }
}
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
fn check_variant_for_ffi(
/// Checks if the given indirection (box,ref,pointer) is "ffi-safe".
fn visit_indirection(
&mut self,
state: VisitorState,
ty: Ty<'tcx>,
def: ty::AdtDef<'tcx>,
inner_ty: Ty<'tcx>,
indirection_kind: IndirectionKind,
) -> FfiResult<'tcx> {
use FfiResult::*;
let tcx = self.cx.tcx;
match indirection_kind {
IndirectionKind::Box => {
// FIXME(ctypes): this logic is broken, but it still fits the current tests:
// - for some reason `Box<_>`es in `extern "ABI" {}` blocks
// (including within FnPtr:s)
// are not treated as pointers but as FFI-unsafe structs
// - otherwise, treat the box itself correctly, and follow pointee safety logic
// as described in the other `indirection_type` match branch.
if state.is_in_defined_function()
|| (state.is_in_fnptr() && matches!(self.base_fn_mode, CItemKind::Definition))
{
if inner_ty.is_sized(tcx, self.cx.typing_env()) {
return FfiSafe;
} else {
return FfiUnsafe {
ty,
reason: msg!("box cannot be represented as a single pointer"),
help: None,
};
}
} else {
// (mid-retcon-commit-chain comment:)
// this is the original fallback behavior, which is wrong
if let ty::Adt(def, args) = ty.kind() {
self.visit_struct_or_union(state, ty, *def, args)
} else if cfg!(debug_assertions) {
bug!("ImproperCTypes: this retcon commit was badly written")
} else {
FfiSafe
}
}
}
IndirectionKind::Ref | IndirectionKind::RawPtr => {
// Weird behaviour for pointee safety. the big question here is
// "if you have a FFI-unsafe pointee behind a FFI-safe pointer type, is it ok?"
// The answer until now is:
// "It's OK for rust-defined functions and callbacks, we'll assume those are
// meant to be opaque types on the other side of the FFI boundary".
//
// Reasoning:
// For extern function declarations, the actual definition of the function is
// written somewhere else, meaning the declaration is free to express this
// opaqueness with an extern type (opaque caller-side) or a std::ffi::c_void
// (opaque callee-side). For extern function definitions, however, in the case
// where the type is opaque caller-side, it is not opaque callee-side,
// and having the full type information is necessary to compile the function.
//
// It might be better to rething this, or even ignore pointee safety for a first
// batch of behaviour changes. See the discussion that ends with
// https://github.com/rust-lang/rust/pull/134697#issuecomment-2692610258
if (state.is_in_defined_function() || state.is_in_fnptr())
&& inner_ty.is_sized(self.cx.tcx, self.cx.typing_env())
{
FfiSafe
} else {
self.visit_type(state, OuterTyData::from_ty(ty), inner_ty)
}
}
}
}
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
fn visit_variant_fields(
&mut self,
state: VisitorState,
ty: Ty<'tcx>,
def: AdtDef<'tcx>,
variant: &ty::VariantDef,
args: GenericArgsRef<'tcx>,
) -> FfiResult<'tcx> {
use FfiResult::*;
let transparent_with_all_zst_fields = if def.repr().transparent() {
if let Some(field) = super::transparent_newtype_field(self.cx.tcx, variant) {
// Transparent newtypes have at most one non-ZST field which needs to be checked..
let field_ty = get_type_from_field(self.cx, field, args);
match self.visit_type(state, field_ty) {
match self.visit_type(state, OuterTyData::from_ty(ty), field_ty) {
FfiUnsafe { ty, .. } if ty.is_unit() => (),
r => return r,
}
@@ -411,7 +525,7 @@ fn check_variant_for_ffi(
let mut all_phantom = !variant.fields.is_empty();
for field in &variant.fields {
let field_ty = get_type_from_field(self.cx, field, args);
all_phantom &= match self.visit_type(state, field_ty) {
all_phantom &= match self.visit_type(state, OuterTyData::from_ty(ty), field_ty) {
FfiSafe => false,
// `()` fields are FFI-safe!
FfiUnsafe { ty, .. } if ty.is_unit() => false,
@@ -433,9 +547,125 @@ fn check_variant_for_ffi(
}
}
fn visit_struct_or_union(
&mut self,
state: VisitorState,
ty: Ty<'tcx>,
def: AdtDef<'tcx>,
args: GenericArgsRef<'tcx>,
) -> FfiResult<'tcx> {
debug_assert!(matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union));
use FfiResult::*;
if !def.repr().c() && !def.repr().transparent() {
return FfiUnsafe {
ty,
reason: if def.is_struct() {
msg!("this struct has unspecified layout")
} else {
msg!("this union has unspecified layout")
},
help: if def.is_struct() {
Some(msg!(
"consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct"
))
} else {
// FIXME(ctypes): confirm that this makes sense for unions once #60405 / RFC2645 stabilises
Some(msg!(
"consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union"
))
},
};
}
if def.non_enum_variant().field_list_has_applicable_non_exhaustive() {
return FfiUnsafe {
ty,
reason: if def.is_struct() {
msg!("this struct is non-exhaustive")
} else {
msg!("this union is non-exhaustive")
},
help: None,
};
}
if def.non_enum_variant().fields.is_empty() {
FfiUnsafe {
ty,
reason: if def.is_struct() {
msg!("this struct has no fields")
} else {
msg!("this union has no fields")
},
help: if def.is_struct() {
Some(msg!("consider adding a member to this struct"))
} else {
Some(msg!("consider adding a member to this union"))
},
}
} else {
self.visit_variant_fields(state, ty, def, def.non_enum_variant(), args)
}
}
fn visit_enum(
&mut self,
state: VisitorState,
ty: Ty<'tcx>,
def: AdtDef<'tcx>,
args: GenericArgsRef<'tcx>,
) -> FfiResult<'tcx> {
debug_assert!(matches!(def.adt_kind(), AdtKind::Enum));
use FfiResult::*;
if def.variants().is_empty() {
// Empty enums are okay... although sort of useless.
return FfiSafe;
}
// Check for a repr() attribute to specify the size of the
// discriminant.
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none() {
// Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
if let Some(inner_ty) = repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty) {
return self.visit_type(state, OuterTyData::from_ty(ty), inner_ty);
}
return FfiUnsafe {
ty,
reason: msg!("enum has no representation hint"),
help: Some(msg!(
"consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum"
)),
};
}
let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
// Check the contained variants.
let ret = def.variants().iter().try_for_each(|variant| {
check_non_exhaustive_variant(non_exhaustive, variant)
.map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
match self.visit_variant_fields(state, ty, def, variant, args) {
FfiSafe => ControlFlow::Continue(()),
r => ControlFlow::Break(r),
}
});
if let ControlFlow::Break(result) = ret {
return result;
}
FfiSafe
}
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
/// representation which can be exported to C code).
fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
fn visit_type(
&mut self,
state: VisitorState,
outer_ty: OuterTyData,
ty: Ty<'tcx>,
) -> FfiResult<'tcx> {
use FfiResult::*;
let tcx = self.cx.tcx;
@@ -450,23 +680,8 @@ fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
match *ty.kind() {
ty::Adt(def, args) => {
if let Some(boxed) = ty.boxed_ty()
&& (
// FIXME(ctypes): this logic is broken, but it still fits the current tests
state.is_in_defined_function()
|| (state.is_in_fnptr()
&& matches!(self.base_fn_mode, CItemKind::Definition))
)
{
if boxed.is_sized(tcx, self.cx.typing_env()) {
return FfiSafe;
} else {
return FfiUnsafe {
ty,
reason: msg!("box cannot be represented as a single pointer"),
help: None,
};
}
if let Some(inner_ty) = ty.boxed_ty() {
return self.visit_indirection(state, ty, inner_ty, IndirectionKind::Box);
}
if def.is_phantom_data() {
return FfiPhantom(ty);
@@ -485,115 +700,29 @@ fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
)),
};
}
if !def.repr().c() && !def.repr().transparent() {
return FfiUnsafe {
ty,
reason: if def.is_struct() {
msg!("this struct has unspecified layout")
} else {
msg!("this union has unspecified layout")
},
help: if def.is_struct() {
Some(msg!(
"consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct"
))
} else {
Some(msg!(
"consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union"
))
},
};
}
if def.non_enum_variant().field_list_has_applicable_non_exhaustive() {
return FfiUnsafe {
ty,
reason: if def.is_struct() {
msg!("this struct is non-exhaustive")
} else {
msg!("this union is non-exhaustive")
},
help: None,
};
}
if def.non_enum_variant().fields.is_empty() {
return FfiUnsafe {
ty,
reason: if def.is_struct() {
msg!("this struct has no fields")
} else {
msg!("this union has no fields")
},
help: if def.is_struct() {
Some(msg!("consider adding a member to this struct"))
} else {
Some(msg!("consider adding a member to this union"))
},
};
}
self.check_variant_for_ffi(state, ty, def, def.non_enum_variant(), args)
}
AdtKind::Enum => {
if def.variants().is_empty() {
// Empty enums are okay... although sort of useless.
return FfiSafe;
}
// Check for a repr() attribute to specify the size of the
// discriminant.
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
{
// Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
if let Some(ty) =
repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty)
{
return self.visit_type(state, ty);
}
return FfiUnsafe {
ty,
reason: msg!("enum has no representation hint"),
help: Some(msg!(
"consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum"
)),
};
}
let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
// Check the contained variants.
let ret = def.variants().iter().try_for_each(|variant| {
check_non_exhaustive_variant(non_exhaustive, variant)
.map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
match self.check_variant_for_ffi(state, ty, def, variant, args) {
FfiSafe => ControlFlow::Continue(()),
r => ControlFlow::Break(r),
}
});
if let ControlFlow::Break(result) = ret {
return result;
}
FfiSafe
self.visit_struct_or_union(state, ty, def, args)
}
AdtKind::Enum => self.visit_enum(state, ty, def, args),
}
}
ty::Char => FfiUnsafe {
// Pattern types are just extra invariants on the type that you need to uphold,
// but only the base type is relevant for being representable in FFI.
// (note: this lint was written when pattern types could only be integers constrained to ranges)
ty::Pat(pat_ty, _) => self.visit_type(state, outer_ty, pat_ty),
// types which likely have a stable representation, if the target architecture defines those
// note: before rust 1.77, 128-bit ints were not FFI-safe on x86_64
ty::Int(..) | ty::Uint(..) | ty::Float(..) => FfiResult::FfiSafe,
ty::Bool => FfiResult::FfiSafe,
ty::Char => FfiResult::FfiUnsafe {
ty,
reason: msg!("the `char` type has no C equivalent"),
help: Some(msg!("consider using `u32` or `libc::wchar_t` instead")),
},
// It's just extra invariants on the type that you need to uphold,
// but only the base type is relevant for being representable in FFI.
ty::Pat(base, ..) => self.visit_type(state, base),
// Primitive types with a stable representation.
ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe,
ty::Slice(_) => FfiUnsafe {
ty,
reason: msg!("slices have no C equivalent"),
@@ -610,19 +739,21 @@ fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
help: Some(msg!("consider using `*const u8` and a length instead")),
},
ty::Tuple(..) => FfiUnsafe {
ty,
reason: msg!("tuples have unspecified layout"),
help: Some(msg!("consider using a struct instead")),
},
ty::Tuple(tuple) => {
// C functions can return void
let empty_and_safe = tuple.is_empty()
&& outer_ty.contains(OuterTyData::NO_OUTER_TY)
&& state.is_in_function_return();
ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
if {
(state.is_in_defined_function() || state.is_in_fnptr())
&& ty.is_sized(self.cx.tcx, self.cx.typing_env())
} =>
{
FfiSafe
if empty_and_safe {
FfiSafe
} else {
FfiUnsafe {
ty,
reason: msg!("tuples have unspecified layout"),
help: Some(msg!("consider using a struct instead")),
}
}
}
ty::RawPtr(ty, _)
@@ -634,9 +765,32 @@ fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
FfiSafe
}
ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.visit_type(state, ty),
ty::RawPtr(inner_ty, _) => {
return self.visit_indirection(state, ty, inner_ty, IndirectionKind::RawPtr);
}
ty::Ref(_, inner_ty, _) => {
return self.visit_indirection(state, ty, inner_ty, IndirectionKind::Ref);
}
ty::Array(inner_ty, _) => self.visit_type(state, inner_ty),
ty::Array(inner_ty, _) => {
if state.is_in_function()
&& outer_ty.contains(OuterTyData::NO_OUTER_TY)
// FIXME(ctypes): VVV-this-VVV shouldn't be the case
&& !outer_ty.contains(OuterTyData::NO_OUTER_TY_FNPTR)
{
// C doesn't really support passing arrays by value - the only way to pass an array by value
// is through a struct.
FfiResult::FfiUnsafe {
ty,
reason: msg!("passing raw arrays by value is not FFI-safe"),
help: Some(msg!("consider passing a pointer to the array")),
}
} else {
// let's allow phantoms to go through,
// since an array of 1-ZSTs is also a 1-ZST
self.visit_type(state, OuterTyData::from_ty(ty), inner_ty)
}
}
ty::FnPtr(sig_tys, hdr) => {
let sig = sig_tys.with(hdr);
@@ -652,22 +806,25 @@ fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
let sig = tcx.instantiate_bound_regions_with_erased(sig);
for arg in sig.inputs() {
match self.visit_type(VisitorState::ARGUMENT_TY_IN_FNPTR, *arg) {
match self.visit_type(
VisitorState::ARGUMENT_TY_IN_FNPTR,
OuterTyData::from_ty(ty),
*arg,
) {
FfiSafe => {}
r => return r,
}
}
let ret_ty = sig.output();
if ret_ty.is_unit() {
return FfiSafe;
}
self.visit_type(VisitorState::RETURN_TY_IN_FNPTR, ret_ty)
self.visit_type(VisitorState::RETURN_TY_IN_FNPTR, OuterTyData::from_ty(ty), ret_ty)
}
ty::Foreign(..) => FfiSafe,
ty::Never => FfiSafe,
// While opaque types are checked for earlier, if a projection in a struct field
// normalizes to an opaque type, then it will reach this branch.
ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
@@ -729,20 +886,6 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
})
}
/// Check if the type is array and emit an unsafe type lint.
fn check_for_array_ty(&mut self, ty: Ty<'tcx>) -> PartialFfiResult<'tcx> {
if let ty::Array(..) = ty.kind() {
Some(FfiResult::FfiUnsafe {
ty,
reason: msg!("passing raw arrays by value is not FFI-safe"),
help: Some(msg!("consider passing a pointer to the array")),
})
} else {
None
}
}
/// Determine the FFI-safety of a single (MIR) type, given the context of how it is used.
fn check_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
let ty = self
.cx
@@ -753,23 +896,7 @@ fn check_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
return res;
}
// C doesn't really support passing arrays by value - the only way to pass an array by value
// is through a struct. So, first test that the top level isn't an array, and then
// recursively check the types inside.
if state.is_in_function() {
if let Some(res) = self.check_for_array_ty(ty) {
return res;
}
}
// Don't report FFI errors for unit return types. This check exists here, and not in
// the caller (where it would make more sense) so that normalization has definitely
// happened.
if state.is_in_function_return() && ty.is_unit() {
return FfiResult::FfiSafe;
}
self.visit_type(state, ty)
self.visit_type(state, OuterTyData::NO_OUTER_TY, ty)
}
}
-6
View File
@@ -656,12 +656,6 @@ pub enum DeprecatedSinceKind {
pub enum AttributeLintKind {
UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
DocTestTakesList,
DocTestUnknown { name: Symbol },
DocTestLiteral,
AttrCrateLevelOnly,
DoNotRecommendDoesNotExpectArgs,
CrateTypeUnknown { span: Span, suggested: Option<Symbol> },
MalformedDoc,
ExpectedNoArgs,
ExpectedNameValue,
+1 -1
View File
@@ -1251,7 +1251,7 @@ fn force_delayed_owners_lowering(tcx: TyCtxt<'_>) {
tcx.ensure_done().lower_delayed_owner(id);
}
let (_, krate) = krate.delayed_resolver.steal();
let (_, krate, _) = krate.delayed_resolver.steal();
let prof = tcx.sess.prof.clone();
// Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
+12 -3
View File
@@ -16,7 +16,8 @@
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap, LocalModDefId};
use rustc_hir::definitions::PerParentDisambiguatorState;
use rustc_hir::*;
use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable, HashStable};
@@ -39,7 +40,11 @@ pub struct Crate<'hir> {
pub delayed_ids: FxIndexSet<LocalDefId>,
// The resolver and AST crate which are set in the end of the `hir_crate` query
// and then stolen and dropped in `force_delayed_owners_lowering`.
pub delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc<ast::Crate>)>,
pub delayed_resolver: Steal<(
ResolverAstLowering<'hir>,
Arc<ast::Crate>,
Arc<LocalDefIdMap<Steal<PerParentDisambiguatorState>>>,
)>,
// Only present when incr. comp. is enabled.
pub opt_hir_hash: Option<Fingerprint>,
}
@@ -48,7 +53,11 @@ impl<'hir> Crate<'hir> {
pub fn new(
owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
delayed_ids: FxIndexSet<LocalDefId>,
delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc<ast::Crate>)>,
delayed_resolver: Steal<(
ResolverAstLowering<'hir>,
Arc<ast::Crate>,
Arc<LocalDefIdMap<Steal<PerParentDisambiguatorState>>>,
)>,
opt_hir_hash: Option<Fingerprint>,
) -> Crate<'hir> {
Crate { owners, delayed_ids, delayed_resolver, opt_hir_hash }
+3 -3
View File
@@ -32,7 +32,7 @@
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, MultiSpan};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::definitions::{DefPathData, Definitions, Disambiguator};
use rustc_hir::definitions::{DefPathData, Definitions, PerParentDisambiguatorState};
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::lang_items::LangItem;
use rustc_hir::limit::Limit;
@@ -1399,7 +1399,7 @@ pub fn create_def(
name: Option<Symbol>,
def_kind: DefKind,
override_def_path_data: Option<DefPathData>,
disambiguator: &mut impl Disambiguator,
disambiguator: &mut PerParentDisambiguatorState,
) -> TyCtxtFeed<'tcx, LocalDefId> {
let feed =
self.tcx.create_def(parent, name, def_kind, override_def_path_data, disambiguator);
@@ -1417,7 +1417,7 @@ pub fn create_def(
name: Option<Symbol>,
def_kind: DefKind,
override_def_path_data: Option<DefPathData>,
disambiguator: &mut impl Disambiguator,
disambiguator: &mut PerParentDisambiguatorState,
) -> TyCtxtFeed<'tcx, LocalDefId> {
let data = override_def_path_data.unwrap_or_else(|| def_kind.def_path_data(name));
// The following call has the side effect of modifying the tables inside `definitions`.
@@ -166,10 +166,9 @@ fn variances_of(self, def_id: DefId) -> Self::VariancesOf {
fn opt_alias_variances(
self,
kind: impl Into<ty::AliasTermKind>,
def_id: DefId,
kind: impl Into<ty::AliasTermKind<'tcx>>,
) -> Option<&'tcx [ty::Variance]> {
self.opt_alias_variances(kind, def_id)
self.opt_alias_variances(kind)
}
fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
@@ -205,29 +204,27 @@ fn alias_ty_kind_from_def_id(self, def_id: DefId) -> ty::AliasTyKind<'tcx> {
}
}
fn alias_term_kind(self, alias: ty::AliasTerm<'tcx>) -> ty::AliasTermKind {
match self.def_kind(alias.def_id) {
fn alias_term_kind_from_def_id(self, def_id: DefId) -> ty::AliasTermKind<'tcx> {
match self.def_kind(def_id) {
DefKind::AssocTy => {
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
{
ty::AliasTermKind::InherentTy
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) {
ty::AliasTermKind::InherentTy { def_id }
} else {
ty::AliasTermKind::ProjectionTy
ty::AliasTermKind::ProjectionTy { def_id }
}
}
DefKind::AssocConst { .. } => {
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
{
ty::AliasTermKind::InherentConst
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) {
ty::AliasTermKind::InherentConst { def_id }
} else {
ty::AliasTermKind::ProjectionConst
ty::AliasTermKind::ProjectionConst { def_id }
}
}
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
DefKind::TyAlias => ty::AliasTermKind::FreeTy,
DefKind::Const { .. } => ty::AliasTermKind::FreeConst,
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy { def_id },
DefKind::TyAlias => ty::AliasTermKind::FreeTy { def_id },
DefKind::Const { .. } => ty::AliasTermKind::FreeConst { def_id },
DefKind::AnonConst | DefKind::Ctor(_, CtorKind::Const) => {
ty::AliasTermKind::UnevaluatedConst
ty::AliasTermKind::UnevaluatedConst { def_id }
}
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
}
+6 -6
View File
@@ -91,9 +91,9 @@
pub use self::opaque_types::OpaqueTypeKey;
pub use self::pattern::{Pattern, PatternKind};
pub use self::predicate::{
AliasTerm, ArgOutlivesPredicate, Clause, ClauseKind, CoercePredicate, ExistentialPredicate,
ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef,
HostEffectPredicate, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
AliasTerm, AliasTermKind, ArgOutlivesPredicate, Clause, ClauseKind, CoercePredicate,
ExistentialPredicate, ExistentialPredicateStableCmpExt, ExistentialProjection,
ExistentialTraitRef, HostEffectPredicate, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef,
PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate,
PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate,
@@ -227,7 +227,7 @@ pub struct ResolverAstLowering<'tcx> {
// Information about delegations which is used when handling recursive delegations
pub delegation_infos: LocalDefIdMap<DelegationInfo>,
pub per_parent_disambiguators: LocalDefIdMap<Steal<PerParentDisambiguatorState>>,
pub disambiguators: Steal<LocalDefIdMap<PerParentDisambiguatorState>>,
}
#[derive(Debug)]
@@ -607,14 +607,14 @@ pub fn into_arg(self) -> GenericArg<'tcx> {
}
}
pub fn to_alias_term(self) -> Option<AliasTerm<'tcx>> {
pub fn to_alias_term(self, tcx: TyCtxt<'tcx>) -> Option<AliasTerm<'tcx>> {
match self.kind() {
TermKind::Ty(ty) => match *ty.kind() {
ty::Alias(alias_ty) => Some(alias_ty.into()),
_ => None,
},
TermKind::Const(ct) => match ct.kind() {
ConstKind::Unevaluated(uv) => Some(uv.into()),
ConstKind::Unevaluated(uv) => Some(AliasTerm::from_unevaluated_const(tcx, uv)),
_ => None,
},
}
+3 -2
View File
@@ -9,6 +9,7 @@
pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>;
pub type AliasTerm<'tcx> = ir::AliasTerm<TyCtxt<'tcx>>;
pub type AliasTermKind<'tcx> = ir::AliasTermKind<TyCtxt<'tcx>>;
pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate<TyCtxt<'tcx>>;
pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate<TyCtxt<'tcx>>;
pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef<TyCtxt<'tcx>>;
@@ -642,7 +643,7 @@ mod size_asserts {
use super::*;
// tidy-alphabetical-start
static_assert_size!(PredicateKind<'_>, 32);
static_assert_size!(WithCachedTypeInfo<PredicateKind<'_>>, 56);
static_assert_size!(PredicateKind<'_>, 40);
static_assert_size!(WithCachedTypeInfo<PredicateKind<'_>>, 64);
// tidy-alphabetical-end
}
+12 -12
View File
@@ -1346,7 +1346,7 @@ fn pretty_print_inherent_projection(
&mut self,
alias_ty: ty::AliasTerm<'tcx>,
) -> Result<(), PrintError> {
let def_key = self.tcx().def_key(alias_ty.def_id);
let def_key = self.tcx().def_key(alias_ty.def_id());
self.print_path_with_generic_args(
|p| {
p.print_path_with_simple(
@@ -3158,22 +3158,22 @@ macro_rules! define_print_and_forward_display {
ty::AliasTerm<'tcx> {
match self.kind(p.tcx()) {
ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => p.pretty_print_inherent_projection(*self)?,
ty::AliasTermKind::ProjectionTy => {
ty::AliasTermKind::InherentTy {..} | ty::AliasTermKind::InherentConst {..} => p.pretty_print_inherent_projection(*self)?,
ty::AliasTermKind::ProjectionTy { def_id } => {
if !(p.should_print_verbose() || with_reduced_queries())
&& p.tcx().is_impl_trait_in_trait(self.def_id)
&& p.tcx().is_impl_trait_in_trait(def_id)
{
p.pretty_print_rpitit(self.def_id, self.args)?;
p.pretty_print_rpitit(def_id, self.args)?;
} else {
p.print_def_path(self.def_id, self.args)?;
p.print_def_path(def_id, self.args)?;
}
}
ty::AliasTermKind::FreeTy
| ty::AliasTermKind::FreeConst
| ty::AliasTermKind::OpaqueTy
| ty::AliasTermKind::UnevaluatedConst
| ty::AliasTermKind::ProjectionConst => {
p.print_def_path(self.def_id, self.args)?;
ty::AliasTermKind::FreeTy { def_id }
| ty::AliasTermKind::FreeConst { def_id }
| ty::AliasTermKind::OpaqueTy { def_id }
| ty::AliasTermKind::UnevaluatedConst { def_id }
| ty::AliasTermKind::ProjectionConst { def_id } => {
p.print_def_path(def_id, self.args)?;
}
}
}
+9 -10
View File
@@ -939,24 +939,23 @@ pub fn peel_off_free_alias_tys(self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
// its (un)captured regions.
pub fn opt_alias_variances(
self,
kind: impl Into<ty::AliasTermKind>,
def_id: DefId,
kind: impl Into<ty::AliasTermKind<'tcx>>,
) -> Option<&'tcx [ty::Variance]> {
match kind.into() {
ty::AliasTermKind::ProjectionTy => {
ty::AliasTermKind::ProjectionTy { def_id } => {
if self.is_impl_trait_in_trait(def_id) {
Some(self.variances_of(def_id))
} else {
None
}
}
ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)),
ty::AliasTermKind::InherentTy
| ty::AliasTermKind::InherentConst
| ty::AliasTermKind::FreeTy
| ty::AliasTermKind::FreeConst
| ty::AliasTermKind::UnevaluatedConst
| ty::AliasTermKind::ProjectionConst => None,
ty::AliasTermKind::OpaqueTy { def_id } => Some(self.variances_of(def_id)),
ty::AliasTermKind::InherentTy { .. }
| ty::AliasTermKind::InherentConst { .. }
| ty::AliasTermKind::FreeTy { .. }
| ty::AliasTermKind::FreeConst { .. }
| ty::AliasTermKind::UnevaluatedConst { .. }
| ty::AliasTermKind::ProjectionConst { .. } => None,
}
}
}
@@ -38,12 +38,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let mut any_replacement = false;
// Locals that participate in copy propagation either as a source or a destination.
let mut unified = DenseBitSet::new_empty(body.local_decls.len());
let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len());
for (local, &head) in ssa.copy_classes().iter_enumerated() {
if local != head {
any_replacement = true;
storage_to_remove.insert(head);
unified.insert(head);
unified.insert(local);
}
@@ -58,7 +56,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// only if the head might be uninitialized at that point, or if the local is borrowed
// (since we cannot easily determine when it's used).
let storage_to_remove = if tcx.sess.emit_lifetime_markers() {
storage_to_remove.clear();
let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len());
// If the local is borrowed, we cannot easily determine if it is used, so we have to remove the storage statements.
let borrowed_locals = ssa.borrowed_locals();
@@ -83,15 +81,16 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
storage_checker.visit_basic_block_data(bb, data);
}
storage_checker.storage_to_remove
Some(storage_checker.storage_to_remove)
} else {
// Remove the storage statements of all the head locals.
storage_to_remove
None
};
// If None, remove the storage statements of all the unified locals.
let storage_to_remove = storage_to_remove.as_ref().unwrap_or(&unified);
debug!(?storage_to_remove);
Replacer { tcx, copy_classes: ssa.copy_classes(), unified, storage_to_remove }
Replacer { tcx, copy_classes: ssa.copy_classes(), unified: &unified, storage_to_remove }
.visit_body_preserves_cfg(body);
crate::simplify::remove_unused_definitions(body);
@@ -106,8 +105,8 @@ fn is_required(&self) -> bool {
/// all occurrences of the key get replaced by the value.
struct Replacer<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
unified: DenseBitSet<Local>,
storage_to_remove: DenseBitSet<Local>,
unified: &'a DenseBitSet<Local>,
storage_to_remove: &'a DenseBitSet<Local>,
copy_classes: &'a IndexSlice<Local, Local>,
}
@@ -70,10 +70,10 @@
use rustc_abi::{FieldIdx, VariantIdx};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::unord::UnordMap;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::definitions::DisambiguatorState;
use rustc_hir::definitions::PerParentDisambiguatorState;
use rustc_hir::{self as hir};
use rustc_middle::bug;
use rustc_middle::hir::place::{Projection, ProjectionKind};
use rustc_middle::mir::visit::MutVisitor;
@@ -221,7 +221,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
None,
DefKind::SyntheticCoroutineBody,
None,
&mut DisambiguatorState::new(),
&mut PerParentDisambiguatorState::new(parent_def_id),
);
by_move_body.source =
mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id()));
+9 -8
View File
@@ -173,15 +173,16 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
storage_checker.visit_basic_block_data(bb, data);
}
storage_checker.storage_to_remove
Some(storage_checker.storage_to_remove)
} else {
// Remove the storage statements of all the reused locals.
state.reused_locals.clone()
None
};
// If None, remove the storage statements of all the reused locals.
let storage_to_remove = storage_to_remove.as_ref().unwrap_or(&state.reused_locals);
debug!(?storage_to_remove);
StorageRemover { tcx, reused_locals: state.reused_locals, storage_to_remove }
StorageRemover { tcx, reused_locals: &state.reused_locals, storage_to_remove }
.visit_body_preserves_cfg(body);
}
@@ -2058,13 +2059,13 @@ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Loca
}
}
struct StorageRemover<'tcx> {
struct StorageRemover<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
reused_locals: DenseBitSet<Local>,
storage_to_remove: DenseBitSet<Local>,
reused_locals: &'a DenseBitSet<Local>,
storage_to_remove: &'a DenseBitSet<Local>,
}
impl<'tcx> MutVisitor<'tcx> for StorageRemover<'tcx> {
impl<'a, 'tcx> MutVisitor<'tcx> for StorageRemover<'a, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@@ -109,6 +109,7 @@
use rustc_middle::bug;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
use rustc_middle::mir::StatementKind;
use rustc_middle::mono::{
CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, MonoItem, MonoItemData,
MonoItemPartitions, Visibility,
@@ -1334,7 +1335,21 @@ pub(crate) fn provide(providers: &mut Providers) {
| InstanceKind::DropGlue(..)
| InstanceKind::AsyncDropGlueCtorShim(..) => {
let mir = tcx.instance_mir(instance.def);
mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum()
mir.basic_blocks
.iter()
.map(|bb| {
bb.statements
.iter()
.filter_map(|stmt| match stmt.kind {
StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => {
None
}
_ => Some(stmt),
})
.count()
+ 1
})
.sum()
}
// Other compiler-generated shims size estimate: 1
_ => 1,
@@ -41,14 +41,14 @@ pub(super) fn compute_alias_relate_goal(
// `{type error}` if the alias still contains infer vars, so we also
// accept alias-relate goals where one of the terms is an error.
debug_assert!(
lhs.to_alias_term().is_some()
|| rhs.to_alias_term().is_some()
lhs.to_alias_term(self.cx()).is_some()
|| rhs.to_alias_term(self.cx()).is_some()
|| lhs.is_error()
|| rhs.is_error()
);
// Structurally normalize the lhs.
let lhs = if let Some(alias) = lhs.to_alias_term() {
let lhs = if let Some(alias) = lhs.to_alias_term(self.cx()) {
let term = self.next_term_infer_of_kind(lhs);
self.add_goal(
GoalSource::TypeRelating,
@@ -60,7 +60,7 @@ pub(super) fn compute_alias_relate_goal(
};
// Structurally normalize the rhs.
let rhs = if let Some(alias) = rhs.to_alias_term() {
let rhs = if let Some(alias) = rhs.to_alias_term(self.cx()) {
let term = self.next_term_infer_of_kind(rhs);
self.add_goal(
GoalSource::TypeRelating,
@@ -87,7 +87,7 @@ pub(super) fn compute_alias_relate_goal(
ty::AliasRelationDirection::Equate => ty::Invariant,
ty::AliasRelationDirection::Subtype => ty::Covariant,
};
match (lhs.to_alias_term(), rhs.to_alias_term()) {
match (lhs.to_alias_term(self.cx()), rhs.to_alias_term(self.cx())) {
(None, None) => {
self.relate(param_env, lhs, variance, rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
@@ -958,7 +958,7 @@ fn projection_may_match(
source_projection: ty::Binder<I, ty::ProjectionPredicate<I>>,
target_projection: ty::AliasTerm<I>,
) -> bool {
source_projection.item_def_id() == target_projection.def_id
source_projection.item_def_id() == target_projection.def_id()
&& self
.ecx
.probe(|_| ProbeKind::ProjectionCompatibility)
@@ -982,7 +982,7 @@ fn try_eagerly_replace_alias(
return Ok(None);
}
let Some(replacements) = self.mapping.get(&alias_term.def_id) else {
let Some(replacements) = self.mapping.get(&alias_term.def_id()) else {
return Ok(None);
};
@@ -964,8 +964,8 @@ pub(super) fn relate_rigid_alias_non_alias(
//
// Alternatively we could modify `Equate` for this case by adding another
// variant to `StructurallyRelateAliases`.
let identity_args = self.fresh_args_for_item(alias.def_id);
let rigid_ctor = ty::AliasTerm::new_from_args(cx, alias.def_id, identity_args);
let identity_args = self.fresh_args_for_item(alias.def_id());
let rigid_ctor = alias.with_args(cx, identity_args);
let ctor_term = rigid_ctor.to_term(cx);
let obligations = self.delegate.eq_structurally_relating_aliases(
param_env,
@@ -344,7 +344,7 @@ fn structurally_normalize_term(
param_env: I::ParamEnv,
term: I::Term,
) -> Result<I::Term, NoSolution> {
if let Some(_) = term.to_alias_term() {
if let Some(_) = term.to_alias_term(self.cx()) {
let normalized_term = self.next_term_infer_of_kind(term);
let alias_relate_goal = Goal::new(
self.cx(),
@@ -17,7 +17,7 @@ pub(super) fn normalize_anon_const(
if let Some(normalized_const) = self.evaluate_const(
goal.param_env,
ty::UnevaluatedConst::new(
goal.predicate.alias.def_id.try_into().unwrap(),
goal.predicate.alias.def_id().try_into().unwrap(),
goal.predicate.alias.args,
),
) {
@@ -24,16 +24,16 @@ pub(super) fn normalize_free_alias(
// Check where clauses
self.add_goals(
GoalSource::Misc,
cx.predicates_of(free_alias.def_id)
cx.predicates_of(free_alias.def_id())
.iter_instantiated(cx, free_alias.args)
.map(Unnormalized::skip_norm_wip)
.map(|pred| goal.with(cx, pred)),
);
let actual = if free_alias.kind(cx).is_type() {
cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args).skip_norm_wip().into()
cx.type_of(free_alias.def_id()).instantiate(cx, free_alias.args).skip_norm_wip().into()
} else {
cx.const_of_item(free_alias.def_id)
cx.const_of_item(free_alias.def_id())
.instantiate(cx, free_alias.args)
.skip_norm_wip()
.into()
@@ -22,7 +22,7 @@ pub(super) fn normalize_inherent_associated_term(
let cx = self.cx();
let inherent = goal.predicate.alias;
let impl_def_id = cx.parent(inherent.def_id);
let impl_def_id = cx.parent(inherent.def_id());
let impl_args = self.fresh_args_for_item(impl_def_id);
// Equate impl header and add impl where clauses
@@ -46,16 +46,19 @@ pub(super) fn normalize_inherent_associated_term(
// to be very careful when changing the impl where-clauses to be productive.
self.add_goals(
GoalSource::Misc,
cx.predicates_of(inherent.def_id)
cx.predicates_of(inherent.def_id())
.iter_instantiated(cx, inherent_args)
.map(Unnormalized::skip_norm_wip)
.map(|pred| goal.with(cx, pred)),
);
let normalized = if inherent.kind(cx).is_type() {
cx.type_of(inherent.def_id).instantiate(cx, inherent_args).skip_norm_wip().into()
cx.type_of(inherent.def_id()).instantiate(cx, inherent_args).skip_norm_wip().into()
} else {
cx.const_of_item(inherent.def_id).instantiate(cx, inherent_args).skip_norm_wip().into()
cx.const_of_item(inherent.def_id())
.instantiate(cx, inherent_args)
.skip_norm_wip()
.into()
};
self.instantiate_normalizes_to_term(goal, normalized);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
@@ -34,7 +34,7 @@ pub(super) fn compute_normalizes_to_goal(
debug_assert!(self.term_is_fully_unconstrained(goal));
let cx = self.cx();
match goal.predicate.alias.kind(cx) {
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
ty::AliasTermKind::ProjectionTy { .. } | ty::AliasTermKind::ProjectionConst { .. } => {
let trait_ref = goal.predicate.alias.trait_ref(cx);
let (_, proven_via) =
self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
@@ -85,14 +85,14 @@ pub(super) fn compute_normalizes_to_goal(
},
)
}
ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => {
ty::AliasTermKind::InherentTy { .. } | ty::AliasTermKind::InherentConst { .. } => {
self.normalize_inherent_associated_term(goal)
}
ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal),
ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => {
ty::AliasTermKind::OpaqueTy { .. } => self.normalize_opaque_type(goal),
ty::AliasTermKind::FreeTy { .. } | ty::AliasTermKind::FreeConst { .. } => {
self.normalize_free_alias(goal)
}
ty::AliasTermKind::UnevaluatedConst => self.normalize_anon_const(goal),
ty::AliasTermKind::UnevaluatedConst { .. } => self.normalize_anon_const(goal),
}
}
@@ -268,8 +268,8 @@ fn consider_impl_candidate(
let error_response = |ecx: &mut EvalCtxt<'_, D>, guar| {
let error_term = match goal.predicate.alias.kind(cx) {
ty::AliasTermKind::ProjectionTy => Ty::new_error(cx, guar).into(),
ty::AliasTermKind::ProjectionConst => Const::new_error(cx, guar).into(),
ty::AliasTermKind::ProjectionTy { .. } => Ty::new_error(cx, guar).into(),
ty::AliasTermKind::ProjectionConst { .. } => Const::new_error(cx, guar).into(),
kind => panic!("expected projection, found {kind:?}"),
};
ecx.instantiate_normalizes_to_term(goal, error_term);
@@ -384,10 +384,10 @@ fn consider_impl_candidate(
// Finally we construct the actual value of the associated type.
let term = match goal.predicate.alias.kind(cx) {
ty::AliasTermKind::ProjectionTy => {
ty::AliasTermKind::ProjectionTy { .. } => {
cx.type_of(target_item_def_id).map_bound(|ty| ty.into())
}
ty::AliasTermKind::ProjectionConst => {
ty::AliasTermKind::ProjectionConst { .. } => {
cx.const_of_item(target_item_def_id).map_bound(|ct| ct.into())
}
kind => panic!("expected projection, found {kind:?}"),
@@ -472,7 +472,7 @@ fn consider_builtin_fn_trait_candidates(
let pred = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new(
cx,
goal.predicate.def_id(),
cx.alias_term_kind_from_def_id(goal.predicate.def_id()),
[goal.predicate.self_ty(), inputs],
),
term: output.into(),
@@ -526,7 +526,7 @@ fn consider_builtin_async_fn_trait_candidates(
(
ty::AliasTerm::new(
cx,
goal.predicate.def_id(),
cx.alias_term_kind_from_def_id(goal.predicate.def_id()),
[goal.predicate.self_ty(), tupled_inputs_ty],
),
output_coroutine_ty.into(),
@@ -535,7 +535,7 @@ fn consider_builtin_async_fn_trait_candidates(
(
ty::AliasTerm::new(
cx,
goal.predicate.def_id(),
cx.alias_term_kind_from_def_id(goal.predicate.def_id()),
[
I::GenericArg::from(goal.predicate.self_ty()),
tupled_inputs_ty.into(),
@@ -548,7 +548,7 @@ fn consider_builtin_async_fn_trait_candidates(
(
ty::AliasTerm::new(
cx,
goal.predicate.def_id(),
cx.alias_term_kind_from_def_id(goal.predicate.def_id()),
[goal.predicate.self_ty(), tupled_inputs_ty],
),
coroutine_return_ty.into(),
@@ -746,7 +746,11 @@ fn consider_builtin_future_candidate(
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
goal,
ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new(ecx.cx(), goal.predicate.def_id(), [self_ty]),
projection_term: ty::AliasTerm::new(
ecx.cx(),
cx.alias_term_kind_from_def_id(goal.predicate.def_id()),
[self_ty],
),
term,
}
.upcast(cx),
@@ -778,7 +782,11 @@ fn consider_builtin_iterator_candidate(
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
goal,
ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new(ecx.cx(), goal.predicate.def_id(), [self_ty]),
projection_term: ty::AliasTerm::new(
ecx.cx(),
cx.alias_term_kind_from_def_id(goal.predicate.def_id()),
[self_ty],
),
term,
}
.upcast(cx),
@@ -863,7 +871,7 @@ fn consider_builtin_coroutine_candidate(
ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new(
ecx.cx(),
goal.predicate.def_id(),
cx.alias_term_kind_from_def_id(goal.predicate.def_id()),
[self_ty, coroutine.resume_ty()],
),
term,
@@ -26,7 +26,7 @@ pub(super) fn normalize_opaque_type(
// An impossible opaque type bound is the only way this goal will fail
// e.g. assigning `impl Copy := NotCopy`
self.add_item_bounds_for_hidden_type(
opaque_ty.def_id,
opaque_ty.def_id(),
opaque_ty.args,
goal.param_env,
expected,
@@ -43,7 +43,7 @@ pub(super) fn normalize_opaque_type(
}
| TypingMode::Borrowck { defining_opaque_types } => {
let Some(def_id) = opaque_ty
.def_id
.def_id()
.as_local()
.filter(|&def_id| defining_opaque_types.contains(&def_id))
else {
@@ -110,7 +110,7 @@ pub(super) fn normalize_opaque_type(
}
TypingMode::PostBorrowckAnalysis { defined_opaque_types } => {
let Some(def_id) = opaque_ty
.def_id
.def_id()
.as_local()
.filter(|&def_id| defined_opaque_types.contains(&def_id))
else {
@@ -133,7 +133,7 @@ pub(super) fn normalize_opaque_type(
TypingMode::PostAnalysis => {
// FIXME: Add an assertion that opaque type storage is empty.
let actual =
cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args).skip_norm_wip();
cx.type_of(opaque_ty.def_id()).instantiate(cx, opaque_ty.args).skip_norm_wip();
self.eq(goal.param_env, expected, actual)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
+17 -111
View File
@@ -51,31 +51,9 @@
use crate::errors;
#[derive(Diagnostic)]
#[diag("`#[diagnostic::on_unimplemented]` can only be applied to trait definitions")]
struct DiagnosticOnUnimplementedOnlyForTraits;
#[derive(Diagnostic)]
#[diag("`#[diagnostic::on_const]` can only be applied to trait impls")]
struct DiagnosticOnConstOnlyForTraitImpls {
#[label("not a trait impl")]
item_span: Span,
}
#[derive(Diagnostic)]
#[diag("`#[diagnostic::on_const]` can only be applied to non-const trait impls")]
#[diag("`#[diagnostic::on_const]` can only be applied to non-const trait implementations")]
struct DiagnosticOnConstOnlyForNonConstTraitImpls {
#[label("this is a const trait impl")]
item_span: Span,
}
#[derive(Diagnostic)]
#[diag("`#[diagnostic::on_move]` can only be applied to enums, structs or unions")]
struct DiagnosticOnMoveOnlyForAdt;
#[derive(Diagnostic)]
#[diag("`#[diagnostic::on_unknown]` can only be applied to `use` statements")]
struct DiagnosticOnUnknownOnlyForImports {
#[label("not an import")]
#[label("this is a const trait implementation")]
item_span: Span,
}
@@ -221,12 +199,10 @@ fn check_attributes(
Attribute::Parsed(AttributeKind::RustcMustImplementOneOf { attr_span, fn_names }) => {
self.check_rustc_must_implement_one_of(*attr_span, fn_names, hir_id,target)
},
Attribute::Parsed(AttributeKind::DoNotRecommend{attr_span}) => {self.check_do_not_recommend(*attr_span, hir_id, target, item)},
Attribute::Parsed(AttributeKind::OnUnimplemented{span, directive}) => {self.check_diagnostic_on_unimplemented(*span, hir_id, target,directive.as_deref())},
Attribute::Parsed(AttributeKind::OnUnknown { span, .. }) => { self.check_diagnostic_on_unknown(*span, hir_id, target) },
Attribute::Parsed(AttributeKind::OnUnimplemented{directive,..}) => {self.check_diagnostic_on_unimplemented(hir_id, directive.as_deref())},
Attribute::Parsed(AttributeKind::OnConst{span, ..}) => {self.check_diagnostic_on_const(*span, hir_id, target, item)}
Attribute::Parsed(AttributeKind::OnMove { span, directive }) => {
self.check_diagnostic_on_move(*span, hir_id, target, directive.as_deref())
Attribute::Parsed(AttributeKind::OnMove { directive , .. }) => {
self.check_diagnostic_on_move(hir_id, directive.as_deref())
},
Attribute::Parsed(
// tidy-alphabetical-start
@@ -245,6 +221,7 @@ fn check_attributes(
| AttributeKind::CustomMir(..)
| AttributeKind::DebuggerVisualizer(..)
| AttributeKind::DefaultLibAllocator
| AttributeKind::DoNotRecommend {..}
// `#[doc]` is actually a lot more than just doc comments, so is checked below
| AttributeKind::DocComment {..}
| AttributeKind::EiiDeclaration { .. }
@@ -275,6 +252,7 @@ fn check_attributes(
| AttributeKind::NoMain
| AttributeKind::NoMangle(..)
| AttributeKind::NoStd { .. }
| AttributeKind::OnUnknown { .. }
| AttributeKind::Optimize(..)
| AttributeKind::PanicRuntime
| AttributeKind::PatchableFunctionEntry { .. }
@@ -512,47 +490,8 @@ fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) {
}
}
/// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl
fn check_do_not_recommend(
&self,
attr_span: Span,
hir_id: HirId,
target: Target,
item: Option<ItemLike<'_>>,
) {
if !matches!(target, Target::Impl { .. })
|| matches!(
item,
Some(ItemLike::Item(hir::Item { kind: hir::ItemKind::Impl(_impl),.. }))
if _impl.of_trait.is_none()
)
{
self.tcx.emit_node_span_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
hir_id,
attr_span,
errors::IncorrectDoNotRecommendLocation,
);
}
}
/// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
fn check_diagnostic_on_unimplemented(
&self,
attr_span: Span,
hir_id: HirId,
target: Target,
directive: Option<&Directive>,
) {
if !matches!(target, Target::Trait) {
self.tcx.emit_node_span_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
hir_id,
attr_span,
DiagnosticOnUnimplementedOnlyForTraits,
);
}
/// Checks use of generic formatting parameters in `#[diagnostic::on_unimplemented]`
fn check_diagnostic_on_unimplemented(&self, hir_id: HirId, directive: Option<&Directive>) {
if let Some(directive) = directive {
if let Node::Item(Item {
kind: ItemKind::Trait(_, _, _, _, trait_name, generics, _, _),
@@ -587,7 +526,7 @@ fn check_diagnostic_on_unimplemented(
}
}
/// Checks if `#[diagnostic::on_const]` is applied to a trait impl
/// Checks if `#[diagnostic::on_const]` is applied to a on-const trait impl
fn check_diagnostic_on_const(
&self,
attr_span: Span,
@@ -595,6 +534,8 @@ fn check_diagnostic_on_const(
target: Target,
item: Option<ItemLike<'_>>,
) {
// We only check the non-constness here. A diagnostic for use
// on not-trait impl items is issued during attribute parsing.
if target == (Target::Impl { of_trait: true }) {
match item.unwrap() {
ItemLike::Item(it) => match it.expect_impl().constness {
@@ -613,35 +554,13 @@ fn check_diagnostic_on_const(
ItemLike::ForeignItem => {}
}
}
let item_span = self.tcx.hir_span(hir_id);
self.tcx.emit_node_span_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
hir_id,
attr_span,
DiagnosticOnConstOnlyForTraitImpls { item_span },
);
// We don't check the validity of generic args here...whose generics would that be, anyway?
// The traits' or the impls'?
// FIXME(#155570) Can we do something with generic args here?
// regardless, we don't check the validity of generic args here
// ...whose generics would that be, anyway? The traits' or the impls'?
}
/// Checks if `#[diagnostic::on_move]` is applied to an ADT definition
fn check_diagnostic_on_move(
&self,
attr_span: Span,
hir_id: HirId,
target: Target,
directive: Option<&Directive>,
) {
if !matches!(target, Target::Enum | Target::Struct | Target::Union) {
self.tcx.emit_node_span_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
hir_id,
attr_span,
DiagnosticOnMoveOnlyForAdt,
);
}
/// Checks use of generic formatting parameters in `#[diagnostic::on_move]`
fn check_diagnostic_on_move(&self, hir_id: HirId, directive: Option<&Directive>) {
if let Some(directive) = directive {
if let Node::Item(Item {
kind:
@@ -675,19 +594,6 @@ fn check_diagnostic_on_move(
}
}
/// Checks if `#[diagnostic::on_unknown]` is applied to a trait impl
fn check_diagnostic_on_unknown(&self, attr_span: Span, hir_id: HirId, target: Target) {
if !matches!(target, Target::Use) {
let item_span = self.tcx.hir_span(hir_id);
self.tcx.emit_node_span_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
hir_id,
attr_span,
DiagnosticOnUnknownOnlyForImports { item_span },
);
}
}
/// Checks if an `#[inline]` is applied to a function or a closure.
fn check_inline(&self, hir_id: HirId, attr_span: Span, kind: &InlineAttr, target: Target) {
match target {
+127 -35
View File
@@ -8,7 +8,7 @@
use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
use rustc_abi::FieldIdx;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
@@ -75,11 +75,46 @@ enum ComesFromAllowExpect {
No,
}
/// Carries both the propagated `allow/expect` context and the current item's
/// own `allow/expect` status.
///
/// For example:
///
/// ```rust
/// #[expect(dead_code)]
/// fn root() { middle() }
///
/// fn middle() { leaf() }
///
/// #[expect(dead_code)]
/// fn leaf() {}
/// ```
///
/// The seed for `root` starts as `propagated = Yes, own = Yes`.
///
/// When `root` reaches `middle`, the propagated context stays `Yes`, but
/// `middle` itself does not have `#[allow(dead_code)]` or `#[expect(dead_code)]`,
/// so its work item becomes `propagated = Yes, own = No`.
///
/// When `middle` reaches `leaf`, that same propagated `Yes` context is preserved,
/// and since `leaf` itself has `#[expect(dead_code)]`, its work item becomes
/// `propagated = Yes, own = Yes`.
///
/// In general, `propagated` controls whether descendants are still explored
/// under an `allow/expect` context, while `own` controls whether the current
/// item itself should be excluded from `live_symbols`.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
struct WorkItem {
id: LocalDefId,
propagated: ComesFromAllowExpect,
own: ComesFromAllowExpect,
}
struct MarkSymbolVisitor<'tcx> {
worklist: Vec<(LocalDefId, ComesFromAllowExpect)>,
worklist: Vec<WorkItem>,
tcx: TyCtxt<'tcx>,
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
scanned: LocalDefIdSet,
scanned: FxHashSet<(LocalDefId, ComesFromAllowExpect)>,
live_symbols: LocalDefIdSet,
repr_unconditionally_treats_fields_as_live: bool,
repr_has_repr_simd: bool,
@@ -89,6 +124,7 @@ struct MarkSymbolVisitor<'tcx> {
// and the span of their respective impl (i.e., part of the derive
// macro)
ignored_derived_traits: LocalDefIdMap<FxIndexSet<DefId>>,
propagated_comes_from_allow_expect: ComesFromAllowExpect,
}
impl<'tcx> MarkSymbolVisitor<'tcx> {
@@ -101,19 +137,45 @@ fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
.expect("`MarkSymbolVisitor::typeck_results` called outside of body")
}
/// Returns whether `def_id` itself should be treated as coming from
/// `#[allow(dead_code)]` or `#[expect(dead_code)]` in the current
/// propagated work-item context.
fn own_comes_from_allow_expect(&self, def_id: LocalDefId) -> ComesFromAllowExpect {
if self.propagated_comes_from_allow_expect == ComesFromAllowExpect::Yes
&& let Some(ComesFromAllowExpect::Yes) =
has_allow_dead_code_or_lang_attr(self.tcx, def_id)
{
ComesFromAllowExpect::Yes
} else {
ComesFromAllowExpect::No
}
}
fn check_def_id(&mut self, def_id: DefId) {
if let Some(def_id) = def_id.as_local() {
let own_comes_from_allow_expect = self.own_comes_from_allow_expect(def_id);
if should_explore(self.tcx, def_id) {
self.worklist.push((def_id, ComesFromAllowExpect::No));
self.worklist.push(WorkItem {
id: def_id,
propagated: self.propagated_comes_from_allow_expect,
own: own_comes_from_allow_expect,
});
}
if own_comes_from_allow_expect == ComesFromAllowExpect::No {
self.live_symbols.insert(def_id);
}
self.live_symbols.insert(def_id);
}
}
fn insert_def_id(&mut self, def_id: DefId) {
if let Some(def_id) = def_id.as_local() {
debug_assert!(!should_explore(self.tcx, def_id));
self.live_symbols.insert(def_id);
if self.own_comes_from_allow_expect(def_id) == ComesFromAllowExpect::No {
self.live_symbols.insert(def_id);
}
}
}
@@ -323,7 +385,8 @@ fn handle_offset_of(&mut self, expr: &'tcx hir::Expr<'tcx>) {
fn mark_live_symbols(&mut self) -> <MarkSymbolVisitor<'tcx> as Visitor<'tcx>>::Result {
while let Some(work) = self.worklist.pop() {
let (mut id, comes_from_allow_expect) = work;
let WorkItem { mut id, propagated, own } = work;
self.propagated_comes_from_allow_expect = propagated;
// in the case of tuple struct constructors we want to check the item,
// not the generated tuple struct constructor function
@@ -352,14 +415,14 @@ fn mark_live_symbols(&mut self) -> <MarkSymbolVisitor<'tcx> as Visitor<'tcx>>::R
// this "duplication" is essential as otherwise a function with `#[expect]`
// called from a `pub fn` may be falsely reported as not live, falsely
// triggering the `unfulfilled_lint_expectations` lint.
match comes_from_allow_expect {
match own {
ComesFromAllowExpect::Yes => {}
ComesFromAllowExpect::No => {
self.live_symbols.insert(id);
}
}
if !self.scanned.insert(id) {
if !self.scanned.insert((id, propagated)) {
continue;
}
@@ -694,7 +757,11 @@ fn visit_trait_ref(&mut self, t: &'tcx hir::TraitRef<'tcx>) -> Self::Result {
)
.and_then(|item| item.def_id.as_local())
{
self.worklist.push((local_def_id, ComesFromAllowExpect::No));
self.worklist.push(WorkItem {
id: local_def_id,
propagated: ComesFromAllowExpect::No,
own: ComesFromAllowExpect::No,
});
}
}
}
@@ -752,23 +819,27 @@ fn has_used_like_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
fn maybe_record_as_seed<'tcx>(
tcx: TyCtxt<'tcx>,
owner_id: hir::OwnerId,
worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>,
worklist: &mut Vec<WorkItem>,
unsolved_items: &mut Vec<LocalDefId>,
) {
let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, owner_id.def_id);
if let Some(comes_from_allow) = allow_dead_code {
worklist.push((owner_id.def_id, comes_from_allow));
worklist.push(WorkItem {
id: owner_id.def_id,
propagated: comes_from_allow,
own: comes_from_allow,
});
}
match tcx.def_kind(owner_id) {
DefKind::Enum => {
if let Some(comes_from_allow) = allow_dead_code {
let adt = tcx.adt_def(owner_id);
worklist.extend(
adt.variants()
.iter()
.map(|variant| (variant.def_id.expect_local(), comes_from_allow)),
);
worklist.extend(adt.variants().iter().map(|variant| WorkItem {
id: variant.def_id.expect_local(),
propagated: comes_from_allow,
own: comes_from_allow,
}));
}
}
DefKind::AssocFn | DefKind::AssocConst { .. } | DefKind::AssocTy => {
@@ -783,7 +854,11 @@ fn maybe_record_as_seed<'tcx>(
&& let Some(comes_from_allow) =
has_allow_dead_code_or_lang_attr(tcx, trait_item_local_def_id)
{
worklist.push((owner_id.def_id, comes_from_allow));
worklist.push(WorkItem {
id: owner_id.def_id,
propagated: comes_from_allow,
own: comes_from_allow,
});
}
// We only care about associated items of traits,
@@ -804,7 +879,11 @@ fn maybe_record_as_seed<'tcx>(
&& let Some(comes_from_allow) =
has_allow_dead_code_or_lang_attr(tcx, trait_def_id)
{
worklist.push((owner_id.def_id, comes_from_allow));
worklist.push(WorkItem {
id: owner_id.def_id,
propagated: comes_from_allow,
own: comes_from_allow,
});
}
unsolved_items.push(owner_id.def_id);
@@ -812,38 +891,48 @@ fn maybe_record_as_seed<'tcx>(
}
DefKind::GlobalAsm => {
// global_asm! is always live.
worklist.push((owner_id.def_id, ComesFromAllowExpect::No));
worklist.push(WorkItem {
id: owner_id.def_id,
propagated: ComesFromAllowExpect::No,
own: ComesFromAllowExpect::No,
});
}
DefKind::Const { .. } => {
if tcx.item_name(owner_id.def_id) == kw::Underscore {
// `const _` is always live, as that syntax only exists for the side effects
// of type checking and evaluating the constant expression, and marking them
// as dead code would defeat that purpose.
worklist.push((owner_id.def_id, ComesFromAllowExpect::No));
worklist.push(WorkItem {
id: owner_id.def_id,
propagated: ComesFromAllowExpect::No,
own: ComesFromAllowExpect::No,
});
}
}
_ => {}
}
}
fn create_and_seed_worklist(
tcx: TyCtxt<'_>,
) -> (Vec<(LocalDefId, ComesFromAllowExpect)>, Vec<LocalDefId>) {
fn create_and_seed_worklist(tcx: TyCtxt<'_>) -> (Vec<WorkItem>, Vec<LocalDefId>) {
let effective_visibilities = &tcx.effective_visibilities(());
let mut unsolved_impl_item = Vec::new();
let mut worklist = effective_visibilities
.iter()
.filter_map(|(&id, effective_vis)| {
effective_vis
.is_public_at_level(Level::Reachable)
.then_some(id)
.map(|id| (id, ComesFromAllowExpect::No))
effective_vis.is_public_at_level(Level::Reachable).then_some(id).map(|id| WorkItem {
id,
propagated: ComesFromAllowExpect::No,
own: ComesFromAllowExpect::No,
})
})
// Seed entry point
.chain(
tcx.entry_fn(())
.and_then(|(def_id, _)| def_id.as_local().map(|id| (id, ComesFromAllowExpect::No))),
)
.chain(tcx.entry_fn(()).and_then(|(def_id, _)| {
def_id.as_local().map(|id| WorkItem {
id,
propagated: ComesFromAllowExpect::No,
own: ComesFromAllowExpect::No,
})
}))
.collect::<Vec<_>>();
let crate_items = tcx.hir_crate_items(());
@@ -870,6 +959,7 @@ fn live_symbols_and_ignored_derived_traits(
in_pat: false,
ignore_variant_stack: vec![],
ignored_derived_traits: Default::default(),
propagated_comes_from_allow_expect: ComesFromAllowExpect::No,
};
if let ControlFlow::Break(guar) = symbol_visitor.mark_live_symbols() {
return Err(guar);
@@ -884,9 +974,11 @@ fn live_symbols_and_ignored_derived_traits(
.collect();
while !items_to_check.is_empty() {
symbol_visitor
.worklist
.extend(items_to_check.drain(..).map(|id| (id, ComesFromAllowExpect::No)));
symbol_visitor.worklist.extend(items_to_check.drain(..).map(|id| WorkItem {
id,
propagated: ComesFromAllowExpect::No,
own: ComesFromAllowExpect::No,
}));
if let ControlFlow::Break(guar) = symbol_visitor.mark_live_symbols() {
return Err(guar);
}
-4
View File
@@ -13,10 +13,6 @@
use crate::check_attr::ProcMacroKind;
use crate::lang_items::Duplicate;
#[derive(Diagnostic)]
#[diag("`#[diagnostic::do_not_recommend]` can only be placed on trait implementations")]
pub(crate) struct IncorrectDoNotRecommendLocation;
#[derive(Diagnostic)]
#[diag("`#[loop_match]` should be applied to a loop")]
pub(crate) struct LoopMatchAttr {
@@ -46,8 +46,11 @@ fn stable<'cx>(
tables: &mut Tables<'cx, BridgeTys>,
cx: &CompilerCtxt<'cx, BridgeTys>,
) -> Self::T {
let ty::AliasTerm { args, def_id, .. } = self;
crate::ty::AliasTerm { def_id: tables.alias_def(*def_id), args: args.stable(tables, cx) }
let ty::AliasTerm { args, kind, .. } = self;
crate::ty::AliasTerm {
def_id: tables.alias_def(kind.def_id()),
args: args.stable(tables, cx),
}
}
}
+35 -11
View File
@@ -979,23 +979,47 @@ pub(crate) fn into_struct_error(
.source_map()
.span_extend_to_prev_str(ident.span, current, true, false);
let ((with, with_label), without) = match sp {
let (with, with_label, without) = match sp {
Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => {
let sp = sp
.with_lo(BytePos(sp.lo().0 - (current.len() as u32)))
.until(ident.span);
(
(Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
span: sp,
suggestion,
current,
type_span,
}), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})),
None,
)
// Only suggest replacing the binding keyword if this is a simple
// binding.
//
// Note: this approach still incorrectly suggests for irrefutable
// patterns like `if let x = 1 { const { x } }`, since the text
// between `let` and the identifier is just whitespace.
// See tests/ui/consts/non-const-value-in-const-irrefutable-pat-binding.rs
let is_simple_binding =
self.tcx.sess.source_map().span_to_snippet(sp).is_ok_and(|snippet| {
let after_keyword = snippet[current.len()..].trim();
after_keyword.is_empty() || after_keyword == "mut"
});
if is_simple_binding {
(
Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
span: sp,
suggestion,
current,
type_span,
}),
Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion { span }),
None,
)
} else {
(
None,
Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion { span }),
None,
)
}
}
_ => (
(None, None),
None,
None,
Some(errs::AttemptToUseNonConstantValueInConstantWithoutSuggestion {
ident_span: ident.span,
suggestion,
+44 -16
View File
@@ -1797,6 +1797,7 @@ fn record_segment_res<'r, 'ra, 'tcx>(
"too many leading `super` keywords".to_string(),
"there are too many leading `super` keywords".to_string(),
None,
None,
)
},
);
@@ -1863,7 +1864,7 @@ fn record_segment_res<'r, 'ra, 'tcx>(
"can only be used in path start position".to_string(),
)
};
(message, label, None)
(message, label, None, None)
},
);
}
@@ -1977,10 +1978,28 @@ fn record_segment_res<'r, 'ra, 'tcx>(
module_had_parse_errors,
module,
|| {
let import_inherent_item_error_flag =
self.tcx.features().import_trait_associated_functions()
&& matches!(
res,
Res::Def(
DefKind::Struct
| DefKind::Enum
| DefKind::Union
| DefKind::ForeignTy,
_
)
);
// Show a different error message for items that can have associated items.
let label = format!(
"`{ident}` is {} {}, not a module",
"`{ident}` is {} {}, not a module{}",
res.article(),
res.descr()
res.descr(),
if import_inherent_item_error_flag {
" or a trait"
} else {
""
}
);
let scope = match &path[..segment_idx] {
[.., prev] => {
@@ -1995,7 +2014,14 @@ fn record_segment_res<'r, 'ra, 'tcx>(
// FIXME: reword, as the reason we expected a module is because of
// the following path segment.
let message = format!("cannot find module `{ident}` in {scope}");
(message, label, None)
let note = if import_inherent_item_error_flag {
Some(
"cannot import inherent associated items, only trait associated items".to_string(),
)
} else {
None
};
(message, label, None, note)
},
);
}
@@ -2020,18 +2046,20 @@ fn record_segment_res<'r, 'ra, 'tcx>(
module_had_parse_errors,
module,
|| {
this.get_mut().report_path_resolution_error(
path,
opt_ns,
parent_scope,
ribs,
ignore_decl,
ignore_import,
module,
segment_idx,
ident,
diag_metadata,
)
let (message, label, suggestion) =
this.get_mut().report_path_resolution_error(
path,
opt_ns,
parent_scope,
ribs,
ignore_decl,
ignore_import,
module,
segment_idx,
ident,
diag_metadata,
);
(message, label, suggestion, None)
},
);
}
+17 -1
View File
@@ -1134,6 +1134,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
module,
error_implied_by_parse_error: _,
message,
note: _,
} => {
if no_ambiguity {
if !self.issue_145575_hack_applied {
@@ -1159,6 +1160,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
suggestion,
module,
segment_name,
note,
..
} => {
if no_ambiguity {
@@ -1190,7 +1192,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
None => UnresolvedImportError {
span,
label: Some(label),
note: None,
note,
suggestion,
candidates: None,
segment: Some(segment_name),
@@ -1420,6 +1422,20 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
_ => (lev_suggestion, None),
};
// If importing of trait asscoiated items is enabled, an also find an
// `Enum`, then note that inherent associated items cannot be imported.
let note = if self.tcx.features().import_trait_associated_functions()
&& let PathResult::Module(ModuleOrUniformRoot::Module(m)) = path_res
&& let Some(Res::Def(DefKind::Enum, _)) = m.res()
{
note.or(Some(
"cannot import inherent associated items, only trait associated items"
.to_string(),
))
} else {
note
};
let label = match module {
ModuleOrUniformRoot::Module(module) => {
let module_str = module_to_string(module);
+1
View File
@@ -4979,6 +4979,7 @@ fn resolve_qpath(
segment_name,
error_implied_by_parse_error: _,
message,
note: _,
} => {
return Err(respan(
span,
+18 -19
View File
@@ -57,7 +57,7 @@
PerNS,
};
use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap};
use rustc_hir::definitions::PerParentDisambiguatorState;
use rustc_hir::definitions::{PerParentDisambiguatorState, PerParentDisambiguatorsMap};
use rustc_hir::{PrimTy, TraitCandidate, find_attr};
use rustc_index::bit_set::DenseBitSet;
use rustc_metadata::creader::CStore;
@@ -481,6 +481,7 @@ enum PathResult<'ra> {
segment_name: Symbol,
error_implied_by_parse_error: bool,
message: String,
note: Option<String>,
},
}
@@ -491,13 +492,18 @@ fn failed(
finalize: bool,
error_implied_by_parse_error: bool,
module: Option<ModuleOrUniformRoot<'ra>>,
label_and_suggestion: impl FnOnce() -> (String, String, Option<Suggestion>),
label_and_suggestion_and_note: impl FnOnce() -> (
String,
String,
Option<Suggestion>,
Option<String>,
),
) -> PathResult<'ra> {
let (message, label, suggestion) = if finalize {
label_and_suggestion()
let (message, label, suggestion, note) = if finalize {
label_and_suggestion_and_note()
} else {
// FIXME: this output isn't actually present in the test suite.
(format!("cannot find `{ident}` in this scope"), String::new(), None)
(format!("cannot find `{ident}` in this scope"), String::new(), None, None)
};
PathResult::Failed {
span: ident.span,
@@ -508,6 +514,7 @@ fn failed(
module,
error_implied_by_parse_error,
message,
note,
}
}
}
@@ -1417,7 +1424,7 @@ pub struct Resolver<'ra, 'tcx> {
node_id_to_def_id: NodeMap<Feed<'tcx, LocalDefId>>,
per_parent_disambiguators: LocalDefIdMap<PerParentDisambiguatorState>,
disambiguators: LocalDefIdMap<PerParentDisambiguatorState>,
/// Indices of unnamed struct or variant fields with unresolved attributes.
placeholder_field_indices: FxHashMap<NodeId, usize> = default::fx_hash_map(),
@@ -1620,14 +1627,10 @@ fn create_def(
self.tcx.definitions_untracked().def_key(self.node_id_to_def_id[&node_id].key()),
);
let disambiguator = self.disambiguators.get_or_create(parent);
// FIXME: remove `def_span` body, pass in the right spans here and call `tcx.at().create_def()`
let feed = self.tcx.create_def(
parent,
name,
def_kind,
None,
self.per_parent_disambiguators.entry(parent).or_default(),
);
let feed = self.tcx.create_def(parent, name, def_kind, None, disambiguator);
let def_id = feed.def_id();
// Create the definition.
@@ -1811,7 +1814,7 @@ pub fn new(
doc_link_resolutions: Default::default(),
doc_link_traits_in_scope: Default::default(),
current_crate_outer_attr_insert_span,
per_parent_disambiguators: Default::default(),
disambiguators: Default::default(),
..
};
@@ -1951,11 +1954,7 @@ pub fn into_outputs(self) -> ResolverOutputs<'tcx> {
lifetime_elision_allowed: self.lifetime_elision_allowed,
lint_buffer: Steal::new(self.lint_buffer),
delegation_infos: self.delegation_infos,
per_parent_disambiguators: self
.per_parent_disambiguators
.into_items()
.map(|(k, d)| (k, Steal::new(d)))
.collect(),
disambiguators: Steal::new(self.disambiguators),
};
ResolverOutputs { global_ctxt, ast_lowering }
}
@@ -245,7 +245,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
.map(move |assoc_item| {
super_poly_trait_ref.map_bound(|super_trait_ref| {
let projection_term = ty::AliasTerm::new_from_args(
let projection_term = ty::AliasTerm::new_from_def_id(
tcx,
assoc_item.def_id,
super_trait_ref.args,
@@ -202,7 +202,7 @@ pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
.kind()
.map_bound(|kind| match kind {
ty::ClauseKind::Projection(projection_predicate)
if projection_predicate.projection_term.def_id == item_def_id =>
if projection_predicate.projection_term.def_id() == item_def_id =>
{
projection_predicate.term.as_type()
}
@@ -1468,7 +1468,7 @@ enum Mismatch<'a> {
}
ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
ValuePairs::Aliases(ExpectedFound { expected, .. }) => {
(false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id)))
(false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id())))
}
ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
ValuePairs::ExistentialTraitRef(_) => {
@@ -579,7 +579,7 @@ pub(super) fn maybe_report_ambiguity(
if let Err(guar) = self
.tcx
.ensure_result()
.coherent_trait(self.tcx.parent(data.projection_term.def_id))
.coherent_trait(self.tcx.parent(data.projection_term.def_id()))
{
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
@@ -1536,8 +1536,11 @@ pub(super) fn report_projection_error(
let unnormalized_term = data.projection_term.to_term(self.tcx);
// FIXME(-Znext-solver): For diagnostic purposes, it would be nice
// to deeply normalize this type.
let normalized_term =
ocx.normalize(&obligation.cause, obligation.param_env, Unnormalized::new_wip(unnormalized_term));
let normalized_term = ocx.normalize(
&obligation.cause,
obligation.param_env,
Unnormalized::new_wip(unnormalized_term),
);
// constrain inference variables a bit more to nested obligations from normalize so
// we can have more helpful errors.
@@ -1586,8 +1589,9 @@ pub(super) fn report_projection_error(
}
};
if let Some(lhs) = lhs.to_alias_term()
&& let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst = lhs.kind(self.tcx)
if let Some(lhs) = lhs.to_alias_term(self.tcx)
&& let ty::AliasTermKind::ProjectionTy { .. }
| ty::AliasTermKind::ProjectionConst { .. } = lhs.kind(self.tcx)
&& let Some((better_type_err, expected_term)) =
derive_better_type_error(lhs, rhs)
{
@@ -1595,8 +1599,9 @@ pub(super) fn report_projection_error(
Some((lhs, self.resolve_vars_if_possible(expected_term), rhs)),
better_type_err,
)
} else if let Some(rhs) = rhs.to_alias_term()
&& let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst = rhs.kind(self.tcx)
} else if let Some(rhs) = rhs.to_alias_term(self.tcx)
&& let ty::AliasTermKind::ProjectionTy { .. }
| ty::AliasTermKind::ProjectionConst { .. } = rhs.kind(self.tcx)
&& let Some((better_type_err, expected_term)) =
derive_better_type_error(rhs, lhs)
{
@@ -1741,7 +1746,7 @@ fn maybe_detailed_projection_msg(
let self_ty = projection_term.self_ty();
with_forced_trimmed_paths! {
if self.tcx.is_lang_item(projection_term.def_id, LangItem::FnOnceOutput) {
if self.tcx.is_lang_item(projection_term.def_id(), LangItem::FnOnceOutput) {
let (span, closure_span) = if let ty::Closure(def_id, _) = *self_ty.kind() {
let def_span = self.tcx.def_span(def_id);
if let Some(local_def_id) = def_id.as_local()
@@ -1043,17 +1043,25 @@ pub(super) fn suggest_fn_call(
&& let ty::Tuple(inputs) = *sig.tupled_inputs_ty.kind()
&& inputs.is_empty()
&& self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Future)
&& let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) =
self.tcx.hir_node(*arg_hir_id)
&& let Some(hir::Node::Expr(hir::Expr {
kind:
hir::ExprKind::Closure(hir::Closure {
kind: hir::ClosureKind::CoroutineClosure(CoroutineDesugaring::Async),
fn_arg_span: Some(arg_span),
..
}),
..
kind: hir::ExprKind::Closure(closure), ..
})) = self.tcx.hir_get_if_local(def_id)
&& obligation.cause.span.contains(*arg_span)
&& let hir::ClosureKind::CoroutineClosure(CoroutineDesugaring::Async) = closure.kind
&& let Some(arg_span) = closure.fn_arg_span
&& obligation.cause.span.contains(arg_span)
{
let mut body = self.tcx.hir_body(closure.body).value;
let peeled = body.peel_blocks().peel_drop_temps();
if let hir::ExprKind::Closure(inner) = peeled.kind {
body = self.tcx.hir_body(inner.body).value;
}
if !matches!(body.peel_blocks().peel_drop_temps().kind, hir::ExprKind::Block(..)) {
return false;
}
let sm = self.tcx.sess.source_map();
let removal_span = if let Ok(snippet) =
sm.span_to_snippet(arg_span.with_hi(arg_span.hi() + rustc_span::BytePos(1)))
@@ -1062,7 +1070,7 @@ pub(super) fn suggest_fn_call(
// There's a space after `||`, include it in the removal
arg_span.with_hi(arg_span.hi() + rustc_span::BytePos(1))
} else {
*arg_span
arg_span
};
err.span_suggestion_verbose(
removal_span,
@@ -1102,23 +1110,63 @@ pub(super) fn suggest_fn_call(
.collect::<Vec<_>>()
.join(", ");
if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArg { .. })
if let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()
&& obligation.cause.span.can_be_used_for_suggestions()
{
let (span, sugg) = if let Some(snippet) =
self.tcx.sess.source_map().span_to_snippet(obligation.cause.span).ok()
&& snippet.starts_with("|")
{
(obligation.cause.span, format!("({snippet})({args})"))
} else {
(obligation.cause.span.shrink_to_hi(), format!("({args})"))
let span = obligation.cause.span;
let arg_expr = match self.tcx.hir_node(*arg_hir_id) {
hir::Node::Expr(expr) => Some(expr),
_ => None,
};
// When the obligation error has been ensured to have been caused by
// an argument, the `obligation.cause.span` points at the expression
// of the argument, so we can provide a suggestion. Otherwise, we give
// a more general note.
err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders);
let is_closure_expr =
arg_expr.is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Closure(..)));
// If the user wrote `|| {}()`, suggesting to call the closure would produce `(|| {}())()`,
// which doesn't help and is often outright wrong.
if args.is_empty()
&& let Some(expr) = arg_expr
&& let hir::ExprKind::Closure(closure) = expr.kind
{
let mut body = self.tcx.hir_body(closure.body).value;
// Async closures desugar to a closure returning a coroutine
if let hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) =
closure.kind
{
let peeled = body.peel_blocks().peel_drop_temps();
if let hir::ExprKind::Closure(inner) = peeled.kind {
body = self.tcx.hir_body(inner.body).value;
}
}
let peeled_body = body.peel_blocks().peel_drop_temps();
if let hir::ExprKind::Call(callee, call_args) = peeled_body.kind
&& call_args.is_empty()
&& let hir::ExprKind::Block(..) = callee.peel_blocks().peel_drop_temps().kind
{
return false;
}
}
if is_closure_expr {
err.multipart_suggestions(
msg,
vec![vec![
(span.shrink_to_lo(), "(".to_string()),
(span.shrink_to_hi(), format!(")({args})")),
]],
Applicability::HasPlaceholders,
);
} else {
err.span_suggestion_verbose(
span.shrink_to_hi(),
msg,
format!("({args})"),
Applicability::HasPlaceholders,
);
}
} else if let DefIdOrName::DefId(def_id) = def_id_or_name {
let name = match self.tcx.hir_get_if_local(def_id) {
Some(hir::Node::Expr(hir::Expr {
@@ -1445,7 +1493,7 @@ pub fn extract_callable_info(
if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
&& self
.tcx
.is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
.is_lang_item(proj.projection_term.def_id(), LangItem::FnOnceOutput)
// args tuple will always be args[1]
&& let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
{
@@ -1489,7 +1537,7 @@ pub fn extract_callable_info(
if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
&& self
.tcx
.is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
.is_lang_item(proj.projection_term.def_id(), LangItem::FnOnceOutput)
&& proj.projection_term.self_ty() == found
// args tuple will always be args[1]
&& let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
@@ -5256,7 +5304,7 @@ fn probe_assoc_types_at_expr(
let TypeError::Sorts(expected_found) = diff else {
continue;
};
let ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, .. }) =
let &ty::Alias(ty::AliasTy { kind: kind @ ty::Projection { def_id }, .. }) =
expected_found.expected.kind()
else {
continue;
@@ -5265,7 +5313,7 @@ fn probe_assoc_types_at_expr(
// Make `Self` be equivalent to the type of the call chain
// expression we're looking at now, so that we can tell what
// for example `Iterator::Item` is at this point in the chain.
let args = GenericArgs::for_item(self.tcx, *def_id, |param, _| {
let args = GenericArgs::for_item(self.tcx, def_id, |param, _| {
if param.index == 0 {
debug_assert_matches!(param.kind, ty::GenericParamDefKind::Type { .. });
return prev_ty.into();
@@ -5279,7 +5327,7 @@ fn probe_assoc_types_at_expr(
// This corresponds to `<ExprTy as Iterator>::Item = _`.
let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
ty::ClauseKind::Projection(ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(self.tcx, *def_id, args),
projection_term: ty::AliasTerm::new_from_args(self.tcx, kind.into(), args),
term: ty.into(),
}),
));
@@ -5296,7 +5344,7 @@ fn probe_assoc_types_at_expr(
&& let ty = self.resolve_vars_if_possible(ty)
&& !ty.is_ty_var()
{
assocs_in_this_method.push(Some((span, (*def_id, ty))));
assocs_in_this_method.push(Some((span, (def_id, ty))));
} else {
// `<ExprTy as Iterator>` didn't select, so likely we've
// reached the end of the iterator chain, like the originating
@@ -6344,12 +6392,12 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
return;
};
let Some(name) = tcx
.opt_rpitit_info(proj.projection_term.def_id)
.opt_rpitit_info(proj.projection_term.def_id())
.and_then(|data| match data {
ty::ImplTraitInTraitData::Trait { fn_def_id, .. } => Some(tcx.item_name(fn_def_id)),
ty::ImplTraitInTraitData::Impl { .. } => None,
})
.or_else(|| tcx.opt_item_name(proj.projection_term.def_id))
.or_else(|| tcx.opt_item_name(proj.projection_term.def_id()))
else {
return;
};
@@ -388,8 +388,8 @@ fn detect_error_from_empty_candidates(
self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?;
}
Some(ty::PredicateKind::NormalizesTo(pred))
if let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst =
pred.alias.kind(tcx) =>
if let ty::AliasTermKind::ProjectionTy { .. }
| ty::AliasTermKind::ProjectionConst { .. } = pred.alias.kind(tcx) =>
{
self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?;
self.detect_non_well_formed_assoc_item(goal, pred.alias)?;
@@ -450,7 +450,8 @@ fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result
ty::PredicateKind::NormalizesTo(normalizes_to)
if matches!(
normalizes_to.alias.kind(tcx),
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst
ty::AliasTermKind::ProjectionTy { .. }
| ty::AliasTermKind::ProjectionConst { .. }
) =>
{
ChildMode::Trait(pred.kind().rebind(ty::TraitPredicate {
@@ -107,7 +107,7 @@ fn normalize_alias_term(
let tcx = infcx.tcx;
let recursion_limit = tcx.recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
let term = alias_term.to_alias_term().unwrap();
let term = alias_term.to_alias_term(tcx).unwrap();
self.at.infcx.err_ctxt().report_overflow_error(
OverflowCause::DeeplyNormalize(term),
@@ -753,7 +753,7 @@ fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => tr.trait_ref,
ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj))
if matches!(
infcx.tcx.def_kind(proj.projection_term.def_id),
infcx.tcx.def_kind(proj.projection_term.def_id()),
DefKind::AssocTy | DefKind::AssocConst { .. }
) =>
{
@@ -556,15 +556,8 @@ fn evaluate_host_effect_for_fn_goal<'tcx>(
ty::Closure(def, args) => {
// For now we limit ourselves to closures without binders. The next solver can handle them.
let sig =
args.as_closure().sig().no_bound_vars().ok_or(EvaluationFailure::NoSolution)?;
(
def,
tcx.mk_args_from_iter(
[ty::GenericArg::from(*sig.inputs().get(0).unwrap()), sig.output().into()]
.into_iter(),
),
)
args.as_closure().sig().no_bound_vars().ok_or(EvaluationFailure::NoSolution)?;
(def, args)
}
// Everything else needs explicit impls or cannot have an impl
@@ -699,8 +699,8 @@ fn process_obligation(
// `generic_const_exprs`
.eq(
DefineOpaqueTypes::Yes,
ty::AliasTerm::from(a),
ty::AliasTerm::from(b),
ty::AliasTerm::from_unevaluated_const(tcx, a),
ty::AliasTerm::from_unevaluated_const(tcx, b),
)
{
return ProcessResult::Changed(mk_pending(
@@ -321,7 +321,7 @@ fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> {
self.obligations.extend(
infcx
.tcx
.predicates_of(free.def_id)
.predicates_of(free.def_id())
.instantiate_own(infcx.tcx, free.args)
.map(|(pred, span)| (pred.skip_norm_wip(), span))
.map(|(mut predicate, span)| {
@@ -333,7 +333,8 @@ fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> {
);
}
let mut cause = self.cause.clone();
cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, free.def_id));
cause
.map_code(|code| ObligationCauseCode::TypeAlias(code, span, free.def_id()));
Obligation::new(infcx.tcx, cause, self.param_env, predicate)
}),
);
@@ -341,7 +342,7 @@ fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> {
let res = if free.kind(infcx.tcx).is_type() {
infcx
.tcx
.type_of(free.def_id)
.type_of(free.def_id())
.instantiate(infcx.tcx, free.args)
.skip_norm_wip()
.fold_with(self)
@@ -349,7 +350,7 @@ fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> {
} else {
infcx
.tcx
.const_of_item(free.def_id)
.const_of_item(free.def_id())
.instantiate(infcx.tcx, free.args)
.skip_norm_wip()
.fold_with(self)
@@ -468,16 +469,20 @@ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
// feature gate causes a parse error.
let ct = match tcx.def_kind(uv.def) {
DefKind::AssocConst { .. } => match tcx.def_kind(tcx.parent(uv.def)) {
DefKind::Trait => self.normalize_trait_projection(uv.into()).expect_const(),
DefKind::Impl { of_trait: false } => {
self.normalize_inherent_projection(uv.into()).expect_const()
}
DefKind::Trait => self
.normalize_trait_projection(ty::AliasTerm::from_unevaluated_const(tcx, uv))
.expect_const(),
DefKind::Impl { of_trait: false } => self
.normalize_inherent_projection(ty::AliasTerm::from_unevaluated_const(tcx, uv))
.expect_const(),
kind => unreachable!(
"unexpected `DefKind` for const alias' resolution's parent def: {:?}",
kind
),
},
DefKind::Const { .. } => self.normalize_free_alias(uv.into()).expect_const(),
DefKind::Const { .. } => self
.normalize_free_alias(ty::AliasTerm::from_unevaluated_const(tcx, uv))
.expect_const(),
DefKind::AnonConst => {
let ct = ct.super_fold_with(self);
super::with_replaced_escaping_bound_vars(
@@ -463,14 +463,16 @@ fn normalize_to_error<'a, 'tcx>(
) -> NormalizedTerm<'tcx> {
let trait_ref = ty::Binder::dummy(projection_term.trait_ref(selcx.tcx()));
let new_value = match projection_term.kind(selcx.tcx()) {
ty::AliasTermKind::ProjectionTy
| ty::AliasTermKind::InherentTy
| ty::AliasTermKind::OpaqueTy
| ty::AliasTermKind::FreeTy => selcx.infcx.next_ty_var(cause.span).into(),
ty::AliasTermKind::FreeConst
| ty::AliasTermKind::InherentConst
| ty::AliasTermKind::UnevaluatedConst
| ty::AliasTermKind::ProjectionConst => selcx.infcx.next_const_var(cause.span).into(),
ty::AliasTermKind::ProjectionTy { .. }
| ty::AliasTermKind::InherentTy { .. }
| ty::AliasTermKind::OpaqueTy { .. }
| ty::AliasTermKind::FreeTy { .. } => selcx.infcx.next_ty_var(cause.span).into(),
ty::AliasTermKind::FreeConst { .. }
| ty::AliasTermKind::InherentConst { .. }
| ty::AliasTermKind::UnevaluatedConst { .. }
| ty::AliasTermKind::ProjectionConst { .. } => {
selcx.infcx.next_const_var(cause.span).into()
}
};
let mut obligations = PredicateObligations::new();
obligations.push(Obligation {
@@ -513,7 +515,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
);
// Register the obligations arising from the impl and from the associated type itself.
let predicates = tcx.predicates_of(alias_term.def_id).instantiate(tcx, args);
let predicates = tcx.predicates_of(alias_term.def_id()).instantiate(tcx, args);
for (predicate, span) in predicates {
let predicate = normalize_with_depth_to(
selcx,
@@ -531,7 +533,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
// cause code, inherent projections will be printed with identity instantiation in
// diagnostics which is not ideal.
// Consider creating separate cause codes for this specific situation.
ObligationCauseCode::WhereClause(alias_term.def_id, span),
ObligationCauseCode::WhereClause(alias_term.def_id(), span),
);
obligations.push(Obligation::with_depth(
@@ -544,9 +546,9 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
}
let term: Term<'tcx> = if alias_term.kind(tcx).is_type() {
tcx.type_of(alias_term.def_id).instantiate(tcx, args).skip_norm_wip().into()
tcx.type_of(alias_term.def_id()).instantiate(tcx, args).skip_norm_wip().into()
} else {
tcx.const_of_item(alias_term.def_id).instantiate(tcx, args).skip_norm_wip().into()
tcx.const_of_item(alias_term.def_id()).instantiate(tcx, args).skip_norm_wip().into()
};
let mut term = selcx.infcx.resolve_vars_if_possible(term);
@@ -569,7 +571,7 @@ pub fn compute_inherent_assoc_term_args<'a, 'b, 'tcx>(
) -> ty::GenericArgsRef<'tcx> {
let tcx = selcx.tcx();
let impl_def_id = tcx.parent(alias_term.def_id);
let impl_def_id = tcx.parent(alias_term.def_id());
let impl_args = selcx.infcx.fresh_args_for_item(cause.span, impl_def_id);
let mut impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args).skip_norm_wip();
@@ -747,7 +749,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
let Some(clause) = clause.as_projection_clause() else {
return ControlFlow::Continue(());
};
if clause.item_def_id() != obligation.predicate.def_id {
if clause.item_def_id() != obligation.predicate.def_id() {
return ControlFlow::Continue(());
}
@@ -815,7 +817,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
};
let env_predicates = data
.projection_bounds()
.filter(|bound| bound.item_def_id() == obligation.predicate.def_id)
.filter(|bound| bound.item_def_id() == obligation.predicate.def_id())
.map(|p| p.with_self_ty(tcx, object_ty).upcast(tcx));
assemble_candidates_from_predicates(
@@ -846,7 +848,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
let bound_predicate = predicate.kind();
if let ty::ClauseKind::Projection(data) = predicate.kind().skip_binder() {
let data = bound_predicate.rebind(data);
if data.item_def_id() != obligation.predicate.def_id {
if data.item_def_id() != obligation.predicate.def_id() {
continue;
}
@@ -937,7 +939,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
match specialization_graph::assoc_def(
selcx.tcx(),
impl_data.impl_def_id,
obligation.predicate.def_id,
obligation.predicate.def_id(),
) {
Ok(node_item) => {
if node_item.is_final() {
@@ -1143,7 +1145,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
}
_ if tcx.trait_is_auto(trait_ref.def_id) => {
tcx.dcx().span_delayed_bug(
tcx.def_span(obligation.predicate.def_id),
tcx.def_span(obligation.predicate.def_id()),
"associated types not allowed on auto traits",
);
false
@@ -1325,24 +1327,20 @@ fn confirm_coroutine_candidate<'cx, 'tcx>(
coroutine_sig,
);
let ty = if tcx.is_lang_item(obligation.predicate.def_id, LangItem::CoroutineReturn) {
let ty = if tcx.is_lang_item(obligation.predicate.def_id(), LangItem::CoroutineReturn) {
return_ty
} else if tcx.is_lang_item(obligation.predicate.def_id, LangItem::CoroutineYield) {
} else if tcx.is_lang_item(obligation.predicate.def_id(), LangItem::CoroutineYield) {
yield_ty
} else {
span_bug!(
tcx.def_span(obligation.predicate.def_id),
tcx.def_span(obligation.predicate.def_id()),
"unexpected associated type: `Coroutine::{}`",
tcx.item_name(obligation.predicate.def_id),
tcx.item_name(obligation.predicate.def_id()),
);
};
let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(
tcx,
obligation.predicate.def_id,
trait_ref.args,
),
projection_term: obligation.predicate.with_args(tcx, trait_ref.args),
term: ty.into(),
};
@@ -1383,14 +1381,10 @@ fn confirm_future_candidate<'cx, 'tcx>(
coroutine_sig,
);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Output);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id()).name(), sym::Output);
let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(
tcx,
obligation.predicate.def_id,
trait_ref.args,
),
projection_term: obligation.predicate.with_args(tcx, trait_ref.args),
term: return_ty.into(),
};
@@ -1429,14 +1423,10 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
gen_sig,
);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id()).name(), sym::Item);
let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(
tcx,
obligation.predicate.def_id,
trait_ref.args,
),
projection_term: obligation.predicate.with_args(tcx, trait_ref.args),
term: yield_ty.into(),
};
@@ -1475,7 +1465,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>(
gen_sig,
);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id()).name(), sym::Item);
let ty::Adt(_poll_adt, args) = *yield_ty.kind() else {
bug!();
@@ -1486,11 +1476,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>(
let item_ty = args.type_at(0);
let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(
tcx,
obligation.predicate.def_id,
trait_ref.args,
),
projection_term: obligation.predicate.with_args(tcx, trait_ref.args),
term: item_ty.into(),
};
@@ -1506,7 +1492,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
) -> Progress<'tcx> {
let tcx = selcx.tcx();
let self_ty = obligation.predicate.self_ty();
let item_def_id = obligation.predicate.def_id;
let item_def_id = obligation.predicate.def_id();
let trait_def_id = tcx.parent(item_def_id);
let args = tcx.mk_args(&[self_ty.into()]);
let (term, obligations) = if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) {
@@ -1569,7 +1555,11 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
};
let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(tcx, item_def_id, args),
projection_term: ty::AliasTerm::new_from_args(
tcx,
ty::AliasTermKind::ProjectionTy { def_id: item_def_id },
args,
),
term,
};
@@ -1702,7 +1692,11 @@ fn confirm_callable_candidate<'cx, 'tcx>(
flag,
)
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(tcx, fn_once_output_def_id, trait_ref.args),
projection_term: ty::AliasTerm::new_from_args(
tcx,
ty::AliasTermKind::ProjectionTy { def_id: fn_once_output_def_id },
trait_ref.args,
),
term: ret_type.into(),
});
@@ -1723,7 +1717,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => obligation.predicate.args.region_at(2),
ty::ClosureKind::FnOnce => tcx.lifetimes.re_static,
};
let item_name = tcx.item_name(obligation.predicate.def_id);
let item_name = tcx.item_name(obligation.predicate.def_id());
let poly_cache_entry = match *self_ty.kind() {
ty::CoroutineClosure(def_id, args) => {
@@ -1787,12 +1781,12 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
let projection_term = match item_name {
sym::CallOnceFuture | sym::Output => ty::AliasTerm::new(
tcx,
obligation.predicate.def_id,
obligation.predicate.kind,
[self_ty, sig.tupled_inputs_ty],
),
sym::CallRefFuture => ty::AliasTerm::new(
tcx,
obligation.predicate.def_id,
obligation.predicate.kind,
[ty::GenericArg::from(self_ty), sig.tupled_inputs_ty.into(), env_region.into()],
),
name => bug!("no such associated type: {name}"),
@@ -1817,12 +1811,12 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
let projection_term = match item_name {
sym::CallOnceFuture | sym::Output => ty::AliasTerm::new(
tcx,
obligation.predicate.def_id,
obligation.predicate.kind,
[self_ty, Ty::new_tup(tcx, sig.inputs())],
),
sym::CallRefFuture => ty::AliasTerm::new(
tcx,
obligation.predicate.def_id,
obligation.predicate.kind,
[
ty::GenericArg::from(self_ty),
Ty::new_tup(tcx, sig.inputs()).into(),
@@ -1850,11 +1844,11 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
};
let projection_term = match item_name {
sym::CallOnceFuture | sym::Output => {
ty::AliasTerm::new(tcx, obligation.predicate.def_id, [self_ty, sig.inputs()[0]])
ty::AliasTerm::new(tcx, obligation.predicate.kind, [self_ty, sig.inputs()[0]])
}
sym::CallRefFuture => ty::AliasTerm::new(
tcx,
obligation.predicate.def_id,
obligation.predicate.kind,
[ty::GenericArg::from(self_ty), sig.inputs()[0].into(), env_region.into()],
),
name => bug!("no such associated type: {name}"),
@@ -1888,11 +1882,7 @@ fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>(
};
let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(
selcx.tcx(),
obligation.predicate.def_id,
obligation.predicate.args,
),
projection_term: obligation.predicate.with_args(selcx.tcx(), obligation.predicate.args),
term: ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind(
selcx.tcx(),
goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap(),
@@ -1986,7 +1976,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
let ImplSourceUserDefinedData { impl_def_id, args, mut nested } = impl_impl_source;
let assoc_item_id = obligation.predicate.def_id;
let assoc_item_id = obligation.predicate.def_id();
let trait_def_id = tcx.impl_trait_id(impl_def_id);
let param_env = obligation.param_env;
@@ -2074,7 +2064,7 @@ fn assoc_term_own_obligations<'cx, 'tcx>(
) {
let tcx = selcx.tcx();
let predicates = tcx
.predicates_of(obligation.predicate.def_id)
.predicates_of(obligation.predicate.def_id())
.instantiate_own(tcx, obligation.predicate.args);
for (predicate, span) in predicates {
let normalized = normalize_with_depth_to(
@@ -2097,7 +2087,7 @@ fn assoc_term_own_obligations<'cx, 'tcx>(
ObligationCause::new(
obligation.cause.span,
obligation.cause.body_id,
ObligationCauseCode::WhereClause(obligation.predicate.def_id, span),
ObligationCauseCode::WhereClause(obligation.predicate.def_id(), span),
)
};
nested.push(Obligation::with_depth(
@@ -256,8 +256,8 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
}
}
ty::Projection { def_id } | ty::Inherent { def_id } | ty::Free { def_id } => self
.try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), def_id, data.args))?
kind @ (ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. }) => self
.try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), kind.into(), data.args))?
.expect_type(),
};
@@ -286,7 +286,7 @@ fn try_fold_const(
|constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env),
),
_ => self
.try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), uv.def, uv.args))?
.try_fold_free_or_assoc(ty::AliasTerm::from_unevaluated_const(self.cx(), uv))?
.expect_const(),
};
debug!(?constant, ?self.param_env);
@@ -329,16 +329,17 @@ fn try_fold_free_or_assoc(
debug!("QueryNormalizer: c_term = {:#?}", c_term);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
let result = match term.kind(tcx) {
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
ty::AliasTermKind::ProjectionTy { .. } | ty::AliasTermKind::ProjectionConst { .. } => {
tcx.normalize_canonicalized_projection(c_term)
}
ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => {
ty::AliasTermKind::FreeTy { .. } | ty::AliasTermKind::FreeConst { .. } => {
tcx.normalize_canonicalized_free_alias(c_term)
}
ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => {
ty::AliasTermKind::InherentTy { .. } | ty::AliasTermKind::InherentConst { .. } => {
tcx.normalize_canonicalized_inherent_projection(c_term)
}
kind @ (ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::UnevaluatedConst) => {
kind @ (ty::AliasTermKind::OpaqueTy { .. }
| ty::AliasTermKind::UnevaluatedConst { .. }) => {
unreachable!("did not expect {kind:?} due to match arm above")
}
}?;
@@ -382,7 +383,7 @@ fn try_fold_free_or_assoc(
&& (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION)
|| matches!(
term.kind(tcx),
ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst
ty::AliasTermKind::FreeTy { .. } | ty::AliasTermKind::FreeConst { .. }
))
{
res.try_fold_with(self)
@@ -891,8 +891,8 @@ fn evaluate_predicate_recursively<'o>(
// `generic_const_exprs`
.eq(
DefineOpaqueTypes::Yes,
ty::AliasTerm::from(a),
ty::AliasTerm::from(b),
ty::AliasTerm::from_unevaluated_const(tcx, a),
ty::AliasTerm::from_unevaluated_const(tcx, b),
)
{
return self.evaluate_predicates_recursively(
@@ -1761,7 +1761,7 @@ pub(super) fn match_projection_projections(
env_predicate: PolyProjectionPredicate<'tcx>,
potentially_unnormalized_candidates: bool,
) -> ProjectionMatchesProjection {
debug_assert_eq!(obligation.predicate.def_id, env_predicate.item_def_id());
debug_assert_eq!(obligation.predicate.def_id(), env_predicate.item_def_id());
let mut nested_obligations = PredicateObligations::new();
let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars(
@@ -1797,7 +1797,7 @@ pub(super) fn match_projection_projections(
});
if is_match {
let generics = self.tcx().generics_of(obligation.predicate.def_id);
let generics = self.tcx().generics_of(obligation.predicate.def_id());
// FIXME(generic_associated_types): Addresses aggressive inference in #92917.
// If this type is a GAT, and of the GAT args resolve to something new,
// that means that we must have newly inferred something about the GAT.
@@ -41,7 +41,7 @@ fn structurally_normalize_term<E: 'tcx>(
if self.infcx.next_trait_solver() {
let term = term.skip_normalization();
if let None = term.to_alias_term() {
if let None = term.to_alias_term(self.infcx.tcx) {
return Ok(term);
}
@@ -478,7 +478,7 @@ fn add_wf_preds_for_alias_term(&mut self, data: ty::AliasTerm<'tcx>) {
// `i32: Clone`
// `i32: Copy`
// ]
let obligations = self.nominal_obligations(data.def_id, data.args);
let obligations = self.nominal_obligations(data.def_id(), data.args);
self.out.extend(obligations);
self.add_wf_preds_for_projection_args(data.args);
@@ -507,7 +507,7 @@ fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTerm<'tcx>) {
self.recursion_depth,
&mut self.out,
);
let obligations = self.nominal_obligations(data.def_id, args);
let obligations = self.nominal_obligations(data.def_id(), args);
self.out.extend(obligations);
}
@@ -1001,7 +1001,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
.map_bound(|p| {
p.term.as_const().map(|ct| {
let assoc_const_ty = tcx
.type_of(p.projection_term.def_id)
.type_of(p.projection_term.def_id())
.instantiate(tcx, p.projection_term.args)
.skip_norm_wip();
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(
@@ -1077,7 +1077,9 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result {
if matches!(tcx.def_kind(uv.def), DefKind::AssocConst { .. })
&& tcx.def_kind(tcx.parent(uv.def)) == (DefKind::Impl { of_trait: false })
{
self.add_wf_preds_for_inherent_projection(uv.into());
self.add_wf_preds_for_inherent_projection(
ty::AliasTerm::from_unevaluated_const(tcx, uv),
);
return; // Subtree is handled by above function
} else {
let obligations = self.nominal_obligations(uv.def, uv.args);
@@ -75,7 +75,7 @@ fn normalize_canonicalized_free_alias<'tcx>(
tcx.infer_ctxt().enter_canonical_trait_query(
&goal,
|ocx, ParamEnvAnd { param_env, value: goal }| {
let obligations = tcx.predicates_of(goal.def_id).instantiate_own(tcx, goal.args).map(
let obligations = tcx.predicates_of(goal.def_id()).instantiate_own(tcx, goal.args).map(
|(predicate, span)| {
traits::Obligation::new(
tcx,
@@ -87,9 +87,9 @@ fn normalize_canonicalized_free_alias<'tcx>(
);
ocx.register_obligations(obligations);
let normalized_term = if goal.kind(tcx).is_type() {
tcx.type_of(goal.def_id).instantiate(tcx, goal.args).skip_norm_wip().into()
tcx.type_of(goal.def_id()).instantiate(tcx, goal.args).skip_norm_wip().into()
} else {
tcx.const_of_item(goal.def_id).instantiate(tcx, goal.args).skip_norm_wip().into()
tcx.const_of_item(goal.def_id()).instantiate(tcx, goal.args).skip_norm_wip().into()
};
Ok(NormalizationResult { normalized_term })
},
+13 -11
View File
@@ -1,6 +1,8 @@
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdMap};
use rustc_hir::definitions::{
DefPathData, PerParentDisambiguatorState, PerParentDisambiguatorsMap,
};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self as hir, ConstItemRhs, ImplItemImplKind, ItemKind};
use rustc_middle::query::Providers;
@@ -129,7 +131,7 @@ struct RPITVisitor<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
synthetics: Vec<LocalDefId>,
data: DefPathData,
disambiguator: &'a mut DisambiguatorState,
disambiguators: &'a mut LocalDefIdMap<PerParentDisambiguatorState>,
}
impl<'tcx> Visitor<'tcx> for RPITVisitor<'_, 'tcx> {
@@ -138,7 +140,7 @@ fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result
self.tcx,
opaque.def_id,
self.data,
&mut self.disambiguator,
&mut self.disambiguators,
));
intravisit::walk_opaque_ty(self, opaque)
}
@@ -149,7 +151,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>(
def_id: LocalDefId,
) -> DefIdMap<Vec<DefId>> {
let item = tcx.hir_expect_item(def_id);
let disambiguator = &mut DisambiguatorState::new();
let disambiguators = &mut Default::default();
match item.kind {
ItemKind::Trait(.., trait_item_refs) => trait_item_refs
.iter()
@@ -163,7 +165,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>(
};
let def_name = tcx.item_name(fn_def_id.to_def_id());
let data = DefPathData::AnonAssocTy(def_name);
let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, disambiguator };
let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, disambiguators };
visitor.visit_fn_ret_ty(output);
let defs = visitor
.synthetics
@@ -197,7 +199,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>(
return Some((did, vec![]));
};
let iter = in_trait_def[&trait_item_def_id].iter().map(|&id| {
associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguator)
associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguators)
.to_def_id()
});
Some((did, iter.collect()))
@@ -221,7 +223,7 @@ fn associated_type_for_impl_trait_in_trait(
tcx: TyCtxt<'_>,
opaque_ty_def_id: LocalDefId,
data: DefPathData,
disambiguator: &mut DisambiguatorState,
disambiguators: &mut LocalDefIdMap<PerParentDisambiguatorState>,
) -> LocalDefId {
let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
| hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
@@ -240,7 +242,7 @@ fn associated_type_for_impl_trait_in_trait(
None,
DefKind::AssocTy,
Some(data),
disambiguator,
disambiguators.get_or_create(trait_def_id),
);
let local_def_id = trait_assoc_ty.def_id();
@@ -283,7 +285,7 @@ fn associated_type_for_impl_trait_in_impl(
tcx: TyCtxt<'_>,
trait_assoc_def_id: DefId,
impl_fn: &hir::ImplItem<'_>,
disambiguator: &mut DisambiguatorState,
disambiguators: &mut LocalDefIdMap<PerParentDisambiguatorState>,
) -> LocalDefId {
let impl_local_def_id = tcx.local_parent(impl_fn.owner_id.def_id);
@@ -306,7 +308,7 @@ fn associated_type_for_impl_trait_in_impl(
None,
DefKind::AssocTy,
Some(data),
disambiguator,
disambiguators.get_or_create(impl_local_def_id),
);
let local_def_id = impl_assoc_ty.def_id();
+4 -2
View File
@@ -432,14 +432,16 @@ fn is_error(self) -> bool {
}
}
fn to_alias_term(self) -> Option<ty::AliasTerm<I>> {
fn to_alias_term(self, interner: I) -> Option<ty::AliasTerm<I>> {
match self.kind() {
ty::TermKind::Ty(ty) => match ty.kind() {
ty::Alias(alias_ty) => Some(alias_ty.into()),
_ => None,
},
ty::TermKind::Const(ct) => match ct.kind() {
ty::ConstKind::Unevaluated(uv) => Some(uv.into()),
ty::ConstKind::Unevaluated(uv) => {
Some(ty::AliasTerm::from_unevaluated_const(interner, uv))
}
_ => None,
},
}
+3 -4
View File
@@ -197,11 +197,9 @@ fn canonical_param_env_cache_get_or_insert<R>(
type VariancesOf: Copy + Debug + SliceLike<Item = ty::Variance>;
fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf;
// FIXME: remove `def_id` param after `AliasTermKind` contains `def_id` within
fn opt_alias_variances(
self,
kind: impl Into<ty::AliasTermKind>,
def_id: Self::DefId,
kind: impl Into<ty::AliasTermKind<Self>>,
) -> Option<Self::VariancesOf>;
fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
@@ -215,7 +213,8 @@ fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId)
fn alias_ty_kind_from_def_id(self, def_id: Self::DefId) -> ty::AliasTyKind<Self>;
fn alias_term_kind(self, alias: ty::AliasTerm<Self>) -> ty::AliasTermKind;
// FIXME: remove in favor of explicit construction
fn alias_term_kind_from_def_id(self, def_id: Self::DefId) -> ty::AliasTermKind<Self>;
fn trait_ref_and_own_args_for_alias(
self,
+1 -1
View File
@@ -226,7 +226,7 @@ pub fn compute_alias_components_recursive<I: Interner>(
alias_ty: ty::AliasTy<I>,
out: &mut SmallVec<[Component<I>; 4]>,
) {
let opt_variances = cx.opt_alias_variances(alias_ty.kind, alias_ty.kind.def_id());
let opt_variances = cx.opt_alias_variances(alias_ty.kind);
let mut visitor = OutlivesCollector { cx, out, visited: Default::default() };
+135 -90
View File
@@ -3,9 +3,7 @@
use derive_where::derive_where;
#[cfg(feature = "nightly")]
use rustc_macros::{
Decodable, Decodable_NoContext, Encodable, Encodable_NoContext, HashStable_NoContext,
};
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir_macros::{
GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
};
@@ -532,7 +530,7 @@ pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I
ProjectionPredicate {
projection_term: AliasTerm::new(
interner,
self.def_id,
interner.alias_term_kind_from_def_id(self.def_id),
[self_ty.into()].iter().chain(self.args.iter()),
),
term: self.term,
@@ -544,7 +542,7 @@ pub fn erase_self_ty(interner: I, projection_predicate: ProjectionPredicate<I>)
projection_predicate.projection_term.args.type_at(0);
Self {
def_id: projection_predicate.projection_term.def_id,
def_id: projection_predicate.projection_term.def_id(),
args: interner.mk_args(&projection_predicate.projection_term.args.as_slice()[1..]),
term: projection_predicate.term,
use_existential_projection_new_instead: (),
@@ -562,71 +560,104 @@ pub fn item_def_id(&self) -> I::DefId {
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
pub enum AliasTermKind {
#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
#[derive(Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
)]
pub enum AliasTermKind<I: Interner> {
/// A projection `<Type as Trait>::AssocType`.
///
/// Can get normalized away if monomorphic enough.
ProjectionTy,
///
/// The `def_id` is the `DefId` of the `TraitItem` for the associated type.
///
/// Note that the `def_id` is not the `DefId` of the `TraitRef` containing this
/// associated type, which is in `interner.associated_item(def_id).container`,
/// aka. `interner.parent(def_id)`.
ProjectionTy { def_id: I::DefId },
/// An associated type in an inherent `impl`
InherentTy,
///
/// The `def_id` is the `DefId` of the `ImplItem` for the associated type.
InherentTy { def_id: I::DefId },
/// An opaque type (usually from `impl Trait` in type aliases or function return types)
///
/// Can only be normalized away in PostAnalysis mode or its defining scope.
OpaqueTy,
/// A free type alias that actually checks its trait bounds.
/// `def_id` is the `DefId` of the `OpaqueType` item.
///
/// Can only be normalized away in `PostAnalysis` mode or its defining scope.
///
/// During codegen, `interner.type_of(def_id)` can be used to get the type of the
/// underlying type if the type is an opaque.
OpaqueTy { def_id: I::DefId },
/// A type alias that actually checks its trait bounds.
///
/// Currently only used if the type alias references opaque types.
/// Can always be normalized away.
FreeTy,
FreeTy { def_id: I::DefId },
/// An unevaluated anonymous constants.
UnevaluatedConst,
UnevaluatedConst { def_id: I::DefId },
/// An unevaluated const coming from an associated const.
ProjectionConst,
ProjectionConst { def_id: I::DefId },
/// A top level const item not part of a trait or impl.
FreeConst,
FreeConst { def_id: I::DefId },
/// An associated const in an inherent `impl`
InherentConst,
InherentConst { def_id: I::DefId },
}
impl AliasTermKind {
impl<I: Interner> AliasTermKind<I> {
pub fn descr(self) -> &'static str {
match self {
AliasTermKind::ProjectionTy => "associated type",
AliasTermKind::ProjectionConst => "associated const",
AliasTermKind::InherentTy => "inherent associated type",
AliasTermKind::InherentConst => "inherent associated const",
AliasTermKind::OpaqueTy => "opaque type",
AliasTermKind::FreeTy => "type alias",
AliasTermKind::FreeConst => "unevaluated constant",
AliasTermKind::UnevaluatedConst => "unevaluated constant",
AliasTermKind::ProjectionTy { .. } => "associated type",
AliasTermKind::ProjectionConst { .. } => "associated const",
AliasTermKind::InherentTy { .. } => "inherent associated type",
AliasTermKind::InherentConst { .. } => "inherent associated const",
AliasTermKind::OpaqueTy { .. } => "opaque type",
AliasTermKind::FreeTy { .. } => "type alias",
AliasTermKind::FreeConst { .. } => "unevaluated constant",
AliasTermKind::UnevaluatedConst { .. } => "unevaluated constant",
}
}
pub fn is_type(self) -> bool {
match self {
AliasTermKind::ProjectionTy
| AliasTermKind::InherentTy
| AliasTermKind::OpaqueTy
| AliasTermKind::FreeTy => true,
AliasTermKind::ProjectionTy { .. }
| AliasTermKind::InherentTy { .. }
| AliasTermKind::OpaqueTy { .. }
| AliasTermKind::FreeTy { .. } => true,
AliasTermKind::UnevaluatedConst
| AliasTermKind::ProjectionConst
| AliasTermKind::InherentConst
| AliasTermKind::FreeConst => false,
AliasTermKind::UnevaluatedConst { .. }
| AliasTermKind::ProjectionConst { .. }
| AliasTermKind::InherentConst { .. }
| AliasTermKind::FreeConst { .. } => false,
}
}
// FIXME: replace with explicit matches
pub fn def_id(self) -> I::DefId {
let (AliasTermKind::ProjectionTy { def_id }
| AliasTermKind::InherentTy { def_id }
| AliasTermKind::OpaqueTy { def_id }
| AliasTermKind::FreeTy { def_id }
| AliasTermKind::UnevaluatedConst { def_id }
| AliasTermKind::ProjectionConst { def_id }
| AliasTermKind::FreeConst { def_id }
| AliasTermKind::InherentConst { def_id }) = self;
def_id
}
}
impl<I: Interner> From<ty::AliasTyKind<I>> for AliasTermKind {
impl<I: Interner> From<ty::AliasTyKind<I>> for AliasTermKind<I> {
fn from(value: ty::AliasTyKind<I>) -> Self {
match value {
ty::Projection { .. } => AliasTermKind::ProjectionTy,
ty::Opaque { .. } => AliasTermKind::OpaqueTy,
ty::Free { .. } => AliasTermKind::FreeTy,
ty::Inherent { .. } => AliasTermKind::InherentTy,
ty::Projection { def_id } => AliasTermKind::ProjectionTy { def_id },
ty::Opaque { def_id } => AliasTermKind::OpaqueTy { def_id },
ty::Free { def_id } => AliasTermKind::FreeTy { def_id },
ty::Inherent { def_id } => AliasTermKind::InherentTy { def_id },
}
}
}
@@ -655,17 +686,9 @@ pub struct AliasTerm<I: Interner> {
/// while for TAIT it is used for the generic parameters of the alias.
pub args: I::GenericArgs,
/// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
/// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
/// this is an opaque.
///
/// During codegen, `interner.type_of(def_id)` can be used to get the type of the
/// underlying type if the type is an opaque.
///
/// Note that if this is an associated type, this is not the `DefId` of the
/// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`,
/// aka. `interner.parent(def_id)`.
pub def_id: I::DefId,
#[type_foldable(identity)]
#[type_visitable(ignore)]
pub kind: AliasTermKind<I>,
/// This field exists to prevent the creation of `AliasTerm` without using [`AliasTerm::new_from_args`].
#[derive_where(skip(Debug))]
@@ -675,62 +698,86 @@ pub struct AliasTerm<I: Interner> {
impl<I: Interner> Eq for AliasTerm<I> {}
impl<I: Interner> AliasTerm<I> {
pub fn new_from_args(interner: I, def_id: I::DefId, args: I::GenericArgs) -> AliasTerm<I> {
interner.debug_assert_args_compatible(def_id, args);
AliasTerm { def_id, args, _use_alias_term_new_instead: () }
pub fn new_from_args(
interner: I,
kind: AliasTermKind<I>,
args: I::GenericArgs,
) -> AliasTerm<I> {
interner.debug_assert_args_compatible(kind.def_id(), args);
AliasTerm { kind, args, _use_alias_term_new_instead: () }
}
pub fn new(
interner: I,
def_id: I::DefId,
kind: AliasTermKind<I>,
args: impl IntoIterator<Item: Into<I::GenericArg>>,
) -> AliasTerm<I> {
let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
Self::new_from_args(interner, def_id, args)
Self::new_from_args(interner, kind, args)
}
pub fn new_from_def_id(interner: I, def_id: I::DefId, args: I::GenericArgs) -> AliasTerm<I> {
let kind = interner.alias_term_kind_from_def_id(def_id);
Self::new_from_args(interner, kind, args)
}
pub fn from_unevaluated_const(interner: I, ct: ty::UnevaluatedConst<I>) -> Self {
let kind = interner.alias_term_kind_from_def_id(ct.def.into());
AliasTerm::new_from_args(interner, kind, ct.args)
}
pub fn expect_ty(self, interner: I) -> ty::AliasTy<I> {
let kind = match self.kind(interner) {
AliasTermKind::ProjectionTy => AliasTyKind::Projection { def_id: self.def_id },
AliasTermKind::InherentTy => AliasTyKind::Inherent { def_id: self.def_id },
AliasTermKind::OpaqueTy => AliasTyKind::Opaque { def_id: self.def_id },
AliasTermKind::FreeTy => AliasTyKind::Free { def_id: self.def_id },
AliasTermKind::InherentConst
| AliasTermKind::FreeConst
| AliasTermKind::UnevaluatedConst
| AliasTermKind::ProjectionConst => {
AliasTermKind::ProjectionTy { def_id } => AliasTyKind::Projection { def_id },
AliasTermKind::InherentTy { def_id } => AliasTyKind::Inherent { def_id },
AliasTermKind::OpaqueTy { def_id } => AliasTyKind::Opaque { def_id },
AliasTermKind::FreeTy { def_id } => AliasTyKind::Free { def_id },
AliasTermKind::InherentConst { .. }
| AliasTermKind::FreeConst { .. }
| AliasTermKind::UnevaluatedConst { .. }
| AliasTermKind::ProjectionConst { .. } => {
panic!("Cannot turn `UnevaluatedConst` into `AliasTy`")
}
};
ty::AliasTy { kind, args: self.args, _use_alias_ty_new_instead: () }
}
pub fn kind(self, interner: I) -> AliasTermKind {
interner.alias_term_kind(self)
// FIXME: remove this function (access the field instead)
pub fn kind(self, _interner: I) -> AliasTermKind<I> {
self.kind
}
// FIXME: replace with explicit matches
pub fn def_id(self) -> I::DefId {
self.kind.def_id()
}
pub fn to_term(self, interner: I) -> I::Term {
let alias_ty_kind = match self.kind(interner) {
AliasTermKind::FreeConst
| AliasTermKind::InherentConst
| AliasTermKind::UnevaluatedConst
| AliasTermKind::ProjectionConst => {
AliasTermKind::FreeConst { def_id }
| AliasTermKind::InherentConst { def_id }
| AliasTermKind::UnevaluatedConst { def_id }
| AliasTermKind::ProjectionConst { def_id } => {
return I::Const::new_unevaluated(
interner,
ty::UnevaluatedConst::new(self.def_id.try_into().unwrap(), self.args),
ty::UnevaluatedConst::new(def_id.try_into().unwrap(), self.args),
)
.into();
}
AliasTermKind::ProjectionTy => ty::Projection { def_id: self.def_id },
AliasTermKind::InherentTy => ty::Inherent { def_id: self.def_id },
AliasTermKind::OpaqueTy => ty::Opaque { def_id: self.def_id },
AliasTermKind::FreeTy => ty::Free { def_id: self.def_id },
AliasTermKind::ProjectionTy { def_id } => ty::Projection { def_id },
AliasTermKind::InherentTy { def_id } => ty::Inherent { def_id },
AliasTermKind::OpaqueTy { def_id } => ty::Opaque { def_id },
AliasTermKind::FreeTy { def_id } => ty::Free { def_id },
};
Ty::new_alias(interner, ty::AliasTy::new_from_args(interner, alias_ty_kind, self.args))
.into()
}
pub fn with_args(self, interner: I, args: I::GenericArgs) -> Self {
Self::new_from_args(interner, self.kind, args)
}
}
/// The following methods work only with (trait) associated term projections.
@@ -742,7 +789,7 @@ pub fn self_ty(self) -> I::Ty {
pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
AliasTerm::new(
interner,
self.def_id,
self.kind,
[self_ty.into()].into_iter().chain(self.args.iter().skip(1)),
)
}
@@ -751,11 +798,11 @@ pub fn trait_def_id(self, interner: I) -> I::TraitId {
assert!(
matches!(
self.kind(interner),
AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst
AliasTermKind::ProjectionTy { .. } | AliasTermKind::ProjectionConst { .. }
),
"expected a projection"
);
interner.parent(self.def_id).try_into().unwrap()
interner.parent(self.def_id()).try_into().unwrap()
}
/// Extracts the underlying trait reference and own args from this projection.
@@ -763,7 +810,7 @@ pub fn trait_def_id(self, interner: I) -> I::TraitId {
/// then this function would return a `T: StreamingIterator` trait reference and
/// `['a]` as the own args.
pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
interner.trait_ref_and_own_args_for_alias(self.def_id(), self.args)
}
/// Extracts the underlying trait reference from this projection.
@@ -804,7 +851,7 @@ pub fn rebase_inherent_args_onto_impl(
) -> I::GenericArgs {
debug_assert!(matches!(
self.kind(interner),
AliasTermKind::InherentTy | AliasTermKind::InherentConst
AliasTermKind::InherentTy { .. } | AliasTermKind::InherentConst { .. }
));
interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1)))
}
@@ -812,13 +859,11 @@ pub fn rebase_inherent_args_onto_impl(
impl<I: Interner> From<ty::AliasTy<I>> for AliasTerm<I> {
fn from(ty: ty::AliasTy<I>) -> Self {
AliasTerm { args: ty.args, def_id: ty.kind.def_id(), _use_alias_term_new_instead: () }
}
}
impl<I: Interner> From<ty::UnevaluatedConst<I>> for AliasTerm<I> {
fn from(ct: ty::UnevaluatedConst<I>) -> Self {
AliasTerm { args: ct.args, def_id: ct.def.into(), _use_alias_term_new_instead: () }
AliasTerm {
args: ty.args,
kind: AliasTermKind::from(ty.kind),
_use_alias_term_new_instead: (),
}
}
}
@@ -864,7 +909,7 @@ pub fn trait_def_id(self, interner: I) -> I::TraitId {
}
pub fn def_id(self) -> I::DefId {
self.projection_term.def_id
self.projection_term.def_id()
}
}
@@ -885,7 +930,7 @@ pub fn term(&self) -> ty::Binder<I, I::Term> {
/// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
pub fn item_def_id(&self) -> I::DefId {
// Ok to skip binder since trait `DefId` does not care about regions.
self.skip_binder().projection_term.def_id
self.skip_binder().projection_term.def_id()
}
}
@@ -924,7 +969,7 @@ pub fn trait_def_id(self, interner: I) -> I::TraitId {
}
pub fn def_id(self) -> I::DefId {
self.alias.def_id
self.alias.def_id()
}
}
+13 -13
View File
@@ -220,7 +220,7 @@ fn relate<R: TypeRelation<I>>(
)))
} else {
let cx = relation.cx();
let args = if let Some(variances) = cx.opt_alias_variances(a.kind, a.kind.def_id()) {
let args = if let Some(variances) = cx.opt_alias_variances(a.kind) {
relate_args_with_variances(relation, variances, a.args, b.args)?
} else {
relate_args_invariantly(relation, a.args, b.args)?
@@ -236,27 +236,27 @@ fn relate<R: TypeRelation<I>>(
a: ty::AliasTerm<I>,
b: ty::AliasTerm<I>,
) -> RelateResult<I, ty::AliasTerm<I>> {
if a.def_id != b.def_id {
Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.def_id, b.def_id)))
if a.def_id() != b.def_id() {
Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.def_id(), b.def_id())))
} else {
let args = match a.kind(relation.cx()) {
ty::AliasTermKind::OpaqueTy => relate_args_with_variances(
ty::AliasTermKind::OpaqueTy { .. } => relate_args_with_variances(
relation,
relation.cx().variances_of(a.def_id),
relation.cx().variances_of(a.def_id()),
a.args,
b.args,
)?,
ty::AliasTermKind::ProjectionTy
| ty::AliasTermKind::FreeConst
| ty::AliasTermKind::FreeTy
| ty::AliasTermKind::InherentTy
| ty::AliasTermKind::InherentConst
| ty::AliasTermKind::UnevaluatedConst
| ty::AliasTermKind::ProjectionConst => {
ty::AliasTermKind::ProjectionTy { .. }
| ty::AliasTermKind::FreeConst { .. }
| ty::AliasTermKind::FreeTy { .. }
| ty::AliasTermKind::InherentTy { .. }
| ty::AliasTermKind::InherentConst { .. }
| ty::AliasTermKind::UnevaluatedConst { .. }
| ty::AliasTermKind::ProjectionConst { .. } => {
relate_args_invariantly(relation, a.args, b.args)?
}
};
Ok(ty::AliasTerm::new_from_args(relation.cx(), a.def_id, args))
Ok(a.with_args(relation.cx(), args))
}
}
}
+16 -4
View File
@@ -346,6 +346,7 @@ dependencies = [
"vex-sdk",
"wasip1",
"wasip2",
"wasip3",
"windows-link 0.0.0",
]
@@ -418,9 +419,20 @@ dependencies = [
[[package]]
name = "wasip2"
version = "1.0.2+wasi-0.2.9"
version = "1.0.3+wasi-0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
dependencies = [
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
"wit-bindgen",
]
[[package]]
name = "wasip3"
version = "0.6.0+wasi-0.3.0-rc-2026-03-15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed83456dd6a0b8581998c0365e4651fa2997e5093b49243b7f35391afaa7a3d9"
dependencies = [
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
@@ -513,9 +525,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "wit-bindgen"
version = "0.51.0"
version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
dependencies = [
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
+2 -1
View File
@@ -176,7 +176,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
#[stable(feature = "cstr_default", since = "1.10.0")]
impl Default for &CStr {
#[rustc_const_unstable(feature = "const_default", issue = "143894")]
impl const Default for &CStr {
#[inline]
fn default() -> Self {
c""
+30 -11
View File
@@ -213,14 +213,15 @@ struct VaListInner {
/// assert_eq!(unsafe { my_func(3, 42i32, -7i32, 20i32) }, 55);
/// ```
///
/// The [`VaList::arg`] method can be used to read an argument from the list. This method
/// automatically advances the `VaList` to the next argument. The C equivalent is `va_arg`.
/// The [`VaList::arg`] method reads the next argument from the variable argument list,
/// and is equivalent to C `va_arg`.
///
/// Cloning a `VaList` performs the equivalent of C `va_copy`, producing an independent cursor
/// that arguments can be read from without affecting the original. Dropping a `VaList` performs
/// the equivalent of C `va_end`.
///
/// This can be used across an FFI boundary, and fully matches the platform's `va_list`.
/// A `VaList` can be used across an FFI boundary, and fully matches the platform's `va_list` in
/// terms of layout and ABI.
#[repr(transparent)]
#[lang = "va_list"]
pub struct VaList<'a> {
@@ -285,17 +286,33 @@ impl<T> Sealed for *const T {}
/// Types that are valid to read using [`VaList::arg`].
///
/// This trait is implemented for primitive types that have a variable argument application-binary
/// interface (ABI) on the current platform. It is always implemented for:
///
/// - [`c_int`], [`c_long`] and [`c_longlong`]
/// - [`c_uint`], [`c_ulong`] and [`c_ulonglong`]
/// - [`c_double`]
/// - `*const T` and `*mut T`
///
/// Implementations for e.g. `i32` or `usize` shouldn't be relied upon directly,
/// because they may not be available on all platforms.
///
/// # Safety
///
/// The standard library implements this trait for primitive types that are
/// expected to have a variable argument application-binary interface (ABI) on all
/// platforms.
///
/// When C passes variable arguments, integers smaller than [`c_int`] and floats smaller
/// than [`c_double`] are implicitly promoted to [`c_int`] and [`c_double`] respectively.
/// Implementing this trait for types that are subject to this promotion rule is invalid.
/// When C passes variable arguments, signed integers smaller than [`c_int`] are promoted
/// to [`c_int`], unsigned integers smaller than [`c_uint`] are promoted to [`c_uint`],
/// and [`c_float`] is promoted to [`c_double`]. Implementing this trait for types that are
/// subject to this promotion rule is invalid.
///
/// [`c_int`]: core::ffi::c_int
/// [`c_long`]: core::ffi::c_long
/// [`c_longlong`]: core::ffi::c_longlong
///
/// [`c_uint`]: core::ffi::c_uint
/// [`c_ulong`]: core::ffi::c_ulong
/// [`c_ulonglong`]: core::ffi::c_ulonglong
///
/// [`c_float`]: core::ffi::c_float
/// [`c_double`]: core::ffi::c_double
// We may unseal this trait in the future, but currently our `va_arg` implementations don't support
// types with an alignment larger than 8, or with a non-scalar layout. Inline assembly can be used
@@ -352,14 +369,16 @@ const fn va_arg_safe_check<T: VaArgSafe>() {}
va_arg_safe_check::<crate::ffi::c_int>();
va_arg_safe_check::<crate::ffi::c_uint>();
va_arg_safe_check::<crate::ffi::c_long>();
va_arg_safe_check::<crate::ffi::c_ulong>();
va_arg_safe_check::<crate::ffi::c_longlong>();
va_arg_safe_check::<crate::ffi::c_ulonglong>();
va_arg_safe_check::<crate::ffi::c_double>();
};
impl<'f> VaList<'f> {
/// Read an argument from the variable argument list, and advance to the next argument.
/// Read the next argument from the variable argument list.
///
/// Only types that implement [`VaArgSafe`] can be read from a variable argument list.
///
+10 -2
View File
@@ -1911,7 +1911,11 @@ pub const fn strict_pow(self, mut exp: u32) -> Self {
}
}
/// Returns the square root of the number, rounded down.
/// Returns the integer square root of the number, rounded down.
///
/// This function returns the **principal (non-negative) square root**.
/// For a given number `n`, although both `x` and `-x` satisfy x<sup>2</sup> = n,
/// this function always returns the non-negative value.
///
/// Returns `None` if `self` is negative.
///
@@ -3206,7 +3210,11 @@ pub const fn pow(self, mut exp: u32) -> Self {
}
}
/// Returns the square root of the number, rounded down.
/// Returns the integer square root of the number, rounded down.
///
/// This function returns the **principal (non-negative) square root**.
/// For a given number `n`, although both `x` and `-x` satisfy x<sup>2</sup> = n,
/// this function always returns the non-negative value.
///
/// # Panics
///
+8 -2
View File
@@ -1118,7 +1118,10 @@ pub const fn saturating_mul(self, other: Self) -> Self {
/// assuming overflow cannot occur.
/// Overflow is unchecked, and it is undefined behavior to overflow
/// *even if the result would wrap to a non-zero value*.
/// The behavior is undefined as soon as
///
/// # Safety
///
/// This results in undefined behavior when
#[doc = sign_dependent_expr!{
$signedness ?
if signed {
@@ -1695,7 +1698,10 @@ pub const fn saturating_add(self, other: $Int) -> Self {
/// assuming overflow cannot occur.
/// Overflow is unchecked, and it is undefined behavior to overflow
/// *even if the result would wrap to a non-zero value*.
/// The behavior is undefined as soon as
///
/// # Safety
///
/// This results in undefined behavior when
#[doc = concat!("`self + rhs > ", stringify!($Int), "::MAX`.")]
///
/// # Examples
+6
View File
@@ -1,5 +1,11 @@
use core::ffi::CStr;
#[test]
fn const_default() {
const S: &CStr = <_>::default();
assert_eq!(S, c"");
}
#[test]
fn compares_as_u8s() {
let a: &CStr = c"Hello!"; // Starts with ascii
+2 -2
View File
@@ -84,12 +84,12 @@ wasip1 = { version = "1.0.0", features = [
], default-features = false }
[target.'cfg(all(target_os = "wasi", target_env = "p2"))'.dependencies]
wasip2 = { version = '1.0.2', features = [
wasip2 = { version = '1.0.3', features = [
'rustc-dep-of-std',
], default-features = false }
[target.'cfg(all(target_os = "wasi", target_env = "p3"))'.dependencies]
wasip2 = { version = '1.0.2', features = [
wasip3 = { version = '0.6.0', features = [
'rustc-dep-of-std',
], default-features = false }
+2 -2
View File
@@ -42,8 +42,8 @@
pub use wasip1::*;
}
all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => {
mod wasip2;
pub use wasip2::*;
mod wasi;
pub use wasi::*;
}
target_os = "xous" => {
mod xous;

Some files were not shown because too many files have changed in this diff Show More