mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
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:
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)| {
|
||||
|
||||
@@ -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(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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:?}"),
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -4979,6 +4979,7 @@ fn resolve_qpath(
|
||||
segment_name,
|
||||
error_implied_by_parse_error: _,
|
||||
message,
|
||||
note: _,
|
||||
} => {
|
||||
return Err(respan(
|
||||
span,
|
||||
|
||||
@@ -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 })
|
||||
},
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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() };
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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",
|
||||
|
||||
@@ -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""
|
||||
|
||||
@@ -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.
|
||||
///
|
||||
|
||||
@@ -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
|
||||
///
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user