Merge pull request #4150 from rust-lang/rustup-2025-01-25

Automatic Rustup
This commit is contained in:
Ben Kimock 2025-01-25 06:05:36 +00:00 committed by GitHub
commit 57eabac835
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
278 changed files with 5047 additions and 1562 deletions

View file

@ -109,7 +109,7 @@ jobs:
# intensive jobs to run on free runners, which however also have
# less disk space.
- name: free up disk space
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
run: src/ci/scripts/free-disk-space.sh
if: matrix.free_disk
# Rust Log Analyzer can't currently detect the PR number of a GitHub

View file

@ -28,6 +28,7 @@ use rustc_data_structures::packed::Pu128;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::tagged_ptr::Tag;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
pub use rustc_span::AttrId;
use rustc_span::source_map::{Spanned, respan};
@ -287,6 +288,7 @@ impl ParenthesizedArgs {
}
}
use crate::AstDeref;
pub use crate::node_id::{CRATE_NODE_ID, DUMMY_NODE_ID, NodeId};
/// Modifiers on a trait bound like `~const`, `?` and `!`.
@ -2165,6 +2167,14 @@ impl Ty {
}
final_ty
}
pub fn is_maybe_parenthesised_infer(&self) -> bool {
match &self.kind {
TyKind::Infer => true,
TyKind::Paren(inner) => inner.ast_deref().is_maybe_parenthesised_infer(),
_ => false,
}
}
}
#[derive(Clone, Encodable, Decodable, Debug)]
@ -2269,10 +2279,32 @@ impl TyKind {
/// Syntax used to declare a trait object.
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[repr(u8)]
pub enum TraitObjectSyntax {
Dyn,
DynStar,
None,
// SAFETY: When adding new variants make sure to update the `Tag` impl.
Dyn = 0,
DynStar = 1,
None = 2,
}
/// SAFETY: `TraitObjectSyntax` only has 3 data-less variants which means
/// it can be represented with a `u2`. We use `repr(u8)` to guarantee the
/// discriminants of the variants are no greater than `3`.
unsafe impl Tag for TraitObjectSyntax {
const BITS: u32 = 2;
fn into_usize(self) -> usize {
self as u8 as usize
}
unsafe fn from_usize(tag: usize) -> Self {
match tag {
0 => TraitObjectSyntax::Dyn,
1 => TraitObjectSyntax::DynStar,
2 => TraitObjectSyntax::None,
_ => unreachable!(),
}
}
}
#[derive(Clone, Encodable, Decodable, Debug)]

View file

@ -1,3 +1,4 @@
use intravisit::InferKind;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_hir as hir;
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
@ -265,14 +266,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
});
}
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir>) {
self.insert(const_arg.span(), const_arg.hir_id, Node::ConstArg(const_arg));
self.with_parent(const_arg.hir_id, |this| {
intravisit::walk_const_arg(this, const_arg);
});
}
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
self.insert(expr.span, expr.hir_id, Node::Expr(expr));
@ -302,22 +295,41 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
intravisit::walk_path_segment(self, path_segment);
}
fn visit_ty(&mut self, ty: &'hir Ty<'hir>) {
self.insert(ty.span, ty.hir_id, Node::Ty(ty));
fn visit_ty(&mut self, ty: &'hir Ty<'hir, AmbigArg>) {
self.insert(ty.span, ty.hir_id, Node::Ty(ty.as_unambig_ty()));
self.with_parent(ty.hir_id, |this| {
intravisit::walk_ty(this, ty);
});
}
fn visit_infer(&mut self, inf: &'hir InferArg) {
self.insert(inf.span, inf.hir_id, Node::Infer(inf));
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) {
self.insert(
const_arg.as_unambig_ct().span(),
const_arg.hir_id,
Node::ConstArg(const_arg.as_unambig_ct()),
);
self.with_parent(inf.hir_id, |this| {
intravisit::walk_inf(this, inf);
self.with_parent(const_arg.hir_id, |this| {
intravisit::walk_ambig_const_arg(this, const_arg);
});
}
fn visit_infer(
&mut self,
inf_id: HirId,
inf_span: Span,
kind: InferKind<'hir>,
) -> Self::Result {
match kind {
InferKind::Ty(ty) => self.insert(inf_span, inf_id, Node::Ty(ty)),
InferKind::Const(ct) => self.insert(inf_span, inf_id, Node::ConstArg(ct)),
InferKind::Ambig(inf) => self.insert(inf_span, inf_id, Node::Infer(inf)),
}
self.visit_id(inf_id);
}
fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));

View file

@ -48,6 +48,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::tagged_ptr::TaggedRef;
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
@ -1083,17 +1084,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
match arg {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
ast::GenericArg::Type(ty) => {
// We cannot just match on `TyKind::Infer` as `(_)` is represented as
// `TyKind::Paren(TyKind::Infer)` and should also be lowered to `GenericArg::Infer`
if ty.is_maybe_parenthesised_infer() {
return GenericArg::Infer(hir::InferArg {
hir_id: self.lower_node_id(ty.id),
span: self.lower_span(ty.span),
});
}
match &ty.kind {
TyKind::Infer if self.tcx.features().generic_arg_infer() => {
return GenericArg::Infer(hir::InferArg {
hir_id: self.lower_node_id(ty.id),
span: self.lower_span(ty.span),
});
}
// We parse const arguments as path types as we cannot distinguish them during
// parsing. We try to resolve that ambiguity by attempting resolution in both the
// type and value namespaces. If we resolved the path in the value namespace, we
// transform it into a generic const argument.
//
// FIXME: Should we be handling `(PATH_TO_CONST)`?
TyKind::Path(None, path) => {
if let Some(res) = self
.resolver
@ -1110,15 +1116,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let ct =
self.lower_const_path_to_const_arg(path, res, ty.id, ty.span);
return GenericArg::Const(ct);
return GenericArg::Const(ct.try_as_ambig_ct().unwrap());
}
}
}
_ => {}
}
GenericArg::Type(self.lower_ty(ty, itctx))
GenericArg::Type(self.lower_ty(ty, itctx).try_as_ambig_ty().unwrap())
}
ast::GenericArg::Const(ct) => {
GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap())
}
ast::GenericArg::Const(ct) => GenericArg::Const(self.lower_anon_const_to_const_arg(ct)),
}
}
@ -1158,7 +1166,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let lifetime_bound = this.elided_dyn_bound(t.span);
(bounds, lifetime_bound)
});
let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
let kind = hir::TyKind::TraitObject(
bounds,
TaggedRef::new(lifetime_bound, TraitObjectSyntax::None),
);
return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
}
@ -1185,7 +1196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
let kind = match &t.kind {
TyKind::Infer => hir::TyKind::Infer,
TyKind::Infer => hir::TyKind::Infer(()),
TyKind::Err(guar) => hir::TyKind::Err(*guar),
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
@ -1309,7 +1320,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
(bounds, lifetime_bound)
});
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
hir::TyKind::TraitObject(bounds, TaggedRef::new(lifetime_bound, *kind))
}
TyKind::ImplTrait(def_node_id, bounds) => {
let span = t.span;
@ -2041,7 +2052,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
.stash(c.value.span, StashKey::UnderscoreForArrayLengths);
}
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span));
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ());
self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
}
_ => self.lower_anon_const_to_const_arg(c),
@ -2365,8 +2376,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir_id = self.next_id();
hir::TyKind::TraitObject(
arena_vec![self; principal],
self.elided_dyn_bound(span),
TraitObjectSyntax::None,
TaggedRef::new(self.elided_dyn_bound(span), TraitObjectSyntax::None),
)
}
_ => hir::TyKind::Path(hir::QPath::Resolved(None, path)),

View file

@ -525,7 +525,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
};
let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
let args = smallvec![GenericArg::Type(
self.arena.alloc(self.ty_tup(*inputs_span, inputs)).try_as_ambig_ty().unwrap()
)];
// If we have a bound like `async Fn() -> T`, make sure that we mark the
// `Output = T` associated type bound with the right feature gates.

View file

@ -8,7 +8,7 @@ use rustc_hir::QPath::Resolved;
use rustc_hir::WherePredicateKind::BoundPredicate;
use rustc_hir::def::Res::Def;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
use rustc_middle::bug;
@ -887,7 +887,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if alias_ty.span.desugaring_kind().is_some() {
// Skip `async` desugaring `impl Future`.
}
if let TyKind::TraitObject(_, lt, _) = alias_ty.kind {
if let TyKind::TraitObject(_, lt) = alias_ty.kind {
if lt.ident.name == kw::Empty {
spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
} else {
@ -987,7 +987,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
for found_did in found_dids {
let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
hir_v.visit_ty(self_ty);
hir_v.visit_ty_unambig(self_ty);
debug!("trait spans found: {:?}", traits);
for span in &traits {
let mut multi_span: MultiSpan = vec![*span].into();

View file

@ -432,7 +432,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
// must highlight the variable.
// NOTE(eddyb) this is handled in/by the sole caller
// (`give_name_if_anonymous_region_appears_in_arguments`).
hir::TyKind::Infer => None,
hir::TyKind::Infer(()) => None,
_ => Some(argument_hir_ty),
}
@ -615,7 +615,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
}
(GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => {
search_stack.push((ty, hir_ty));
search_stack.push((ty, hir_ty.as_unambig_ty()));
}
(GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => {

View file

@ -444,7 +444,6 @@ impl WriteBackendMethods for GccCodegenBackend {
}
fn autodiff(
_cgcx: &CodegenContext<Self>,
_tcx: TyCtxt<'_>,
_module: &ModuleCodegen<Self::Module>,
_diff_fncs: Vec<AutoDiffItem>,
_config: &ModuleConfig,

View file

@ -1,4 +1,4 @@
use std::borrow::Cow;
use std::borrow::{Borrow, Cow};
use std::ops::Deref;
use std::{iter, ptr};
@ -31,20 +31,22 @@ use tracing::{debug, instrument};
use crate::abi::FnAbiLlvmExt;
use crate::attributes;
use crate::common::Funclet;
use crate::context::CodegenCx;
use crate::context::{CodegenCx, SimpleCx};
use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, True};
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
// All Builders must have an llfn associated with them
#[must_use]
pub(crate) struct Builder<'a, 'll, 'tcx> {
pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow<SimpleCx<'ll>>> {
pub llbuilder: &'ll mut llvm::Builder<'ll>,
pub cx: &'a CodegenCx<'ll, 'tcx>,
pub cx: &'a CX,
}
impl Drop for Builder<'_, '_, '_> {
pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SimpleCx<'ll>>;
pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, CodegenCx<'ll, 'tcx>>;
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> {
fn drop(&mut self) {
unsafe {
llvm::LLVMDisposeBuilder(&mut *(self.llbuilder as *mut _));
@ -52,6 +54,112 @@ impl Drop for Builder<'_, '_, '_> {
}
}
impl<'a, 'll> SBuilder<'a, 'll> {
fn call(
&mut self,
llty: &'ll Type,
llfn: &'ll Value,
args: &[&'ll Value],
funclet: Option<&Funclet<'ll>>,
) -> &'ll Value {
debug!("call {:?} with args ({:?})", llfn, args);
let args = self.check_call("call", llty, llfn, args);
let funclet_bundle = funclet.map(|funclet| funclet.bundle());
let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
if let Some(funclet_bundle) = funclet_bundle {
bundles.push(funclet_bundle);
}
let call = unsafe {
llvm::LLVMBuildCallWithOperandBundles(
self.llbuilder,
llty,
llfn,
args.as_ptr() as *const &llvm::Value,
args.len() as c_uint,
bundles.as_ptr(),
bundles.len() as c_uint,
c"".as_ptr(),
)
};
call
}
fn with_scx(scx: &'a SimpleCx<'ll>) -> Self {
// Create a fresh builder from the simple context.
let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.llcx) };
SBuilder { llbuilder, cx: scx }
}
}
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
pub(crate) fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe { llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) }
}
fn ret_void(&mut self) {
unsafe {
llvm::LLVMBuildRetVoid(self.llbuilder);
}
}
fn ret(&mut self, v: &'ll Value) {
unsafe {
llvm::LLVMBuildRet(self.llbuilder, v);
}
}
}
impl<'a, 'll> SBuilder<'a, 'll> {
fn build(cx: &'a SimpleCx<'ll>, llbb: &'ll BasicBlock) -> SBuilder<'a, 'll> {
let bx = SBuilder::with_scx(cx);
unsafe {
llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);
}
bx
}
fn check_call<'b>(
&mut self,
typ: &str,
fn_ty: &'ll Type,
llfn: &'ll Value,
args: &'b [&'ll Value],
) -> Cow<'b, [&'ll Value]> {
assert!(
self.cx.type_kind(fn_ty) == TypeKind::Function,
"builder::{typ} not passed a function, but {fn_ty:?}"
);
let param_tys = self.cx.func_params_types(fn_ty);
let all_args_match = iter::zip(&param_tys, args.iter().map(|&v| self.cx.val_ty(v)))
.all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);
if all_args_match {
return Cow::Borrowed(args);
}
let casted_args: Vec<_> = iter::zip(param_tys, args)
.enumerate()
.map(|(i, (expected_ty, &actual_val))| {
let actual_ty = self.cx.val_ty(actual_val);
if expected_ty != actual_ty {
debug!(
"type mismatch in function call of {:?}. \
Expected {:?} for param {}, got {:?}; injecting bitcast",
llfn, expected_ty, i, actual_ty
);
self.bitcast(actual_val, expected_ty)
} else {
actual_val
}
})
.collect();
Cow::Owned(casted_args)
}
}
/// Empty string, to be used where LLVM expects an instruction name, indicating
/// that the instruction is to be left unnamed (i.e. numbered, in textual IR).
// FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer.
@ -1222,6 +1330,14 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
}
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
fn build(cx: &'a CodegenCx<'ll, 'tcx>, llbb: &'ll BasicBlock) -> Builder<'a, 'll, 'tcx> {
let bx = Builder::with_cx(cx);
unsafe {
llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);
}
bx
}
fn with_cx(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {
// Create a fresh builder from the crate context.
let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(cx.llcx) };
@ -1231,13 +1347,16 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
pub(crate) fn llfn(&self) -> &'ll Value {
unsafe { llvm::LLVMGetBasicBlockParent(self.llbb()) }
}
}
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
fn position_at_start(&mut self, llbb: &'ll BasicBlock) {
unsafe {
llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb);
}
}
}
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
fn align_metadata(&mut self, load: &'ll Value, align: Align) {
unsafe {
let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))];
@ -1259,7 +1378,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
self.set_metadata(inst, llvm::MD_unpredictable, md);
}
}
}
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
pub(crate) fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) }
}
@ -1360,7 +1480,9 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
let ret = unsafe { llvm::LLVMBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) };
ret.expect("LLVM does not have support for catchret")
}
}
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
fn check_call<'b>(
&mut self,
typ: &str,
@ -1401,11 +1523,13 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
Cow::Owned(casted_args)
}
}
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
pub(crate) fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value {
unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
}
}
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
let (ty, f) = self.cx.get_intrinsic(intrinsic);
self.call(ty, None, None, f, args, None, None)
@ -1423,7 +1547,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
}
}
impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
pub(crate) fn phi(
&mut self,
ty: &'ll Type,
@ -1443,7 +1568,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint);
}
}
}
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
let src_ty = self.cx.val_ty(val);
let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector {

View file

@ -3,20 +3,19 @@ use std::ptr;
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode};
use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_ssa::back::write::ModuleConfig;
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
use rustc_errors::FatalError;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::Lto;
use tracing::{debug, trace};
use crate::back::write::{llvm_err, llvm_optimize};
use crate::builder::Builder;
use crate::declare::declare_raw_fn;
use crate::builder::SBuilder;
use crate::context::SimpleCx;
use crate::declare::declare_simple_fn;
use crate::errors::LlvmError;
use crate::llvm::AttributePlace::Function;
use crate::llvm::{Metadata, True};
use crate::value::Value;
use crate::{CodegenContext, LlvmCodegenBackend, ModuleLlvm, attributes, context, llvm};
use crate::{CodegenContext, LlvmCodegenBackend, ModuleLlvm, attributes, llvm};
fn get_params(fnc: &Value) -> Vec<&Value> {
unsafe {
@ -38,8 +37,8 @@ fn get_params(fnc: &Value) -> Vec<&Value> {
/// [^1]: <https://enzyme.mit.edu/getting_started/CallingConvention/>
// FIXME(ZuseZ4): `outer_fn` should include upstream safety checks to
// cover some assumptions of enzyme/autodiff, which could lead to UB otherwise.
fn generate_enzyme_call<'ll, 'tcx>(
cx: &context::CodegenCx<'ll, 'tcx>,
fn generate_enzyme_call<'ll>(
cx: &SimpleCx<'ll>,
fn_to_diff: &'ll Value,
outer_fn: &'ll Value,
attrs: AutoDiffAttrs,
@ -112,7 +111,7 @@ fn generate_enzyme_call<'ll, 'tcx>(
//FIXME(ZuseZ4): the CC/Addr/Vis values are best effort guesses, we should look at tests and
// think a bit more about what should go here.
let cc = llvm::LLVMGetFunctionCallConv(outer_fn);
let ad_fn = declare_raw_fn(
let ad_fn = declare_simple_fn(
cx,
&ad_name,
llvm::CallConv::try_from(cc).expect("invalid callconv"),
@ -132,7 +131,7 @@ fn generate_enzyme_call<'ll, 'tcx>(
llvm::LLVMRustEraseInstFromParent(br);
let last_inst = llvm::LLVMRustGetLastInstruction(entry).unwrap();
let mut builder = Builder::build(cx, entry);
let mut builder = SBuilder::build(cx, entry);
let num_args = llvm::LLVMCountParams(&fn_to_diff);
let mut args = Vec::with_capacity(num_args as usize + 1);
@ -236,7 +235,7 @@ fn generate_enzyme_call<'ll, 'tcx>(
}
}
let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
let call = builder.call(enzyme_ty, ad_fn, &args, None);
// This part is a bit iffy. LLVM requires that a call to an inlineable function has some
// metadata attachted to it, but we just created this code oota. Given that the
@ -274,10 +273,9 @@ fn generate_enzyme_call<'ll, 'tcx>(
}
}
pub(crate) fn differentiate<'ll, 'tcx>(
pub(crate) fn differentiate<'ll>(
module: &'ll ModuleCodegen<ModuleLlvm>,
cgcx: &CodegenContext<LlvmCodegenBackend>,
tcx: TyCtxt<'tcx>,
diff_items: Vec<AutoDiffItem>,
config: &ModuleConfig,
) -> Result<(), FatalError> {
@ -286,8 +284,7 @@ pub(crate) fn differentiate<'ll, 'tcx>(
}
let diag_handler = cgcx.create_dcx();
let (_, cgus) = tcx.collect_and_partition_mono_items(());
let cx = context::CodegenCx::new(tcx, &cgus.first().unwrap(), &module.module_llvm);
let cx = SimpleCx { llmod: module.module_llvm.llmod(), llcx: module.module_llvm.llcx };
// Before dumping the module, we want all the TypeTrees to become part of the module.
for item in diff_items.iter() {

View file

@ -1,11 +1,13 @@
use std::borrow::Borrow;
use std::cell::{Cell, RefCell};
use std::ffi::{CStr, c_char, c_uint};
use std::ops::Deref;
use std::str;
use rustc_abi::{HasDataLayout, TargetDataLayout, VariantIdx};
use rustc_codegen_ssa::back::versioned_llvm_target;
use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
use rustc_codegen_ssa::common::TypeKind;
use rustc_codegen_ssa::errors as ssa_errors;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
@ -30,23 +32,46 @@ use smallvec::SmallVec;
use crate::back::write::to_llvm_code_model;
use crate::callee::get_fn;
use crate::common::AsCCharPtr;
use crate::common::{self, AsCCharPtr};
use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
use crate::llvm::{Metadata, MetadataType};
use crate::type_::Type;
use crate::value::Value;
use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util};
/// `TyCtxt` (and related cache datastructures) can't be move between threads.
/// However, there are various cx related functions which we want to be available to the builder and
/// other compiler pieces. Here we define a small subset which has enough information and can be
/// moved around more freely.
pub(crate) struct SimpleCx<'ll> {
pub llmod: &'ll llvm::Module,
pub llcx: &'ll llvm::Context,
}
impl<'ll> Borrow<SimpleCx<'ll>> for CodegenCx<'ll, '_> {
fn borrow(&self) -> &SimpleCx<'ll> {
&self.scx
}
}
impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> {
type Target = SimpleCx<'ll>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.scx
}
}
/// There is one `CodegenCx` per codegen unit. Each one has its own LLVM
/// `llvm::Context` so that several codegen units may be processed in parallel.
/// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`.
pub(crate) struct CodegenCx<'ll, 'tcx> {
pub tcx: TyCtxt<'tcx>,
pub scx: SimpleCx<'ll>,
pub use_dll_storage_attrs: bool,
pub tls_model: llvm::ThreadLocalMode,
pub llmod: &'ll llvm::Module,
pub llcx: &'ll llvm::Context,
pub codegen_unit: &'tcx CodegenUnit<'tcx>,
/// Cache instances of monomorphic and polymorphic items
@ -553,10 +578,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
CodegenCx {
tcx,
scx: SimpleCx { llcx, llmod },
use_dll_storage_attrs,
tls_model,
llmod,
llcx,
codegen_unit,
instances: Default::default(),
vtables: Default::default(),
@ -600,6 +624,11 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
llvm::set_section(g, c"llvm.metadata");
}
}
}
impl<'ll> SimpleCx<'ll> {
pub(crate) fn val_ty(&self, v: &'ll Value) -> &'ll Type {
common::val_ty(v)
}
pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value {
unsafe { llvm::LLVMMetadataAsValue(self.llcx, metadata) }
@ -625,6 +654,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
llvm::LLVMMDStringInContext2(self.llcx, name.as_ptr() as *const c_char, name.len())
})
}
pub(crate) fn type_kind(&self, ty: &'ll Type) -> TypeKind {
unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() }
}
}
impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
@ -1178,6 +1211,20 @@ impl CodegenCx<'_, '_> {
}
}
// This is a duplication of the set_metadata function above. However, so far it's the only one
// shared between both contexts, so it doesn't seem worth it to make the Cx generic like we did it
// for the Builder.
impl SimpleCx<'_> {
#[allow(unused)]
/// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`.
pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) {
unsafe {
let node = llvm::LLVMMetadataAsValue(&self.llcx, md);
llvm::LLVMSetMetadata(val, kind_id as c_uint, node);
}
}
}
impl HasDataLayout for CodegenCx<'_, '_> {
#[inline]
fn data_layout(&self) -> &TargetDataLayout {

View file

@ -51,7 +51,7 @@ pub(crate) fn prepare_covfun_record<'tcx>(
is_used: bool,
) -> Option<CovfunRecord<'tcx>> {
let fn_cov_info = tcx.instance_mir(instance.def).function_coverage_info.as_deref()?;
let ids_info = tcx.coverage_ids_info(instance.def);
let ids_info = tcx.coverage_ids_info(instance.def)?;
let expressions = prepare_expressions(fn_cov_info, ids_info, is_used);

View file

@ -8,7 +8,6 @@ use rustc_codegen_ssa::traits::{
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::Instance;
use rustc_middle::ty::layout::HasTyCtxt;
use tracing::{debug, instrument};
use crate::builder::Builder;
@ -147,6 +146,10 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
debug!("function has a coverage statement but no coverage info");
return;
};
let Some(ids_info) = bx.tcx.coverage_ids_info(instance.def) else {
debug!("function has a coverage statement but no IDs info");
return;
};
// Mark the instance as used in this CGU, for coverage purposes.
// This includes functions that were not partitioned into this CGU,
@ -162,8 +165,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
// be smaller than the number originally inserted by the instrumentor,
// if some high-numbered counters were removed by MIR optimizations.
// If so, LLVM's profiler runtime will use fewer physical counters.
let num_counters =
bx.tcx().coverage_ids_info(instance.def).num_counters_after_mir_opts();
let num_counters = ids_info.num_counters_after_mir_opts();
assert!(
num_counters as usize <= function_coverage_info.num_counters,
"num_counters disagreement: query says {num_counters} but function info only has {}",

View file

@ -21,26 +21,26 @@ use tracing::debug;
use crate::abi::{FnAbi, FnAbiLlvmExt};
use crate::common::AsCCharPtr;
use crate::context::CodegenCx;
use crate::context::{CodegenCx, SimpleCx};
use crate::llvm::AttributePlace::Function;
use crate::llvm::Visibility;
use crate::type_::Type;
use crate::value::Value;
use crate::{attributes, llvm};
/// Declare a function.
/// Declare a function with a SimpleCx.
///
/// If theres a value with the same name already declared, the function will
/// update the declaration and return existing Value instead.
pub(crate) fn declare_raw_fn<'ll>(
cx: &CodegenCx<'ll, '_>,
pub(crate) fn declare_simple_fn<'ll>(
cx: &SimpleCx<'ll>,
name: &str,
callconv: llvm::CallConv,
unnamed: llvm::UnnamedAddr,
visibility: llvm::Visibility,
ty: &'ll Type,
) -> &'ll Value {
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
debug!("declare_simple_fn(name={:?}, ty={:?})", name, ty);
let llfn = unsafe {
llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty)
};
@ -49,6 +49,24 @@ pub(crate) fn declare_raw_fn<'ll>(
llvm::SetUnnamedAddress(llfn, unnamed);
llvm::set_visibility(llfn, visibility);
llfn
}
/// Declare a function.
///
/// If theres a value with the same name already declared, the function will
/// update the declaration and return existing Value instead.
pub(crate) fn declare_raw_fn<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
name: &str,
callconv: llvm::CallConv,
unnamed: llvm::UnnamedAddr,
visibility: llvm::Visibility,
ty: &'ll Type,
) -> &'ll Value {
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
let llfn = declare_simple_fn(cx, name, callconv, unnamed, visibility, ty);
let mut attrs = SmallVec::<[_; 4]>::new();
if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {

View file

@ -1081,11 +1081,11 @@ fn codegen_emcc_try<'ll>(
// Helper function to give a Block to a closure to codegen a shim function.
// This is currently primarily used for the `try` intrinsic functions above.
fn gen_fn<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
fn gen_fn<'a, 'll, 'tcx>(
cx: &'a CodegenCx<'ll, 'tcx>,
name: &str,
rust_fn_sig: ty::PolyFnSig<'tcx>,
codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
) -> (&'ll Type, &'ll Value) {
let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
let llty = fn_abi.llvm_type(cx);
@ -1104,9 +1104,9 @@ fn gen_fn<'ll, 'tcx>(
// catch exceptions.
//
// This function is only generated once and is then cached.
fn get_rust_try_fn<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
fn get_rust_try_fn<'a, 'll, 'tcx>(
cx: &'a CodegenCx<'ll, 'tcx>,
codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
) -> (&'ll Type, &'ll Value) {
if let Some(llfn) = cx.rust_try_fn.get() {
return llfn;

View file

@ -237,7 +237,6 @@ impl WriteBackendMethods for LlvmCodegenBackend {
/// Generate autodiff rules
fn autodiff(
cgcx: &CodegenContext<Self>,
tcx: TyCtxt<'_>,
module: &ModuleCodegen<Self::Module>,
diff_fncs: Vec<AutoDiffItem>,
config: &ModuleConfig,
@ -246,7 +245,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
let dcx = cgcx.create_dcx();
return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO));
}
builder::autodiff::differentiate(module, cgcx, tcx, diff_fncs, config)
builder::autodiff::differentiate(module, cgcx, diff_fncs, config)
}
}

View file

@ -11,7 +11,7 @@ use rustc_middle::ty::{self, Ty};
use rustc_target::callconv::{CastTarget, FnAbi, Reg};
use crate::abi::{FnAbiLlvmExt, LlvmType};
use crate::context::CodegenCx;
use crate::context::{CodegenCx, SimpleCx};
pub(crate) use crate::llvm::Type;
use crate::llvm::{Bool, False, Metadata, True};
use crate::type_of::LayoutLlvmExt;
@ -35,7 +35,8 @@ impl fmt::Debug for Type {
}
}
impl<'ll> CodegenCx<'ll, '_> {
impl<'ll> CodegenCx<'ll, '_> {}
impl<'ll> SimpleCx<'ll> {
pub(crate) fn type_named_struct(&self, name: &str) -> &'ll Type {
let name = SmallCStr::new(name);
unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) }
@ -44,11 +45,9 @@ impl<'ll> CodegenCx<'ll, '_> {
pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) {
unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) }
}
pub(crate) fn type_void(&self) -> &'ll Type {
unsafe { llvm::LLVMVoidTypeInContext(self.llcx) }
}
pub(crate) fn type_token(&self) -> &'ll Type {
unsafe { llvm::LLVMTokenTypeInContext(self.llcx) }
}
@ -75,7 +74,8 @@ impl<'ll> CodegenCx<'ll, '_> {
args
}
}
}
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
pub(crate) fn type_bool(&self) -> &'ll Type {
self.type_i8()
}
@ -120,7 +120,8 @@ impl<'ll> CodegenCx<'ll, '_> {
assert_eq!(size % unit_size, 0);
self.type_array(self.type_from_integer(unit), size / unit_size)
}
}
impl<'ll> SimpleCx<'ll> {
pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) }
}

View file

@ -4,7 +4,6 @@ use std::sync::Arc;
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
use rustc_data_structures::memmap::Mmap;
use rustc_errors::FatalError;
use rustc_middle::ty::TyCtxt;
use super::write::CodegenContext;
use crate::ModuleCodegen;
@ -89,13 +88,12 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
pub unsafe fn autodiff(
self,
cgcx: &CodegenContext<B>,
tcx: TyCtxt<'_>,
diff_fncs: Vec<AutoDiffItem>,
config: &ModuleConfig,
) -> Result<LtoModuleCodegen<B>, FatalError> {
match &self {
LtoModuleCodegen::Fat(module) => {
B::autodiff(cgcx, tcx, &module, diff_fncs, config)?;
B::autodiff(cgcx, &module, diff_fncs, config)?;
}
_ => panic!("autodiff called with non-fat LTO module"),
}

View file

@ -1,10 +1,14 @@
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind};
use rustc_attr_parsing::InstructionSetAttr;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility};
use rustc_middle::mir::{Body, InlineAsmOperand};
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf};
use rustc_middle::ty::{Instance, TyCtxt};
use rustc_middle::{bug, ty};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf};
use rustc_middle::ty::{Instance, Ty, TyCtxt};
use rustc_middle::{bug, span_bug, ty};
use rustc_span::sym;
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
use rustc_target::spec::WasmCAbi;
use crate::common;
use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods};
@ -32,7 +36,8 @@ pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap();
let name = cx.mangled_name(instance);
let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data);
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data, fn_abi);
let mut template_vec = Vec::new();
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin.into()));
@ -103,6 +108,7 @@ enum AsmBinaryFormat {
Elf,
Macho,
Coff,
Wasm,
}
impl AsmBinaryFormat {
@ -111,6 +117,8 @@ impl AsmBinaryFormat {
Self::Coff
} else if target.is_like_osx {
Self::Macho
} else if target.is_like_wasm {
Self::Wasm
} else {
Self::Elf
}
@ -122,6 +130,7 @@ fn prefix_and_suffix<'tcx>(
instance: Instance<'tcx>,
asm_name: &str,
item_data: &MonoItemData,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) -> (String, String) {
use std::fmt::Write;
@ -169,7 +178,7 @@ fn prefix_and_suffix<'tcx>(
}
Linkage::LinkOnceAny | Linkage::LinkOnceODR | Linkage::WeakAny | Linkage::WeakODR => {
match asm_binary_format {
AsmBinaryFormat::Elf | AsmBinaryFormat::Coff => {
AsmBinaryFormat::Elf | AsmBinaryFormat::Coff | AsmBinaryFormat::Wasm => {
writeln!(w, ".weak {asm_name}")?;
}
AsmBinaryFormat::Macho => {
@ -264,7 +273,161 @@ fn prefix_and_suffix<'tcx>(
writeln!(end, "{}", arch_suffix).unwrap();
}
}
AsmBinaryFormat::Wasm => {
let section = link_section.unwrap_or(format!(".text.{asm_name}"));
writeln!(begin, ".section {section},\"\",@").unwrap();
// wasm functions cannot be aligned, so skip
write_linkage(&mut begin).unwrap();
if let Visibility::Hidden = item_data.visibility {
writeln!(begin, ".hidden {asm_name}").unwrap();
}
writeln!(begin, ".type {asm_name}, @function").unwrap();
if !arch_prefix.is_empty() {
writeln!(begin, "{}", arch_prefix).unwrap();
}
writeln!(begin, "{asm_name}:").unwrap();
writeln!(
begin,
".functype {asm_name} {}",
wasm_functype(tcx, fn_abi, instance.def_id())
)
.unwrap();
writeln!(end).unwrap();
// .size is ignored for function symbols, so we can skip it
writeln!(end, "end_function").unwrap();
}
}
(begin, end)
}
/// The webassembly type signature for the given function.
///
/// Used by the `.functype` directive on wasm targets.
fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id: DefId) -> String {
let mut signature = String::with_capacity(64);
let ptr_type = match tcx.data_layout.pointer_size.bits() {
32 => "i32",
64 => "i64",
other => bug!("wasm pointer size cannot be {other} bits"),
};
// FIXME: remove this once the wasm32-unknown-unknown ABI is fixed
// please also add `wasm32-unknown-unknown` back in `tests/assembly/wasm32-naked-fn.rs`
// basically the commit introducing this comment should be reverted
if let PassMode::Pair { .. } = fn_abi.ret.mode {
let _ = WasmCAbi::Legacy;
span_bug!(
tcx.def_span(def_id),
"cannot return a pair (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
);
}
let hidden_return = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
signature.push('(');
if hidden_return {
signature.push_str(ptr_type);
if !fn_abi.args.is_empty() {
signature.push_str(", ");
}
}
let mut it = fn_abi.args.iter().peekable();
while let Some(arg_abi) = it.next() {
wasm_type(tcx, &mut signature, arg_abi, ptr_type, def_id);
if it.peek().is_some() {
signature.push_str(", ");
}
}
signature.push_str(") -> (");
if !hidden_return {
wasm_type(tcx, &mut signature, &fn_abi.ret, ptr_type, def_id);
}
signature.push(')');
signature
}
fn wasm_type<'tcx>(
tcx: TyCtxt<'tcx>,
signature: &mut String,
arg_abi: &ArgAbi<'_, Ty<'tcx>>,
ptr_type: &'static str,
def_id: DefId,
) {
match arg_abi.mode {
PassMode::Ignore => { /* do nothing */ }
PassMode::Direct(_) => {
let direct_type = match arg_abi.layout.backend_repr {
BackendRepr::Scalar(scalar) => wasm_primitive(scalar.primitive(), ptr_type),
BackendRepr::Vector { .. } => "v128",
BackendRepr::Memory { .. } => {
// FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed
let _ = WasmCAbi::Legacy;
span_bug!(
tcx.def_span(def_id),
"cannot use memory args (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
);
}
other => unreachable!("unexpected BackendRepr: {:?}", other),
};
signature.push_str(direct_type);
}
PassMode::Pair(_, _) => match arg_abi.layout.backend_repr {
BackendRepr::ScalarPair(a, b) => {
signature.push_str(wasm_primitive(a.primitive(), ptr_type));
signature.push_str(", ");
signature.push_str(wasm_primitive(b.primitive(), ptr_type));
}
other => unreachable!("{other:?}"),
},
PassMode::Cast { pad_i32, ref cast } => {
// For wasm, Cast is used for single-field primitive wrappers like `struct Wrapper(i64);`
assert!(!pad_i32, "not currently used by wasm calling convention");
assert!(cast.prefix[0].is_none(), "no prefix");
assert_eq!(cast.rest.total, arg_abi.layout.size, "single item");
let wrapped_wasm_type = match cast.rest.unit.kind {
RegKind::Integer => match cast.rest.unit.size.bytes() {
..=4 => "i32",
..=8 => "i64",
_ => ptr_type,
},
RegKind::Float => match cast.rest.unit.size.bytes() {
..=4 => "f32",
..=8 => "f64",
_ => ptr_type,
},
RegKind::Vector => "v128",
};
signature.push_str(wrapped_wasm_type);
}
PassMode::Indirect { .. } => signature.push_str(ptr_type),
}
}
fn wasm_primitive(primitive: Primitive, ptr_type: &'static str) -> &'static str {
match primitive {
Primitive::Int(integer, _) => match integer {
Integer::I8 | Integer::I16 | Integer::I32 => "i32",
Integer::I64 => "i64",
Integer::I128 => "i64, i64",
},
Primitive::Float(float) => match float {
Float::F16 | Float::F32 => "f32",
Float::F64 => "f64",
Float::F128 => "i64, i64",
},
Primitive::Pointer(_) => ptr_type,
}
}

View file

@ -1,7 +1,6 @@
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
use rustc_errors::{DiagCtxtHandle, FatalError};
use rustc_middle::dep_graph::WorkProduct;
use rustc_middle::ty::TyCtxt;
use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig};
@ -65,7 +64,6 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
fn autodiff(
cgcx: &CodegenContext<Self>,
tcx: TyCtxt<'_>,
module: &ModuleCodegen<Self::Module>,
diff_fncs: Vec<AutoDiffItem>,
config: &ModuleConfig,

View file

@ -15,6 +15,7 @@ pub use rustc_ast::{
};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::tagged_ptr::TaggedRef;
use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::def_id::LocalDefId;
@ -30,7 +31,7 @@ use crate::LangItem;
use crate::def::{CtorKind, DefKind, Res};
use crate::def_id::{DefId, LocalDefIdMap};
pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
use crate::intravisit::FnKind;
use crate::intravisit::{FnKind, VisitorExt};
#[derive(Debug, Copy, Clone, HashStable_Generic)]
pub struct Lifetime {
@ -263,14 +264,58 @@ impl<'hir> PathSegment<'hir> {
/// So, `ConstArg` (specifically, [`ConstArgKind`]) distinguishes between const args
/// that are [just paths](ConstArgKind::Path) (currently just bare const params)
/// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`).
///
/// The `Unambig` generic parameter represents whether the position this const is from is
/// unambiguously a const or ambiguous as to whether it is a type or a const. When in an
/// ambiguous context the parameter is instantiated with an uninhabited type making the
/// [`ConstArgKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead.
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub struct ConstArg<'hir> {
#[repr(C)]
pub struct ConstArg<'hir, Unambig = ()> {
#[stable_hasher(ignore)]
pub hir_id: HirId,
pub kind: ConstArgKind<'hir>,
pub kind: ConstArgKind<'hir, Unambig>,
}
impl<'hir> ConstArg<'hir, AmbigArg> {
/// Converts a `ConstArg` in an ambiguous position to one in an unambiguous position.
///
/// Functions accepting an unambiguous consts may expect the [`ConstArgKind::Infer`] variant
/// to be used. Care should be taken to separately handle infer consts when calling this
/// function as it cannot be handled by downstream code making use of the returned const.
///
/// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or
/// specifically matching on [`GenericArg::Infer`] when handling generic arguments.
///
/// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer]
pub fn as_unambig_ct(&self) -> &ConstArg<'hir> {
// SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the
// layout is the same across different ZST type arguments.
let ptr = self as *const ConstArg<'hir, AmbigArg> as *const ConstArg<'hir, ()>;
unsafe { &*ptr }
}
}
impl<'hir> ConstArg<'hir> {
/// Converts a `ConstArg` in an unambigous position to one in an ambiguous position. This is
/// fallible as the [`ConstArgKind::Infer`] variant is not present in ambiguous positions.
///
/// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if
/// infer consts are relevant to you then care should be taken to handle them separately.
pub fn try_as_ambig_ct(&self) -> Option<&ConstArg<'hir, AmbigArg>> {
if let ConstArgKind::Infer(_, ()) = self.kind {
return None;
}
// SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the layout is
// the same across different ZST type arguments. We also asserted that the `self` is
// not a `ConstArgKind::Infer` so there is no risk of transmuting a `()` to `AmbigArg`.
let ptr = self as *const ConstArg<'hir> as *const ConstArg<'hir, AmbigArg>;
Some(unsafe { &*ptr })
}
}
impl<'hir, Unambig> ConstArg<'hir, Unambig> {
pub fn anon_const_hir_id(&self) -> Option<HirId> {
match self.kind {
ConstArgKind::Anon(ac) => Some(ac.hir_id),
@ -282,14 +327,15 @@ impl<'hir> ConstArg<'hir> {
match self.kind {
ConstArgKind::Path(path) => path.span(),
ConstArgKind::Anon(anon) => anon.span,
ConstArgKind::Infer(span) => span,
ConstArgKind::Infer(span, _) => span,
}
}
}
/// See [`ConstArg`].
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub enum ConstArgKind<'hir> {
#[repr(u8, C)]
pub enum ConstArgKind<'hir, Unambig = ()> {
/// **Note:** Currently this is only used for bare const params
/// (`N` where `fn foo<const N: usize>(...)`),
/// not paths to any const (`N` where `const N: usize = ...`).
@ -297,11 +343,9 @@ pub enum ConstArgKind<'hir> {
/// However, in the future, we'll be using it for all of those.
Path(QPath<'hir>),
Anon(&'hir AnonConst),
/// **Note:** Not all inferred consts are represented as
/// `ConstArgKind::Infer`. In cases where it is ambiguous whether
/// a generic arg is a type or a const, inference variables are
/// represented as `GenericArg::Infer` instead.
Infer(Span),
/// This variant is not always used to represent inference consts, sometimes
/// [`GenericArg::Infer`] is used instead.
Infer(Span, Unambig),
}
#[derive(Clone, Copy, Debug, HashStable_Generic)]
@ -313,19 +357,24 @@ pub struct InferArg {
impl InferArg {
pub fn to_ty(&self) -> Ty<'static> {
Ty { kind: TyKind::Infer, span: self.span, hir_id: self.hir_id }
Ty { kind: TyKind::Infer(()), span: self.span, hir_id: self.hir_id }
}
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum GenericArg<'hir> {
Lifetime(&'hir Lifetime),
Type(&'hir Ty<'hir>),
Const(&'hir ConstArg<'hir>),
/// **Note:** Inference variables are only represented as
/// `GenericArg::Infer` in cases where it is ambiguous whether
/// a generic arg is a type or a const. Otherwise, inference variables
/// are represented as `TyKind::Infer` or `ConstArgKind::Infer`.
Type(&'hir Ty<'hir, AmbigArg>),
Const(&'hir ConstArg<'hir, AmbigArg>),
/// Inference variables in [`GenericArg`] are always represnted by
/// `GenericArg::Infer` instead of the `Infer` variants on [`TyKind`] and
/// [`ConstArgKind`] as it is not clear until hir ty lowering whether a
/// `_` argument is a type or const argument.
///
/// However, some builtin types' generic arguments are represented by [`TyKind`]
/// without a [`GenericArg`], instead directly storing a [`Ty`] or [`ConstArg`]. In
/// such cases they *are* represented by the `Infer` variants on [`TyKind`] and
/// [`ConstArgKind`] as it is not ambiguous whether the argument is a type or const.
Infer(InferArg),
}
@ -353,7 +402,7 @@ impl GenericArg<'_> {
GenericArg::Lifetime(_) => "lifetime",
GenericArg::Type(_) => "type",
GenericArg::Const(_) => "constant",
GenericArg::Infer(_) => "inferred",
GenericArg::Infer(_) => "placeholder",
}
}
@ -764,11 +813,8 @@ impl<'hir> Generics<'hir> {
&& let [.., segment] = trait_ref.path.segments
&& let Some(ret_ty) = segment.args().paren_sugar_output()
&& let ret_ty = ret_ty.peel_refs()
&& let TyKind::TraitObject(
_,
_,
TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar,
) = ret_ty.kind
&& let TyKind::TraitObject(_, tagged_ptr) = ret_ty.kind
&& let TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar = tagged_ptr.tag()
&& ret_ty.span.can_be_used_for_suggestions()
{
Some(ret_ty.span)
@ -2917,15 +2963,84 @@ impl<'hir> AssocItemConstraintKind<'hir> {
}
}
/// An uninhabited enum used to make `Infer` variants on [`Ty`] and [`ConstArg`] be
/// unreachable. Zero-Variant enums are guaranteed to have the same layout as the never
/// type.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Ty<'hir> {
pub enum AmbigArg {}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
#[repr(C)]
/// Represents a type in the `HIR`.
///
/// The `Unambig` generic parameter represents whether the position this type is from is
/// unambiguously a type or ambiguous as to whether it is a type or a const. When in an
/// ambiguous context the parameter is instantiated with an uninhabited type making the
/// [`TyKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead.
pub struct Ty<'hir, Unambig = ()> {
#[stable_hasher(ignore)]
pub hir_id: HirId,
pub kind: TyKind<'hir>,
pub span: Span,
pub kind: TyKind<'hir, Unambig>,
}
impl<'hir> Ty<'hir, AmbigArg> {
/// Converts a `Ty` in an ambiguous position to one in an unambiguous position.
///
/// Functions accepting an unambiguous types may expect the [`TyKind::Infer`] variant
/// to be used. Care should be taken to separately handle infer types when calling this
/// function as it cannot be handled by downstream code making use of the returned ty.
///
/// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or
/// specifically matching on [`GenericArg::Infer`] when handling generic arguments.
///
/// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer]
pub fn as_unambig_ty(&self) -> &Ty<'hir> {
// SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is
// the same across different ZST type arguments.
let ptr = self as *const Ty<'hir, AmbigArg> as *const Ty<'hir, ()>;
unsafe { &*ptr }
}
}
impl<'hir> Ty<'hir> {
/// Converts a `Ty` in an unambigous position to one in an ambiguous position. This is
/// fallible as the [`TyKind::Infer`] variant is not present in ambiguous positions.
///
/// Functions accepting ambiguous types will not handle the [`TyKind::Infer`] variant, if
/// infer types are relevant to you then care should be taken to handle them separately.
pub fn try_as_ambig_ty(&self) -> Option<&Ty<'hir, AmbigArg>> {
if let TyKind::Infer(()) = self.kind {
return None;
}
// SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is
// the same across different ZST type arguments. We also asserted that the `self` is
// not a `TyKind::Infer` so there is no risk of transmuting a `()` to `AmbigArg`.
let ptr = self as *const Ty<'hir> as *const Ty<'hir, AmbigArg>;
Some(unsafe { &*ptr })
}
}
impl<'hir> Ty<'hir, AmbigArg> {
pub fn peel_refs(&self) -> &Ty<'hir> {
let mut final_ty = self.as_unambig_ty();
while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
final_ty = ty;
}
final_ty
}
}
impl<'hir> Ty<'hir> {
pub fn peel_refs(&self) -> &Self {
let mut final_ty = self;
while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
final_ty = ty;
}
final_ty
}
/// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
pub fn as_generic_param(&self) -> Option<(DefId, Ident)> {
let TyKind::Path(QPath::Resolved(None, path)) = self.kind else {
@ -2942,19 +3057,11 @@ impl<'hir> Ty<'hir> {
}
}
pub fn peel_refs(&self) -> &Self {
let mut final_ty = self;
while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
final_ty = ty;
}
final_ty
}
pub fn find_self_aliases(&self) -> Vec<Span> {
use crate::intravisit::Visitor;
struct MyVisitor(Vec<Span>);
impl<'v> Visitor<'v> for MyVisitor {
fn visit_ty(&mut self, t: &'v Ty<'v>) {
fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) {
if matches!(
&t.kind,
TyKind::Path(QPath::Resolved(_, Path {
@ -2970,7 +3077,7 @@ impl<'hir> Ty<'hir> {
}
let mut my_visitor = MyVisitor(vec![]);
my_visitor.visit_ty(self);
my_visitor.visit_ty_unambig(self);
my_visitor.0
}
@ -2979,14 +3086,14 @@ impl<'hir> Ty<'hir> {
pub fn is_suggestable_infer_ty(&self) -> bool {
fn are_suggestable_generic_args(generic_args: &[GenericArg<'_>]) -> bool {
generic_args.iter().any(|arg| match arg {
GenericArg::Type(ty) => ty.is_suggestable_infer_ty(),
GenericArg::Type(ty) => ty.as_unambig_ty().is_suggestable_infer_ty(),
GenericArg::Infer(_) => true,
_ => false,
})
}
debug!(?self);
match &self.kind {
TyKind::Infer => true,
TyKind::Infer(()) => true,
TyKind::Slice(ty) => ty.is_suggestable_infer_ty(),
TyKind::Array(ty, length) => {
ty.is_suggestable_infer_ty() || matches!(length.kind, ConstArgKind::Infer(..))
@ -3200,7 +3307,9 @@ pub enum InferDelegationKind {
/// The various kinds of types recognized by the compiler.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TyKind<'hir> {
// SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind<!>` are layout compatible
#[repr(u8, C)]
pub enum TyKind<'hir, Unambig = ()> {
/// Actual type should be inherited from `DefId` signature
InferDelegation(DefId, InferDelegationKind),
/// A variable length slice (i.e., `[T]`).
@ -3230,21 +3339,22 @@ pub enum TyKind<'hir> {
TraitAscription(GenericBounds<'hir>),
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
///
/// We use pointer tagging to represent a `&'hir Lifetime` and `TraitObjectSyntax` pair
/// as otherwise this type being `repr(C)` would result in `TyKind` increasing in size.
TraitObject(&'hir [PolyTraitRef<'hir>], TaggedRef<'hir, Lifetime, TraitObjectSyntax>),
/// Unused for now.
Typeof(&'hir AnonConst),
/// `TyKind::Infer` means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
///
/// **Note:** Not all inferred types are represented as
/// `TyKind::Infer`. In cases where it is ambiguous whether
/// a generic arg is a type or a const, inference variables are
/// represented as `GenericArg::Infer` instead.
Infer,
/// Placeholder for a type that has failed to be defined.
Err(rustc_span::ErrorGuaranteed),
/// Pattern types (`pattern_type!(u32 is 1..)`)
Pat(&'hir Ty<'hir>, &'hir Pat<'hir>),
/// `TyKind::Infer` means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
///
/// This variant is not always used to represent inference types, sometimes
/// [`GenericArg::Infer`] is used instead.
Infer(Unambig),
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
@ -4537,3 +4647,6 @@ fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Deb
}
DebugFn(f)
}
#[cfg(test)]
mod tests;

View file

@ -0,0 +1,83 @@
use rustc_span::def_id::DefIndex;
use super::*;
macro_rules! define_tests {
($($name:ident $kind:ident $variant:ident {$($init:tt)*})*) => {$(
#[test]
fn $name() {
let unambig = $kind::$variant::<'_, ()> { $($init)* };
let unambig_to_ambig = unsafe { std::mem::transmute::<_, $kind<'_, AmbigArg>>(unambig) };
assert!(matches!(&unambig_to_ambig, $kind::$variant { $($init)* }));
let ambig_to_unambig = unsafe { std::mem::transmute::<_, $kind<'_, ()>>(unambig_to_ambig) };
assert!(matches!(&ambig_to_unambig, $kind::$variant { $($init)* }));
}
)*};
}
define_tests! {
cast_never TyKind Never {}
cast_tup TyKind Tup { 0: &[Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }] }
cast_ptr TyKind Ptr { 0: MutTy { ty: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }, mutbl: Mutability::Not }}
cast_array TyKind Array {
0: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never },
1: &ConstArg { hir_id: HirId::INVALID, kind: ConstArgKind::Anon(&AnonConst {
hir_id: HirId::INVALID,
def_id: LocalDefId { local_def_index: DefIndex::ZERO },
body: BodyId { hir_id: HirId::INVALID },
span: DUMMY_SP,
})}
}
cast_anon ConstArgKind Anon {
0: &AnonConst {
hir_id: HirId::INVALID,
def_id: LocalDefId { local_def_index: DefIndex::ZERO },
body: BodyId { hir_id: HirId::INVALID },
span: DUMMY_SP,
}
}
}
#[test]
fn trait_object_roundtrips() {
trait_object_roundtrips_impl(TraitObjectSyntax::Dyn);
trait_object_roundtrips_impl(TraitObjectSyntax::DynStar);
trait_object_roundtrips_impl(TraitObjectSyntax::None);
}
fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) {
let unambig = TyKind::TraitObject::<'_, ()>(
&[],
TaggedRef::new(
&const {
Lifetime {
hir_id: HirId::INVALID,
ident: Ident::new(sym::name, DUMMY_SP),
res: LifetimeName::Static,
}
},
syntax,
),
);
let unambig_to_ambig = unsafe { std::mem::transmute::<_, TyKind<'_, AmbigArg>>(unambig) };
match unambig_to_ambig {
TyKind::TraitObject(_, tagged_ref) => {
assert!(tagged_ref.tag() == syntax)
}
_ => panic!("`TyKind::TraitObject` did not roundtrip"),
};
let ambig_to_unambig = unsafe { std::mem::transmute::<_, TyKind<'_, ()>>(unambig_to_ambig) };
match ambig_to_unambig {
TyKind::TraitObject(_, tagged_ref) => {
assert!(tagged_ref.tag() == syntax)
}
_ => panic!("`TyKind::TraitObject` did not roundtrip"),
};
}

View file

@ -351,18 +351,48 @@ pub trait Visitor<'v>: Sized {
fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result {
walk_inline_const(self, c)
}
fn visit_const_arg(&mut self, c: &'v ConstArg<'v>) -> Self::Result {
walk_const_arg(self, c)
fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) -> Self::Result {
walk_generic_arg(self, generic_arg)
}
/// All types are treated as ambiguous types for the purposes of hir visiting in
/// order to ensure that visitors can handle infer vars without it being too error-prone.
///
/// See the doc comments on [`Ty`] for an explanation of what it means for a type to be
/// ambiguous.
///
/// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars.
fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) -> Self::Result {
walk_ty(self, t)
}
/// All consts are treated as ambiguous consts for the purposes of hir visiting in
/// order to ensure that visitors can handle infer vars without it being too error-prone.
///
/// See the doc comments on [`ConstArg`] for an explanation of what it means for a const to be
/// ambiguous.
///
/// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars.
fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result {
walk_ambig_const_arg(self, c)
}
#[allow(unused_variables)]
fn visit_infer(&mut self, inf_id: HirId, inf_span: Span, kind: InferKind<'v>) -> Self::Result {
self.visit_id(inf_id)
}
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) -> Self::Result {
walk_lifetime(self, lifetime)
}
fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result {
walk_expr(self, ex)
}
fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result {
walk_expr_field(self, field)
}
fn visit_ty(&mut self, t: &'v Ty<'v>) -> Self::Result {
walk_ty(self, t)
}
fn visit_pattern_type_pattern(&mut self, _p: &'v Pat<'v>) {
// Do nothing. Only a few visitors need to know the details of the pattern type,
// and they opt into it. All other visitors will just choke on our fake patterns
@ -444,15 +474,6 @@ pub trait Visitor<'v>: Sized {
fn visit_label(&mut self, label: &'v Label) -> Self::Result {
walk_label(self, label)
}
fn visit_infer(&mut self, inf: &'v InferArg) -> Self::Result {
walk_inf(self, inf)
}
fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) -> Self::Result {
walk_generic_arg(self, generic_arg)
}
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) -> Self::Result {
walk_lifetime(self, lifetime)
}
// The span is that of the surrounding type/pattern/expr/whatever.
fn visit_qpath(&mut self, qpath: &'v QPath<'v>, id: HirId, _span: Span) -> Self::Result {
walk_qpath(self, qpath, id)
@ -486,6 +507,26 @@ pub trait Visitor<'v>: Sized {
}
}
pub trait VisitorExt<'v>: Visitor<'v> {
/// Extension trait method to visit types in unambiguous positions, this is not
/// directly on the [`Visitor`] trait as this method should never be overridden.
///
/// Named `visit_ty_unambig` instead of `visit_unambig_ty` to aid in discovery
/// by IDes when `v.visit_ty` is written.
fn visit_ty_unambig(&mut self, t: &'v Ty<'v>) -> Self::Result {
walk_unambig_ty(self, t)
}
/// Extension trait method to visit consts in unambiguous positions, this is not
/// directly on the [`Visitor`] trait as this method should never be overridden.
///
/// Named `visit_const_arg_unambig` instead of `visit_unambig_const_arg` to aid in
/// discovery by IDes when `v.visit_const_arg` is written.
fn visit_const_arg_unambig(&mut self, c: &'v ConstArg<'v>) -> Self::Result {
walk_const_arg(self, c)
}
}
impl<'v, V: Visitor<'v>> VisitorExt<'v> for V {}
pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> V::Result {
try_visit!(visitor.visit_id(param.hir_id));
visitor.visit_pat(param.pat)
@ -503,12 +544,12 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
}
ItemKind::Static(ref typ, _, body) => {
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(visitor.visit_ty(typ));
try_visit!(visitor.visit_ty_unambig(typ));
try_visit!(visitor.visit_nested_body(body));
}
ItemKind::Const(ref typ, ref generics, body) => {
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(visitor.visit_ty(typ));
try_visit!(visitor.visit_ty_unambig(typ));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_nested_body(body));
}
@ -539,7 +580,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
}
ItemKind::TyAlias(ref ty, ref generics) => {
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_ty_unambig(ty));
try_visit!(visitor.visit_generics(generics));
}
ItemKind::Enum(ref enum_definition, ref generics) => {
@ -561,7 +602,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(visitor.visit_generics(generics));
visit_opt!(visitor, visit_trait_ref, of_trait);
try_visit!(visitor.visit_ty(self_ty));
try_visit!(visitor.visit_ty_unambig(self_ty));
walk_list!(visitor, visit_impl_item_ref, *items);
}
ItemKind::Struct(ref struct_definition, ref generics)
@ -618,7 +659,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(
walk_list!(visitor, visit_ident, param_names.iter().copied());
}
ForeignItemKind::Static(ref typ, _, _) => {
try_visit!(visitor.visit_ty(typ));
try_visit!(visitor.visit_ty_unambig(typ));
}
ForeignItemKind::Type => (),
}
@ -632,7 +673,7 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v LetStmt<'v>) -
try_visit!(visitor.visit_id(local.hir_id));
try_visit!(visitor.visit_pat(local.pat));
visit_opt!(visitor, visit_block, local.els);
visit_opt!(visitor, visit_ty, local.ty);
visit_opt!(visitor, visit_ty_unambig, local.ty);
V::Result::output()
}
@ -735,18 +776,6 @@ pub fn walk_inline_const<'v, V: Visitor<'v>>(
visitor.visit_nested_body(constant.body)
}
pub fn walk_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v>,
) -> V::Result {
try_visit!(visitor.visit_id(const_arg.hir_id));
match &const_arg.kind {
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()),
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
ConstArgKind::Infer(..) => V::Result::output(),
}
}
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result {
try_visit!(visitor.visit_id(expression.hir_id));
match expression.kind {
@ -758,7 +787,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
}
ExprKind::Repeat(ref element, ref count) => {
try_visit!(visitor.visit_expr(element));
try_visit!(visitor.visit_const_arg(count));
try_visit!(visitor.visit_const_arg_unambig(count));
}
ExprKind::Struct(ref qpath, fields, ref optional_base) => {
try_visit!(visitor.visit_qpath(qpath, expression.hir_id, expression.span));
@ -789,7 +818,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
}
ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
try_visit!(visitor.visit_expr(subexpression));
try_visit!(visitor.visit_ty(typ));
try_visit!(visitor.visit_ty_unambig(typ));
}
ExprKind::DropTemps(ref subexpression) => {
try_visit!(visitor.visit_expr(subexpression));
@ -798,7 +827,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
// match the visit order in walk_local
try_visit!(visitor.visit_expr(init));
try_visit!(visitor.visit_pat(pat));
visit_opt!(visitor, visit_ty, ty);
visit_opt!(visitor, visit_ty_unambig, ty);
}
ExprKind::If(ref cond, ref then, ref else_opt) => {
try_visit!(visitor.visit_expr(cond));
@ -866,7 +895,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
try_visit!(visitor.visit_inline_asm(asm, expression.hir_id));
}
ExprKind::OffsetOf(ref container, ref fields) => {
try_visit!(visitor.visit_ty(container));
try_visit!(visitor.visit_ty_unambig(container));
walk_list!(visitor, visit_ident, fields.iter().copied());
}
ExprKind::Yield(ref subexpression, _) => {
@ -874,7 +903,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
}
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
try_visit!(visitor.visit_expr(expr));
visit_opt!(visitor, visit_ty, ty);
visit_opt!(visitor, visit_ty_unambig, ty);
}
ExprKind::Lit(_) | ExprKind::Err(_) => {}
}
@ -886,20 +915,49 @@ pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField
try_visit!(visitor.visit_ident(field.ident));
visitor.visit_expr(field.expr)
}
/// We track whether an infer var is from a [`Ty`], [`ConstArg`], or [`GenericArg`] so that
/// HIR visitors overriding [`Visitor::visit_infer`] can determine what kind of infer is being visited
pub enum InferKind<'hir> {
Ty(&'hir Ty<'hir>),
Const(&'hir ConstArg<'hir>),
Ambig(&'hir InferArg),
}
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Result {
pub fn walk_generic_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
generic_arg: &'v GenericArg<'v>,
) -> V::Result {
match generic_arg {
GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
GenericArg::Type(ty) => visitor.visit_ty(ty),
GenericArg::Const(ct) => visitor.visit_const_arg(ct),
GenericArg::Infer(inf) => visitor.visit_infer(inf.hir_id, inf.span, InferKind::Ambig(inf)),
}
}
pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Result {
match typ.try_as_ambig_ty() {
Some(ambig_ty) => visitor.visit_ty(ambig_ty),
None => {
try_visit!(visitor.visit_id(typ.hir_id));
visitor.visit_infer(typ.hir_id, typ.span, InferKind::Ty(typ))
}
}
}
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -> V::Result {
try_visit!(visitor.visit_id(typ.hir_id));
match typ.kind {
TyKind::Slice(ref ty) => try_visit!(visitor.visit_ty(ty)),
TyKind::Ptr(ref mutable_type) => try_visit!(visitor.visit_ty(mutable_type.ty)),
TyKind::Slice(ref ty) => try_visit!(visitor.visit_ty_unambig(ty)),
TyKind::Ptr(ref mutable_type) => try_visit!(visitor.visit_ty_unambig(mutable_type.ty)),
TyKind::Ref(ref lifetime, ref mutable_type) => {
try_visit!(visitor.visit_lifetime(lifetime));
try_visit!(visitor.visit_ty(mutable_type.ty));
try_visit!(visitor.visit_ty_unambig(mutable_type.ty));
}
TyKind::Never => {}
TyKind::Tup(tuple_element_types) => {
walk_list!(visitor, visit_ty, tuple_element_types);
walk_list!(visitor, visit_ty_unambig, tuple_element_types);
}
TyKind::BareFn(ref function_declaration) => {
walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
@ -907,7 +965,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
}
TyKind::UnsafeBinder(ref unsafe_binder) => {
walk_list!(visitor, visit_generic_param, unsafe_binder.generic_params);
try_visit!(visitor.visit_ty(unsafe_binder.inner_ty));
try_visit!(visitor.visit_ty_unambig(unsafe_binder.inner_ty));
}
TyKind::Path(ref qpath) => {
try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
@ -919,25 +977,49 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
walk_list!(visitor, visit_param_bound, bounds);
}
TyKind::Array(ref ty, ref length) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_const_arg(length));
try_visit!(visitor.visit_ty_unambig(ty));
try_visit!(visitor.visit_const_arg_unambig(length));
}
TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
TyKind::TraitObject(bounds, ref lifetime) => {
for bound in bounds {
try_visit!(visitor.visit_poly_trait_ref(bound));
}
try_visit!(visitor.visit_lifetime(lifetime));
}
TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)),
TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {}
TyKind::InferDelegation(..) | TyKind::Err(_) => {}
TyKind::Pat(ty, pat) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_ty_unambig(ty));
try_visit!(visitor.visit_pattern_type_pattern(pat));
}
}
V::Result::output()
}
pub fn walk_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v>,
) -> V::Result {
match const_arg.try_as_ambig_ct() {
Some(ambig_ct) => visitor.visit_const_arg(ambig_ct),
None => {
try_visit!(visitor.visit_id(const_arg.hir_id));
visitor.visit_infer(const_arg.hir_id, const_arg.span(), InferKind::Const(const_arg))
}
}
}
pub fn walk_ambig_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v, AmbigArg>,
) -> V::Result {
try_visit!(visitor.visit_id(const_arg.hir_id));
match &const_arg.kind {
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()),
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
}
}
pub fn walk_generic_param<'v, V: Visitor<'v>>(
visitor: &mut V,
param: &'v GenericParam<'v>,
@ -949,9 +1031,11 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
}
match param.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { ref default, .. } => visit_opt!(visitor, visit_ty, default),
GenericParamKind::Type { ref default, .. } => {
visit_opt!(visitor, visit_ty_unambig, default)
}
GenericParamKind::Const { ref ty, ref default, synthetic: _ } => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_ty_unambig(ty));
if let Some(ref default) = default {
try_visit!(visitor.visit_const_param_default(param.hir_id, default));
}
@ -964,7 +1048,7 @@ pub fn walk_const_param_default<'v, V: Visitor<'v>>(
visitor: &mut V,
ct: &'v ConstArg<'v>,
) -> V::Result {
visitor.visit_const_arg(ct)
visitor.visit_const_arg_unambig(ct)
}
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) -> V::Result {
@ -986,7 +1070,7 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
bound_generic_params,
origin: _,
}) => {
try_visit!(visitor.visit_ty(bounded_ty));
try_visit!(visitor.visit_ty_unambig(bounded_ty));
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_generic_param, bound_generic_params);
}
@ -999,8 +1083,8 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
walk_list!(visitor, visit_param_bound, bounds);
}
WherePredicateKind::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty }) => {
try_visit!(visitor.visit_ty(lhs_ty));
try_visit!(visitor.visit_ty(rhs_ty));
try_visit!(visitor.visit_ty_unambig(lhs_ty));
try_visit!(visitor.visit_ty_unambig(rhs_ty));
}
}
V::Result::output()
@ -1010,13 +1094,13 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>(
visitor: &mut V,
function_declaration: &'v FnDecl<'v>,
) -> V::Result {
walk_list!(visitor, visit_ty, function_declaration.inputs);
walk_list!(visitor, visit_ty_unambig, function_declaration.inputs);
visitor.visit_fn_ret_ty(&function_declaration.output)
}
pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) -> V::Result {
if let FnRetTy::Return(output_ty) = *ret_ty {
try_visit!(visitor.visit_ty(output_ty));
try_visit!(visitor.visit_ty_unambig(output_ty));
}
V::Result::output()
}
@ -1069,7 +1153,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_id(hir_id));
match *kind {
TraitItemKind::Const(ref ty, default) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_ty_unambig(ty));
visit_opt!(visitor, visit_nested_body, default);
}
TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => {
@ -1087,7 +1171,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(
}
TraitItemKind::Type(bounds, ref default) => {
walk_list!(visitor, visit_param_bound, bounds);
visit_opt!(visitor, visit_ty, default);
visit_opt!(visitor, visit_ty_unambig, default);
}
}
V::Result::output()
@ -1125,7 +1209,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_id(impl_item.hir_id()));
match *kind {
ImplItemKind::Const(ref ty, body) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_ty_unambig(ty));
visitor.visit_nested_body(body)
}
ImplItemKind::Fn(ref sig, body_id) => visitor.visit_fn(
@ -1135,7 +1219,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(
impl_item.span,
impl_item.owner_id.def_id,
),
ImplItemKind::Type(ref ty) => visitor.visit_ty(ty),
ImplItemKind::Type(ref ty) => visitor.visit_ty_unambig(ty),
}
}
@ -1223,7 +1307,7 @@ pub fn walk_field_def<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_id(*hir_id));
try_visit!(visitor.visit_ident(*ident));
visit_opt!(visitor, visit_anon_const, default);
visitor.visit_ty(*ty)
visitor.visit_ty_unambig(*ty)
}
pub fn walk_enum_def<'v, V: Visitor<'v>>(
@ -1252,18 +1336,6 @@ pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) -> V::Re
visitor.visit_id(inf.hir_id)
}
pub fn walk_generic_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
generic_arg: &'v GenericArg<'v>,
) -> V::Result {
match generic_arg {
GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
GenericArg::Type(ty) => visitor.visit_ty(ty),
GenericArg::Const(ct) => visitor.visit_const_arg(ct),
GenericArg::Infer(inf) => visitor.visit_infer(inf),
}
}
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) -> V::Result {
try_visit!(visitor.visit_id(lifetime.hir_id));
visitor.visit_ident(lifetime.ident)
@ -1276,11 +1348,11 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(
) -> V::Result {
match *qpath {
QPath::Resolved(ref maybe_qself, ref path) => {
visit_opt!(visitor, visit_ty, maybe_qself);
visit_opt!(visitor, visit_ty_unambig, maybe_qself);
visitor.visit_path(path, id)
}
QPath::TypeRelative(ref qself, ref segment) => {
try_visit!(visitor.visit_ty(qself));
try_visit!(visitor.visit_ty_unambig(qself));
visitor.visit_path_segment(segment)
}
QPath::LangItem(..) => V::Result::output(),
@ -1320,8 +1392,8 @@ pub fn walk_assoc_item_constraint<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_generic_args(constraint.gen_args));
match constraint.kind {
AssocItemConstraintKind::Equality { ref term } => match term {
Term::Ty(ref ty) => try_visit!(visitor.visit_ty(ty)),
Term::Const(ref c) => try_visit!(visitor.visit_const_arg(c)),
Term::Ty(ref ty) => try_visit!(visitor.visit_ty_unambig(ty)),
Term::Const(ref c) => try_visit!(visitor.visit_const_arg_unambig(c)),
},
AssocItemConstraintKind::Bound { bounds } => {
walk_list!(visitor, visit_param_bound, bounds)

View file

@ -6,6 +6,7 @@
#![allow(internal_features)]
#![feature(associated_type_defaults)]
#![feature(closure_track_caller)]
#![feature(exhaustive_patterns)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(rustc_attrs)]

View file

@ -6,9 +6,9 @@ use hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{GenericParamKind, ImplItemKind, intravisit};
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
@ -1610,7 +1610,7 @@ fn compare_synthetic_generics<'tcx>(
struct Visitor(hir::def_id::LocalDefId);
impl<'v> intravisit::Visitor<'v> for Visitor {
type Result = ControlFlow<Span>;
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) -> Self::Result {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) -> Self::Result {
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind
&& let Res::Def(DefKind::TyParam, def_id) = path.res
&& def_id == self.0.to_def_id()
@ -1622,9 +1622,9 @@ fn compare_synthetic_generics<'tcx>(
}
}
let span = input_tys.iter().find_map(|ty| {
intravisit::Visitor::visit_ty(&mut Visitor(impl_def_id), ty).break_value()
})?;
let span = input_tys
.iter()
.find_map(|ty| Visitor(impl_def_id).visit_ty_unambig(ty).break_value())?;
let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
let bounds = bounds.first()?.span().to(bounds.last()?.span());

View file

@ -6,10 +6,10 @@ use rustc_abi::ExternAbi;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_hir::ItemKind;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{AmbigArg, ItemKind};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_macros::LintDiagnostic;
@ -2196,7 +2196,7 @@ impl<'tcx> Visitor<'tcx> for CollectUsageSpans<'_> {
// Skip the generics. We only care about fields, not where clause/param bounds.
}
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
if let hir::TyKind::Path(hir::QPath::Resolved(None, qpath)) = t.kind {
if let Res::Def(DefKind::TyParam, def_id) = qpath.res
&& def_id == self.param_def_id

View file

@ -28,7 +28,7 @@ use rustc_errors::{
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor, walk_generics};
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt, walk_generics};
use rustc_hir::{self as hir, GenericParamKind, HirId, Node};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
@ -139,29 +139,12 @@ pub(crate) struct HirPlaceholderCollector {
}
impl<'v> Visitor<'v> for HirPlaceholderCollector {
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
if let hir::TyKind::Infer = t.kind {
self.spans.push(t.span);
}
intravisit::walk_ty(self, t)
}
fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) {
match generic_arg {
hir::GenericArg::Infer(inf) => {
self.spans.push(inf.span);
self.may_contain_const_infer = true;
intravisit::walk_inf(self, inf);
}
hir::GenericArg::Type(t) => self.visit_ty(t),
_ => {}
}
}
fn visit_const_arg(&mut self, const_arg: &'v hir::ConstArg<'v>) {
if let hir::ConstArgKind::Infer(span) = const_arg.kind {
fn visit_infer(&mut self, _inf_id: HirId, inf_span: Span, kind: InferKind<'v>) -> Self::Result {
self.spans.push(inf_span);
if let InferKind::Const(_) | InferKind::Ambig(_) = kind {
self.may_contain_const_infer = true;
self.spans.push(span);
}
intravisit::walk_const_arg(self, const_arg)
}
}
@ -583,7 +566,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
.iter()
.enumerate()
.map(|(i, a)| {
if let hir::TyKind::Infer = a.kind {
if let hir::TyKind::Infer(()) = a.kind {
if let Some(suggested_ty) =
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
{
@ -593,21 +576,21 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
}
// Only visit the type looking for `_` if we didn't fix the type above
visitor.visit_ty(a);
visitor.visit_ty_unambig(a);
self.lowerer().lower_arg_ty(a, None)
})
.collect();
let output_ty = match decl.output {
hir::FnRetTy::Return(output) => {
if let hir::TyKind::Infer = output.kind
if let hir::TyKind::Infer(()) = output.kind
&& let Some(suggested_ty) =
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
{
infer_replacements.push((output.span, suggested_ty.to_string()));
Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string())
} else {
visitor.visit_ty(output);
visitor.visit_ty_unambig(output);
self.lower_ty(output)
}
}
@ -1453,7 +1436,7 @@ fn recover_infer_ret_ty<'tcx>(
});
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_ty(infer_ret_ty);
visitor.visit_ty_unambig(infer_ret_ty);
let mut diag = bad_placeholder(icx.lowerer(), visitor.spans, "return type");
let ret_ty = fn_sig.output();

View file

@ -3,9 +3,10 @@ use std::ops::ControlFlow;
use hir::intravisit::{self, Visitor};
use hir::{GenericParamKind, HirId, Node};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{self as hir, AmbigArg};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint;
use rustc_span::{Span, Symbol, kw};
@ -461,7 +462,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
type Result = ControlFlow<Span>;
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow<Span> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) -> ControlFlow<Span> {
match ty.kind {
hir::TyKind::BareFn(..) => {
self.outer_index.shift_in(1);
@ -539,7 +540,7 @@ impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
if let GenericParamKind::Const { ty, default: _, synthetic: _ } = p.kind {
let prev = self.in_param_ty;
self.in_param_ty = true;
let res = self.visit_ty(ty);
let res = self.visit_ty_unambig(ty);
self.in_param_ty = prev;
res
} else {

View file

@ -14,11 +14,11 @@ use rustc_ast::visit::walk_list;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::sorted_map::SortedMap;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
use rustc_hir::{
GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap, LifetimeName, Node,
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap,
LifetimeName, Node,
};
use rustc_macros::extension;
use rustc_middle::hir::nested_filter;
@ -489,15 +489,17 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
struct FindInferInClosureWithBinder;
impl<'v> Visitor<'v> for FindInferInClosureWithBinder {
type Result = ControlFlow<Span>;
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> Self::Result {
if matches!(t.kind, hir::TyKind::Infer) {
ControlFlow::Break(t.span)
} else {
intravisit::walk_ty(self, t)
}
fn visit_infer(
&mut self,
_inf_id: HirId,
inf_span: Span,
_kind: InferKind<'v>,
) -> Self::Result {
ControlFlow::Break(inf_span)
}
}
FindInferInClosureWithBinder.visit_ty(ty).break_value()
FindInferInClosureWithBinder.visit_ty_unambig(ty).break_value()
}
let infer_in_rt_sp = match fn_decl.output {
@ -749,7 +751,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
#[instrument(level = "debug", skip(self))]
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
match ty.kind {
hir::TyKind::BareFn(c) => {
let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = c
@ -810,7 +812,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
intravisit::walk_ty(this, ty);
});
}
hir::TyKind::TraitObject(bounds, lifetime, _) => {
hir::TyKind::TraitObject(bounds, lifetime) => {
let lifetime = lifetime.pointer();
debug!(?bounds, ?lifetime, "TraitObject");
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| {
@ -827,7 +831,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
// use the object lifetime defaulting
// rules. So e.g., `Box<dyn Debug>` becomes
// `Box<dyn Debug + 'static>`.
self.resolve_object_lifetime_default(lifetime)
self.resolve_object_lifetime_default(&*lifetime)
}
LifetimeName::Infer => {
// If the user writes `'_`, we use the *ordinary* elision
@ -838,7 +842,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
LifetimeName::Param(..) | LifetimeName::Static => {
// If the user wrote an explicit name, use that.
self.visit_lifetime(lifetime);
self.visit_lifetime(&*lifetime);
}
LifetimeName::Error => {}
}
@ -849,7 +853,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
s: self.scope,
};
self.with(scope, |this| this.visit_ty(mt.ty));
self.with(scope, |this| this.visit_ty_unambig(mt.ty));
}
hir::TyKind::TraitAscription(bounds) => {
let scope = Scope::TraitRefBoundary { s: self.scope };
@ -891,7 +895,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
this.visit_param_bound(bound);
}
if let Some(ty) = ty {
this.visit_ty(ty);
this.visit_ty_unambig(ty);
}
})
}
@ -910,7 +914,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}),
Type(ty) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
this.visit_generics(impl_item.generics);
this.visit_ty(ty);
this.visit_ty_unambig(ty);
}),
Const(_, _) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
intravisit::walk_impl_item(this, impl_item)
@ -1019,7 +1023,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
};
self.with(scope, |this| {
walk_list!(this, visit_generic_param, bound_generic_params);
this.visit_ty(bounded_ty);
this.visit_ty_unambig(bounded_ty);
walk_list!(this, visit_param_bound, bounds);
})
}
@ -1034,8 +1038,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
&hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
lhs_ty, rhs_ty, ..
}) => {
self.visit_ty(lhs_ty);
self.visit_ty(rhs_ty);
self.visit_ty_unambig(lhs_ty);
self.visit_ty_unambig(rhs_ty);
}
}
}
@ -1068,13 +1072,13 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { default, .. } => {
if let Some(ty) = default {
self.visit_ty(ty);
self.visit_ty_unambig(ty);
}
}
GenericParamKind::Const { ty, default, .. } => {
self.visit_ty(ty);
self.visit_ty_unambig(ty);
if let Some(default) = default {
self.visit_const_arg(default);
self.visit_const_arg_unambig(default);
}
}
}
@ -1983,15 +1987,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
},
|this| {
for input in inputs {
this.visit_ty(input);
this.visit_ty_unambig(input);
}
if !in_closure && let Some(output) = output {
this.visit_ty(output);
this.visit_ty_unambig(output);
}
},
);
if in_closure && let Some(output) = output {
self.visit_ty(output);
self.visit_ty_unambig(output);
}
}
@ -2309,7 +2313,7 @@ fn is_late_bound_map(
let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx };
for arg_ty in sig.decl.inputs {
constrained_by_input.visit_ty(arg_ty);
constrained_by_input.visit_ty_unambig(arg_ty);
}
let mut appears_in_output =
@ -2417,7 +2421,7 @@ fn is_late_bound_map(
}
impl<'v> Visitor<'v> for ConstrainedCollector<'_> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
match ty.kind {
hir::TyKind::Path(
hir::QPath::Resolved(Some(_), _) | hir::QPath::TypeRelative(..),

View file

@ -1,10 +1,9 @@
use core::ops::ControlFlow;
use rustc_errors::{Applicability, StashKey, Suggestions};
use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{self as hir, AmbigArg, HirId};
use rustc_middle::query::plumbing::CyclePlaceholder;
use rustc_middle::ty::fold::fold_regions;
use rustc_middle::ty::print::with_forced_trimmed_paths;
@ -451,7 +450,7 @@ fn infer_placeholder_type<'tcx>(
let mut visitor = HirPlaceholderCollector::default();
let node = tcx.hir_node_by_def_id(def_id);
if let Some(ty) = node.ty() {
visitor.visit_ty(ty);
visitor.visit_ty_unambig(ty);
}
// If we have just one span, let's try to steal a const `_` feature error.
let try_steal_span = if !tcx.features().generic_arg_infer() && visitor.spans.len() == 1
@ -525,7 +524,7 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) ->
struct HasTait;
impl<'tcx> Visitor<'tcx> for HasTait {
type Result = ControlFlow<()>;
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
if let hir::TyKind::OpaqueDef(..) = t.kind {
ControlFlow::Break(())
} else {
@ -533,5 +532,5 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) ->
}
}
}
HasTait.visit_ty(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break()
HasTait.visit_ty_unambig(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break()
}

View file

@ -9,6 +9,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_middle::bug;
use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
use rustc_middle::ty::{
self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
@ -998,12 +999,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)),
..
}) = node
&& let Some(adt_def) = qself_ty.ty_adt_def()
&& let [inherent_impl] = tcx.inherent_impls(adt_def.did())
&& let name = format!("{ident2}_{ident3}")
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx
.associated_items(inherent_impl)
.filter_by_name_unhygienic(Symbol::intern(&name))
&& let Some(inherent_impls) = qself_ty
.ty_adt_def()
.map(|adt_def| tcx.inherent_impls(adt_def.did()))
.or_else(|| {
simplify_type(tcx, qself_ty, TreatParams::InstantiateWithInfer)
.map(|simple_ty| tcx.incoherent_impls(simple_ty))
})
&& let name = Symbol::intern(&format!("{ident2}_{ident3}"))
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls
.iter()
.flat_map(|inherent_impl| {
tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
})
.next()
{
Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")

View file

@ -1,10 +1,9 @@
use rustc_ast::ast::ParamKindOrd;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::GenericArg;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, GenericArg};
use rustc_middle::ty::{
self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty,
};
@ -41,17 +40,6 @@ fn generic_arg_mismatch_err(
param.kind.descr(),
);
if let GenericParamDefKind::Const { .. } = param.kind {
if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) {
err.help("const arguments cannot yet be inferred with `_`");
tcx.disabled_nightly_features(
&mut err,
param.def_id.as_local().map(|local| tcx.local_def_id_to_hir_id(local)),
[(String::new(), sym::generic_arg_infer)],
);
}
}
let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut Diag<'_>| {
let suggestions = vec![
(arg.span().shrink_to_lo(), String::from("{ ")),
@ -270,6 +258,21 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
GenericParamDefKind::Const { .. },
_,
) => {
if let GenericParamDefKind::Const { .. } = param.kind
&& let GenericArg::Infer(inf) = arg
&& !tcx.features().generic_arg_infer()
{
rustc_session::parse::feature_err(
tcx.sess,
sym::generic_arg_infer,
inf.span,
"const arguments cannot yet be inferred with `_`",
)
.emit();
}
// We lower to an infer even when the feature gate is not enabled
// as it is useful for diagnostics to be able to see a `ConstKind::Infer`
args.push(ctx.provided_kind(&args, param, arg));
args_iter.next();
params.next();

View file

@ -23,9 +23,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) -> Option<ErrorGuaranteed> {
let tcx = self.tcx();
let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
let poly_trait_ref = if let hir::TyKind::TraitObject([poly_trait_ref, ..], tagged_ptr) =
self_ty.kind
else {
&& let TraitObjectSyntax::None = tagged_ptr.tag()
{
poly_trait_ref
} else {
return None;
};
@ -294,7 +297,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let (dyn_str, paren_dyn_str) =
if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _) = self_ty.kind {
// There are more than one trait bound, we need surrounding parentheses.
vec![
(self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()),

View file

@ -517,14 +517,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.lowerer.lower_lifetime(lt, RegionInferReason::Param(param)).into()
}
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
handle_ty_args(has_default, ty)
// We handle the other parts of `Ty` in the match arm below
handle_ty_args(has_default, ty.as_unambig_ty())
}
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Infer(inf)) => {
handle_ty_args(has_default, &inf.to_ty())
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.lowerer.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
.lowerer
// Ambig portions of `ConstArg` are handled in the match arm below
.lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
.into(),
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
self.lowerer.ct_infer(Some(param), inf.span).into()
}
@ -2115,7 +2118,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
),
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
hir::ConstArgKind::Infer(span) => self.ct_infer(None, span),
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
}
}
@ -2311,7 +2314,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
tcx.late_bound_vars(hir_ty.hir_id),
),
),
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
hir::TyKind::TraitObject(bounds, tagged_ptr) => {
let lifetime = tagged_ptr.pointer();
let repr = tagged_ptr.tag();
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
// Don't continue with type analysis if the `dyn` keyword is missing
// It generates confusing errors, especially if the user meant to use another
@ -2420,7 +2426,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length)
}
hir::TyKind::Typeof(e) => tcx.type_of(e.def_id).instantiate_identity(),
hir::TyKind::Infer => {
hir::TyKind::Infer(()) => {
// Infer also appears as the type of arguments or return
// values in an ExprKind::Closure, or as
// the type of local variables. Both of these cases are
@ -2553,7 +2559,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
pub fn lower_arg_ty(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
match ty.kind {
hir::TyKind::Infer if let Some(expected_ty) = expected_ty => {
hir::TyKind::Infer(()) if let Some(expected_ty) = expected_ty => {
self.record_ty(ty.hir_id, expected_ty, ty.span);
expected_ty
}

View file

@ -1,6 +1,5 @@
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{ForeignItem, ForeignItemKind};
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
use rustc_hir::{self as hir, AmbigArg, ForeignItem, ForeignItemKind};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ObligationCause, WellFormedLoc};
use rustc_middle::bug;
@ -68,11 +67,13 @@ fn diagnostic_hir_wf_check<'tcx>(
}
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let tcx_ty = self.icx.lower_ty(ty);
// We don't handle infer vars but we wouldn't handle them anyway as we're creating a
// fresh `InferCtxt` in this function.
let tcx_ty = self.icx.lower_ty(ty.as_unambig_ty());
// This visitor can walk into binders, resulting in the `tcx_ty` to
// potentially reference escaping bound variables. We simply erase
// those here.
@ -149,7 +150,11 @@ fn diagnostic_hir_wf_check<'tcx>(
.iter()
.flat_map(|seg| seg.args().args)
.filter_map(|arg| {
if let hir::GenericArg::Type(ty) = arg { Some(*ty) } else { None }
if let hir::GenericArg::Type(ty) = arg {
Some(ty.as_unambig_ty())
} else {
None
}
})
.chain([impl_.self_ty])
.collect(),
@ -196,7 +201,7 @@ fn diagnostic_hir_wf_check<'tcx>(
}
};
for ty in tys {
visitor.visit_ty(ty);
visitor.visit_ty_unambig(ty);
}
visitor.cause
}

View file

@ -402,7 +402,8 @@ impl<'a> State<'a> {
self.print_bounds("impl", bounds);
}
hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
hir::TyKind::TraitObject(bounds, lifetime) => {
let syntax = lifetime.tag();
match syntax {
ast::TraitObjectSyntax::Dyn => self.word_nbsp("dyn"),
ast::TraitObjectSyntax::DynStar => self.word_nbsp("dyn*"),
@ -421,7 +422,7 @@ impl<'a> State<'a> {
if !lifetime.is_elided() {
self.nbsp();
self.word_space("+");
self.print_lifetime(lifetime);
self.print_lifetime(lifetime.pointer());
}
}
hir::TyKind::Array(ty, ref length) => {
@ -441,7 +442,7 @@ impl<'a> State<'a> {
self.word("/*ERROR*/");
self.pclose();
}
hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => {
hir::TyKind::Infer(()) | hir::TyKind::InferDelegation(..) => {
self.word("_");
}
hir::TyKind::Pat(ty, pat) => {
@ -1799,8 +1800,8 @@ impl<'a> State<'a> {
match generic_arg {
GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt),
GenericArg::Lifetime(_) => {}
GenericArg::Type(ty) => s.print_type(ty),
GenericArg::Const(ct) => s.print_const_arg(ct),
GenericArg::Type(ty) => s.print_type(ty.as_unambig_ty()),
GenericArg::Const(ct) => s.print_const_arg(ct.as_unambig_ct()),
GenericArg::Infer(_inf) => s.word("_"),
}
});
@ -2150,7 +2151,7 @@ impl<'a> State<'a> {
s.ann.nested(s, Nested::BodyParamPat(body_id, i));
i += 1;
if let hir::TyKind::Infer = ty.kind {
if let hir::TyKind::Infer(()) = ty.kind {
// Print nothing.
} else {
s.word(":");

View file

@ -10,7 +10,7 @@ use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::{InferKind, Visitor};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
@ -641,16 +641,21 @@ impl<'tcx> AnnotateUnitFallbackVisitor<'_, 'tcx> {
impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
type Result = ControlFlow<errors::SuggestAnnotation>;
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_infer(
&mut self,
inf_id: HirId,
inf_span: Span,
_kind: InferKind<'tcx>,
) -> Self::Result {
// Try to replace `_` with `()`.
if let hir::TyKind::Infer = hir_ty.kind
&& let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(hir_ty.hir_id)
if let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(inf_id)
&& let Some(vid) = self.fcx.root_vid(ty)
&& self.reachable_vids.contains(&vid)
{
return ControlFlow::Break(errors::SuggestAnnotation::Unit(hir_ty.span));
return ControlFlow::Break(errors::SuggestAnnotation::Unit(inf_span));
}
hir::intravisit::walk_ty(self, hir_ty)
ControlFlow::Continue(())
}
fn visit_qpath(

View file

@ -6,9 +6,9 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{self as hir, ExprKind, GenericArg, HirId, Node, QPath, intravisit};
use rustc_hir::{self as hir, AmbigArg, ExprKind, GenericArg, HirId, Node, QPath, intravisit};
use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
use rustc_hir_analysis::hir_ty_lowering::generics::{
check_generic_arg_count_for_call, lower_generic_args,
@ -470,7 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
impl<'tcx> intravisit::Visitor<'tcx> for CollectClauses<'_, 'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
if let Some(clauses) = self.fcx.trait_ascriptions.borrow().get(&ty.hir_id.local_id)
{
self.clauses.extend(clauses.iter().cloned());
@ -480,7 +480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let mut clauses = CollectClauses { clauses: vec![], fcx: self };
clauses.visit_ty(hir_ty);
clauses.visit_ty_unambig(hir_ty);
self.tcx.mk_clauses(&clauses.clauses)
}
@ -1272,14 +1272,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.lower_lifetime(lt, RegionInferReason::Param(param))
.into(),
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.fcx.lower_ty(ty).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.fcx.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
// We handle the ambig portions of `Ty` in match arm below
self.fcx.lower_ty(ty.as_unambig_ty()).raw.into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
self.fcx.ty_infer(Some(param), inf.span).into()
self.fcx.lower_ty(&inf.to_ty()).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
.fcx
// Ambiguous parts of `ConstArg` are handled in the match arms below
.lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
.into(),
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
self.fcx.ct_infer(Some(param), inf.span).into()
}

View file

@ -251,7 +251,8 @@ fn typeck_with_inspect<'tcx>(
fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Option<Ty<'tcx>> {
let tcx = fcx.tcx;
let def_id = fcx.body_id;
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = node.ty() {
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty()
{
if let Some(item) = tcx.opt_associated_item(def_id.into())
&& let ty::AssocKind::Const = item.kind
&& let ty::AssocItemContainer::Impl = item.container

View file

@ -425,14 +425,17 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
.lower_lifetime(lt, RegionInferReason::Param(param))
.into(),
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.cfcx.lower_ty(ty).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.cfcx.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
// We handle the ambig portions of `Ty` in the match arms below
self.cfcx.lower_ty(ty.as_unambig_ty()).raw.into()
}
(GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
self.cfcx.ty_infer(Some(param), inf.span).into()
self.cfcx.lower_ty(&inf.to_ty()).raw.into()
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
.cfcx
// We handle the ambig portions of `ConstArg` in the match arms below
.lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
.into(),
(GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
self.cfcx.ct_infer(Some(param), inf.span).into()
}

View file

@ -6,9 +6,8 @@ use std::mem;
use rustc_data_structures::unord::ExtendUnord;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::intravisit::{self, InferKind, Visitor};
use rustc_hir::{self as hir, AmbigArg, HirId};
use rustc_middle::span_bug;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
@ -354,7 +353,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
self.write_ty_to_typeck_results(l.hir_id, var_ty);
}
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
intravisit::walk_ty(self, hir_ty);
// If there are type checking errors, Type privacy pass will stop,
// so we may not get the type from hid_id, see #104513
@ -364,12 +363,20 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
}
}
fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
intravisit::walk_inf(self, inf);
// Ignore cases where the inference is a const.
if let Some(ty) = self.fcx.node_ty_opt(inf.hir_id) {
let ty = self.resolve(ty, &inf.span);
self.write_ty_to_typeck_results(inf.hir_id, ty);
fn visit_infer(
&mut self,
inf_id: HirId,
inf_span: Span,
_kind: InferKind<'cx>,
) -> Self::Result {
self.visit_id(inf_id);
// We don't currently write inference results of const infer vars to
// the typeck results as there is not yet any part of the compiler that
// needs this information.
if let Some(ty) = self.fcx.node_ty_opt(inf_id) {
let ty = self.resolve(ty, &inf_span);
self.write_ty_to_typeck_results(inf_id, ty);
}
}
}

View file

@ -5,8 +5,8 @@ use rustc_ast as ast;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::{
BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat, PatKind,
Path, PathSegment, QPath, Ty, TyKind,
AmbigArg, BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat,
PatKind, Path, PathSegment, QPath, Ty, TyKind,
};
use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
}
}
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx, AmbigArg>) {
match &ty.kind {
TyKind::Path(QPath::Resolved(_, path)) => {
if lint_ty_kind_usage(cx, &path.res) {

View file

@ -8,9 +8,8 @@ use std::cell::Cell;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::join;
use rustc_hir as hir;
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
use rustc_hir::{HirId, intravisit as hir_visit};
use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Session;
@ -214,15 +213,11 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
})
}
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) {
lint_callback!(self, check_ty, t);
hir_visit::walk_ty(self, t);
}
fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
hir_visit::walk_inf(self, inf);
}
fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _: Span, n: HirId) {
if !self.context.only_module {
self.process_mod(m, n);

View file

@ -9,6 +9,7 @@ use rustc_errors::{
};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{self as hir, MissingLifetimeKind};
use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::inhabitedness::InhabitedPredicate;
@ -293,7 +294,7 @@ impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_> {
// avoid doing throwaway work in case the lint ends up getting suppressed.
let mut collector = ShorthandAssocTyCollector { qselves: Vec::new() };
if let Some(ty) = self.ty {
hir::intravisit::Visitor::visit_ty(&mut collector, ty);
collector.visit_ty_unambig(ty);
}
let affect_object_lifetime_defaults = self

View file

@ -1,6 +1,6 @@
use rustc_errors::MultiSpan;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind};
use rustc_middle::ty::TyCtxt;
use rustc_session::{declare_lint, impl_lint_pass};
@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
// 1. We collect all the `hir::Path` from the `Self` type and `Trait` ref
// of the `impl` definition
let mut collector = PathCollector { paths: Vec::new() };
collector.visit_ty(&impl_.self_ty);
collector.visit_ty_unambig(&impl_.self_ty);
if let Some(of_trait) = &impl_.of_trait {
collector.visit_trait_ref(of_trait);
}

View file

@ -1,4 +1,4 @@
use rustc_hir as hir;
use rustc_hir::{self as hir, AmbigArg};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::fold::BottomUpFolder;
@ -67,7 +67,7 @@ declare_lint! {
declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
let hir::TyKind::OpaqueDef(opaque) = &ty.kind else {
return;
};

View file

@ -1,6 +1,5 @@
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::{GenericArg, PathSegment, QPath, TyKind};
use rustc_hir::{self as hir, AmbigArg, GenericArg, PathSegment, QPath, TyKind};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
@ -22,7 +21,7 @@ declare_tool_lint! {
declare_lint_pass!(PassByValue => [PASS_BY_VALUE]);
impl<'tcx> LateLintPass<'tcx> for PassByValue {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
match &ty.kind {
TyKind::Ref(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {

View file

@ -25,7 +25,7 @@ macro_rules! late_lint_methods {
fn check_pat(a: &'tcx rustc_hir::Pat<'tcx>);
fn check_expr(a: &'tcx rustc_hir::Expr<'tcx>);
fn check_expr_post(a: &'tcx rustc_hir::Expr<'tcx>);
fn check_ty(a: &'tcx rustc_hir::Ty<'tcx>);
fn check_ty(a: &'tcx rustc_hir::Ty<'tcx, rustc_hir::AmbigArg>);
fn check_generic_param(a: &'tcx rustc_hir::GenericParam<'tcx>);
fn check_generics(a: &'tcx rustc_hir::Generics<'tcx>);
fn check_poly_trait_ref(a: &'tcx rustc_hir::PolyTraitRef<'tcx>);

View file

@ -1,4 +1,4 @@
use rustc_hir::{self as hir, LangItem};
use rustc_hir::{self as hir, AmbigArg, LangItem};
use rustc_session::{declare_lint, declare_lint_pass};
use rustc_span::sym;
@ -110,8 +110,10 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
}
}
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return };
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
let hir::TyKind::TraitObject(bounds, _lifetime_and_syntax_pointer) = &ty.kind else {
return;
};
for bound in &bounds[..] {
let def_id = bound.trait_ref.trait_def_id();
if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) {

View file

@ -4,7 +4,8 @@ use std::ops::ControlFlow;
use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, WrappingRange};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::DiagMessage;
use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{AmbigArg, Expr, ExprKind, LangItem};
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
use rustc_middle::ty::{
@ -1526,7 +1527,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
impl<'a, 'b, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'a, 'b, 'tcx> {
fn visit_ty(&mut self, ty: &'_ hir::Ty<'_>) {
fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
debug!(?ty);
if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind
&& !self.visitor.is_internal_abi(*abi)
@ -1554,7 +1555,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
let mut visitor = FnPtrFinder { visitor: self, spans: Vec::new(), tys: Vec::new() };
ty.visit_with(&mut visitor);
hir::intravisit::Visitor::visit_ty(&mut visitor, hir_ty);
visitor.visit_ty_unambig(hir_ty);
iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)).collect()
}

View file

@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Formatter};
use rustc_index::IndexVec;
use rustc_index::bit_set::DenseBitSet;
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
use rustc_span::Span;
rustc_index::newtype_index! {
@ -72,7 +72,7 @@ impl ConditionId {
/// Enum that can hold a constant zero value, the ID of an physical coverage
/// counter, or the ID of a coverage-counter expression.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
pub enum CovTerm {
Zero,
Counter(CounterId),
@ -89,7 +89,7 @@ impl Debug for CovTerm {
}
}
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum CoverageKind {
/// Marks a span that might otherwise not be represented in MIR, so that
/// coverage instrumentation can associate it with its enclosing block/BCB.
@ -151,7 +151,7 @@ impl Debug for CoverageKind {
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
#[derive(TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable)]
pub enum Op {
Subtract,
Add,
@ -168,7 +168,7 @@ impl Op {
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
pub struct Expression {
pub lhs: CovTerm,
pub op: Op,
@ -176,7 +176,7 @@ pub struct Expression {
}
#[derive(Clone, Debug)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
pub enum MappingKind {
/// Associates a normal region of code with a counter/expression/zero.
Code(CovTerm),
@ -208,7 +208,7 @@ impl MappingKind {
}
#[derive(Clone, Debug)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
pub struct Mapping {
pub kind: MappingKind,
pub span: Span,
@ -218,7 +218,7 @@ pub struct Mapping {
/// to be used in conjunction with the individual coverage statements injected
/// into the function's basic blocks.
#[derive(Clone, Debug)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
pub struct FunctionCoverageInfo {
pub function_source_hash: u64,
pub body_span: Span,
@ -238,7 +238,7 @@ pub struct FunctionCoverageInfo {
/// ("Hi" indicates that this is "high-level" information collected at the
/// THIR/MIR boundary, before the MIR-based coverage instrumentation pass.)
#[derive(Clone, Debug)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
pub struct CoverageInfoHi {
/// 1 more than the highest-numbered [`CoverageKind::BlockMarker`] that was
/// injected into the MIR body. This makes it possible to allocate per-ID
@ -252,7 +252,7 @@ pub struct CoverageInfoHi {
}
#[derive(Clone, Debug)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
pub struct BranchSpan {
pub span: Span,
pub true_marker: BlockMarkerId,
@ -260,7 +260,7 @@ pub struct BranchSpan {
}
#[derive(Copy, Clone, Debug)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
pub struct ConditionInfo {
pub condition_id: ConditionId,
pub true_next_id: Option<ConditionId>,
@ -268,7 +268,7 @@ pub struct ConditionInfo {
}
#[derive(Clone, Debug)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
pub struct MCDCBranchSpan {
pub span: Span,
pub condition_info: ConditionInfo,
@ -277,14 +277,14 @@ pub struct MCDCBranchSpan {
}
#[derive(Copy, Clone, Debug)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
pub struct DecisionInfo {
pub bitmap_idx: u32,
pub num_conditions: u16,
}
#[derive(Clone, Debug)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
pub struct MCDCDecisionSpan {
pub span: Span,
pub end_markers: Vec<BlockMarkerId>,

View file

@ -358,6 +358,8 @@ pub struct Body<'tcx> {
///
/// Only present if coverage is enabled and this function is eligible.
/// Boxed to limit space overhead in non-coverage builds.
#[type_foldable(identity)]
#[type_visitable(ignore)]
pub coverage_info_hi: Option<Box<coverage::CoverageInfoHi>>,
/// Per-function coverage information added by the `InstrumentCoverage`
@ -366,6 +368,8 @@ pub struct Body<'tcx> {
///
/// If `-Cinstrument-coverage` is not active, or if an individual function
/// is not eligible for coverage, then this should always be `None`.
#[type_foldable(identity)]
#[type_visitable(ignore)]
pub function_coverage_info: Option<Box<coverage::FunctionCoverageInfo>>,
}

View file

@ -417,7 +417,14 @@ pub enum StatementKind<'tcx> {
///
/// Interpreters and codegen backends that don't support coverage instrumentation
/// can usually treat this as a no-op.
Coverage(CoverageKind),
Coverage(
// Coverage statements are unlikely to ever contain type information in
// the foreseeable future, so excluding them from TypeFoldable/TypeVisitable
// avoids some unhelpful derive boilerplate.
#[type_foldable(identity)]
#[type_visitable(ignore)]
CoverageKind,
),
/// Denotes a call to an intrinsic that does not require an unwind path and always returns.
/// This avoids adding a new block and a terminator for simple intrinsics.

View file

@ -618,7 +618,9 @@ rustc_queries! {
/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
/// have had a chance to potentially remove some of them.
query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> &'tcx mir::coverage::CoverageIdsInfo {
///
/// Returns `None` for functions that were not instrumented.
query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> Option<&'tcx mir::coverage::CoverageIdsInfo> {
desc { |tcx| "retrieving coverage IDs info from MIR for `{}`", tcx.def_path_str(key.def_id()) }
arena_cache
}

View file

@ -33,7 +33,7 @@ use rustc_errors::{
use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::definitions::Definitions;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate};
use rustc_index::IndexVec;
@ -2028,7 +2028,7 @@ impl<'tcx> TyCtxt<'tcx> {
};
let mut v = TraitObjectVisitor(vec![], self.hir());
v.visit_ty(hir_output);
v.visit_ty_unambig(hir_output);
v.0
}
@ -2050,7 +2050,7 @@ impl<'tcx> TyCtxt<'tcx> {
&& let Some(alias_ty) = self.hir_node_by_def_id(local_id).alias_ty() // it is type alias
&& let Some(alias_generics) = self.hir_node_by_def_id(local_id).generics()
{
v.visit_ty(alias_ty);
v.visit_ty_unambig(alias_ty);
if !v.0.is_empty() {
return Some((
v.0,

View file

@ -9,7 +9,7 @@ use rustc_errors::{
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, LangItem, PredicateOrigin, WherePredicateKind};
use rustc_hir::{self as hir, AmbigArg, LangItem, PredicateOrigin, WherePredicateKind};
use rustc_span::{BytePos, Span};
use rustc_type_ir::TyKind::*;
@ -570,18 +570,18 @@ pub fn suggest_constraining_type_params<'a>(
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
match ty.kind {
hir::TyKind::TraitObject(
_,
hir::Lifetime {
hir::TyKind::TraitObject(_, tagged_ptr)
if let hir::Lifetime {
res:
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
..
},
_,
)
| hir::TyKind::OpaqueDef(..) => self.0.push(ty),
} = tagged_ptr.pointer() =>
{
self.0.push(ty.as_unambig_ty())
}
hir::TyKind::OpaqueDef(..) => self.0.push(ty.as_unambig_ty()),
_ => {}
}
hir::intravisit::walk_ty(self, ty);

View file

@ -374,7 +374,13 @@ fn find_item_ty_spans(
if let hir::GenericArg::Type(ty) = arg
&& params_in_repr.contains(i as u32)
{
find_item_ty_spans(tcx, ty, needle, spans, seen_representable);
find_item_ty_spans(
tcx,
ty.as_unambig_ty(),
needle,
spans,
seen_representable,
);
}
}
}

View file

@ -785,6 +785,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let local =
place.as_local().unwrap_or_else(|| bug!("projection in tail call args"));
if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) {
return None;
}
Some(DropData { source_info, local, kind: DropKind::Value })
}
Operand::Constant(_) => None,
@ -795,6 +799,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.scopes.scopes.iter().rev().nth(1).unwrap().region_scope,
DUMMY_SP,
);
let typing_env = self.typing_env();
let unwind_drops = &mut self.scopes.unwind_drops;
// the innermost scope contains only the destructors for the tail call arguments
@ -805,6 +810,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let source_info = drop_data.source_info;
let local = drop_data.local;
if !self.local_decls[local].ty.needs_drop(self.tcx, typing_env) {
continue;
}
match drop_data.kind {
DropKind::Value => {
// `unwind_to` should drop the value that we're about to

View file

@ -11,7 +11,9 @@ use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId,
use crate::coverage::counters::balanced_flow::BalancedFlowGraph;
use crate::coverage::counters::iter_nodes::IterNodes;
use crate::coverage::counters::node_flow::{CounterTerm, MergedNodeFlowGraph, NodeCounters};
use crate::coverage::counters::node_flow::{
CounterTerm, NodeCounters, make_node_counters, node_flow_data_for_balanced_graph,
};
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
mod balanced_flow;
@ -27,12 +29,12 @@ pub(super) fn make_bcb_counters(
) -> CoverageCounters {
// Create the derived graphs that are necessary for subsequent steps.
let balanced_graph = BalancedFlowGraph::for_graph(graph, |n| !graph[n].is_out_summable);
let merged_graph = MergedNodeFlowGraph::for_balanced_graph(&balanced_graph);
let node_flow_data = node_flow_data_for_balanced_graph(&balanced_graph);
// Use those graphs to determine which nodes get physical counters, and how
// to compute the execution counts of other nodes from those counters.
let nodes = make_node_counter_priority_list(graph, balanced_graph);
let node_counters = merged_graph.make_node_counters(&nodes);
let priority_list = make_node_flow_priority_list(graph, balanced_graph);
let node_counters = make_node_counters(&node_flow_data, &priority_list);
// Convert the counters into a form suitable for embedding into MIR.
transcribe_counters(&node_counters, bcb_needs_counter)
@ -40,7 +42,7 @@ pub(super) fn make_bcb_counters(
/// Arranges the nodes in `balanced_graph` into a list, such that earlier nodes
/// take priority in being given a counter expression instead of a physical counter.
fn make_node_counter_priority_list(
fn make_node_flow_priority_list(
graph: &CoverageGraph,
balanced_graph: BalancedFlowGraph<&CoverageGraph>,
) -> Vec<BasicCoverageBlock> {
@ -81,11 +83,11 @@ fn transcribe_counters(
let mut new = CoverageCounters::with_num_bcbs(bcb_needs_counter.domain_size());
for bcb in bcb_needs_counter.iter() {
// Our counter-creation algorithm doesn't guarantee that a counter
// expression starts or ends with a positive term, so partition the
// Our counter-creation algorithm doesn't guarantee that a node's list
// of terms starts or ends with a positive term, so partition the
// counters into "positive" and "negative" lists for easier handling.
let (mut pos, mut neg): (Vec<_>, Vec<_>) =
old.counter_expr(bcb).iter().partition_map(|&CounterTerm { node, op }| match op {
old.counter_terms[bcb].iter().partition_map(|&CounterTerm { node, op }| match op {
Op::Add => Either::Left(node),
Op::Subtract => Either::Right(node),
});

View file

@ -8,18 +8,17 @@
use rustc_data_structures::graph;
use rustc_index::bit_set::DenseBitSet;
use rustc_index::{Idx, IndexVec};
use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_middle::mir::coverage::Op;
use smallvec::SmallVec;
use crate::coverage::counters::iter_nodes::IterNodes;
use crate::coverage::counters::union_find::{FrozenUnionFind, UnionFind};
use crate::coverage::counters::union_find::UnionFind;
#[cfg(test)]
mod tests;
/// View of some underlying graph, in which each node's successors have been
/// merged into a single "supernode".
/// Data representing a view of some underlying graph, in which each node's
/// successors have been merged into a single "supernode".
///
/// The resulting supernodes have no obvious meaning on their own.
/// However, merging successor nodes means that a node's out-edges can all
@ -30,10 +29,10 @@ mod tests;
/// in the merged graph, it becomes possible to analyze the original node flows
/// using techniques for analyzing edge flows.
#[derive(Debug)]
pub(crate) struct MergedNodeFlowGraph<Node: Idx> {
pub(crate) struct NodeFlowData<Node: Idx> {
/// Maps each node to the supernode that contains it, indicated by some
/// arbitrary "root" node that is part of that supernode.
supernodes: FrozenUnionFind<Node>,
supernodes: IndexVec<Node, Node>,
/// For each node, stores the single supernode that all of its successors
/// have been merged into.
///
@ -42,84 +41,71 @@ pub(crate) struct MergedNodeFlowGraph<Node: Idx> {
succ_supernodes: IndexVec<Node, Node>,
}
impl<Node: Idx> MergedNodeFlowGraph<Node> {
/// Creates a "merged" view of an underlying graph.
///
/// The given graph is assumed to have [“balanced flow”](balanced-flow),
/// though it does not necessarily have to be a `BalancedFlowGraph`.
///
/// [balanced-flow]: `crate::coverage::counters::balanced_flow::BalancedFlowGraph`.
pub(crate) fn for_balanced_graph<G>(graph: G) -> Self
where
G: graph::DirectedGraph<Node = Node> + graph::Successors,
{
let mut supernodes = UnionFind::<G::Node>::new(graph.num_nodes());
/// Creates a "merged" view of an underlying graph.
///
/// The given graph is assumed to have [“balanced flow”](balanced-flow),
/// though it does not necessarily have to be a `BalancedFlowGraph`.
///
/// [balanced-flow]: `crate::coverage::counters::balanced_flow::BalancedFlowGraph`.
pub(crate) fn node_flow_data_for_balanced_graph<G>(graph: G) -> NodeFlowData<G::Node>
where
G: graph::Successors,
{
let mut supernodes = UnionFind::<G::Node>::new(graph.num_nodes());
// For each node, merge its successors into a single supernode, and
// arbitrarily choose one of those successors to represent all of them.
let successors = graph
.iter_nodes()
.map(|node| {
graph
.successors(node)
.reduce(|a, b| supernodes.unify(a, b))
.expect("each node in a balanced graph must have at least one out-edge")
})
.collect::<IndexVec<G::Node, G::Node>>();
// For each node, merge its successors into a single supernode, and
// arbitrarily choose one of those successors to represent all of them.
let successors = graph
.iter_nodes()
.map(|node| {
graph
.successors(node)
.reduce(|a, b| supernodes.unify(a, b))
.expect("each node in a balanced graph must have at least one out-edge")
})
.collect::<IndexVec<G::Node, G::Node>>();
// Now that unification is complete, freeze the supernode forest,
// and resolve each arbitrarily-chosen successor to its canonical root.
// (This avoids having to explicitly resolve them later.)
let supernodes = supernodes.freeze();
let succ_supernodes = successors.into_iter().map(|succ| supernodes.find(succ)).collect();
// Now that unification is complete, take a snapshot of the supernode forest,
// and resolve each arbitrarily-chosen successor to its canonical root.
// (This avoids having to explicitly resolve them later.)
let supernodes = supernodes.snapshot();
let succ_supernodes = successors.into_iter().map(|succ| supernodes[succ]).collect();
Self { supernodes, succ_supernodes }
NodeFlowData { supernodes, succ_supernodes }
}
/// Uses the graph information in `node_flow_data`, together with a given
/// permutation of all nodes in the graph, to create physical counters and
/// counter expressions for each node in the underlying graph.
///
/// The given list must contain exactly one copy of each node in the
/// underlying balanced-flow graph. The order of nodes is used as a hint to
/// influence counter allocation:
/// - Earlier nodes are more likely to receive counter expressions.
/// - Later nodes are more likely to receive physical counters.
pub(crate) fn make_node_counters<Node: Idx>(
node_flow_data: &NodeFlowData<Node>,
priority_list: &[Node],
) -> NodeCounters<Node> {
let mut builder = SpantreeBuilder::new(node_flow_data);
for &node in priority_list {
builder.visit_node(node);
}
fn num_nodes(&self) -> usize {
self.succ_supernodes.len()
}
fn is_supernode(&self, node: Node) -> bool {
self.supernodes.find(node) == node
}
/// Using the information in this merged graph, together with a given
/// permutation of all nodes in the graph, to create physical counters and
/// counter expressions for each node in the underlying graph.
///
/// The given list must contain exactly one copy of each node in the
/// underlying balanced-flow graph. The order of nodes is used as a hint to
/// influence counter allocation:
/// - Earlier nodes are more likely to receive counter expressions.
/// - Later nodes are more likely to receive physical counters.
pub(crate) fn make_node_counters(&self, all_nodes_permutation: &[Node]) -> NodeCounters<Node> {
let mut builder = SpantreeBuilder::new(self);
for &node in all_nodes_permutation {
builder.visit_node(node);
}
NodeCounters { counter_exprs: builder.finish() }
}
NodeCounters { counter_terms: builder.finish() }
}
/// End result of allocating physical counters and counter expressions for the
/// nodes of a graph.
#[derive(Debug)]
pub(crate) struct NodeCounters<Node: Idx> {
counter_exprs: IndexVec<Node, CounterExprVec<Node>>,
}
impl<Node: Idx> NodeCounters<Node> {
/// For the given node, returns the finished list of terms that represent
/// its physical counter or counter expression. Always non-empty.
///
/// If a node was given a physical counter, its "expression" will contain
/// If a node was given a physical counter, the term list will contain
/// that counter as its sole element.
pub(crate) fn counter_expr(&self, this: Node) -> &[CounterTerm<Node>] {
self.counter_exprs[this].as_slice()
}
pub(crate) counter_terms: IndexVec<Node, Vec<CounterTerm<Node>>>,
}
#[derive(Debug)]
@ -146,12 +132,11 @@ pub(crate) struct CounterTerm<Node> {
pub(crate) node: Node,
}
/// Stores the list of counter terms that make up a node's counter expression.
type CounterExprVec<Node> = SmallVec<[CounterTerm<Node>; 2]>;
#[derive(Debug)]
struct SpantreeBuilder<'a, Node: Idx> {
graph: &'a MergedNodeFlowGraph<Node>,
supernodes: &'a IndexSlice<Node, Node>,
succ_supernodes: &'a IndexSlice<Node, Node>,
is_unvisited: DenseBitSet<Node>,
/// Links supernodes to each other, gradually forming a spanning tree of
/// the merged-flow graph.
@ -163,26 +148,32 @@ struct SpantreeBuilder<'a, Node: Idx> {
yank_buffer: Vec<Node>,
/// An in-progress counter expression for each node. Each expression is
/// initially empty, and will be filled in as relevant nodes are visited.
counter_exprs: IndexVec<Node, CounterExprVec<Node>>,
counter_terms: IndexVec<Node, Vec<CounterTerm<Node>>>,
}
impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
fn new(graph: &'a MergedNodeFlowGraph<Node>) -> Self {
let num_nodes = graph.num_nodes();
fn new(node_flow_data: &'a NodeFlowData<Node>) -> Self {
let NodeFlowData { supernodes, succ_supernodes } = node_flow_data;
let num_nodes = supernodes.len();
Self {
graph,
supernodes,
succ_supernodes,
is_unvisited: DenseBitSet::new_filled(num_nodes),
span_edges: IndexVec::from_fn_n(|_| None, num_nodes),
yank_buffer: vec![],
counter_exprs: IndexVec::from_fn_n(|_| SmallVec::new(), num_nodes),
counter_terms: IndexVec::from_fn_n(|_| vec![], num_nodes),
}
}
fn is_supernode(&self, node: Node) -> bool {
self.supernodes[node] == node
}
/// Given a supernode, finds the supernode that is the "root" of its
/// spantree component. Two nodes that have the same spantree root are
/// connected in the spantree.
fn spantree_root(&self, this: Node) -> Node {
debug_assert!(self.graph.is_supernode(this));
debug_assert!(self.is_supernode(this));
match self.span_edges[this] {
None => this,
@ -193,7 +184,7 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
/// Rotates edges in the spantree so that `this` is the root of its
/// spantree component.
fn yank_to_spantree_root(&mut self, this: Node) {
debug_assert!(self.graph.is_supernode(this));
debug_assert!(self.is_supernode(this));
// The rotation is done iteratively, by first traversing from `this` to
// its root and storing the path in a buffer, and then traversing the
@ -235,12 +226,12 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
// Get the supernode containing `this`, and make it the root of its
// component of the spantree.
let this_supernode = self.graph.supernodes.find(this);
let this_supernode = self.supernodes[this];
self.yank_to_spantree_root(this_supernode);
// Get the supernode containing all of this's successors.
let succ_supernode = self.graph.succ_supernodes[this];
debug_assert!(self.graph.is_supernode(succ_supernode));
let succ_supernode = self.succ_supernodes[this];
debug_assert!(self.is_supernode(succ_supernode));
// If two supernodes are already connected in the spantree, they will
// have the same spantree root. (Each supernode is connected to itself.)
@ -268,8 +259,8 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
// `this_supernode`.
// Instead of setting `this.measure = true` as in the original paper,
// we just add the node's ID to its own "expression".
self.counter_exprs[this].push(CounterTerm { node: this, op: Op::Add });
// we just add the node's ID to its own list of terms.
self.counter_terms[this].push(CounterTerm { node: this, op: Op::Add });
// Walk the spantree from `this.successor` back to `this`. For each
// spantree edge along the way, add this node's physical counter to
@ -279,7 +270,7 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
let &SpantreeEdge { is_reversed, claiming_node, span_parent } =
self.span_edges[curr].as_ref().unwrap();
let op = if is_reversed { Op::Subtract } else { Op::Add };
self.counter_exprs[claiming_node].push(CounterTerm { node: this, op });
self.counter_terms[claiming_node].push(CounterTerm { node: this, op });
curr = span_parent;
}
@ -288,19 +279,20 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
/// Asserts that all nodes have been visited, and returns the computed
/// counter expressions (made up of physical counters) for each node.
fn finish(self) -> IndexVec<Node, CounterExprVec<Node>> {
let Self { graph, is_unvisited, span_edges, yank_buffer: _, counter_exprs } = self;
fn finish(self) -> IndexVec<Node, Vec<CounterTerm<Node>>> {
let Self { ref span_edges, ref is_unvisited, ref counter_terms, .. } = self;
assert!(is_unvisited.is_empty(), "some nodes were never visited: {is_unvisited:?}");
debug_assert!(
span_edges
.iter_enumerated()
.all(|(node, span_edge)| { span_edge.is_some() <= graph.is_supernode(node) }),
.all(|(node, span_edge)| { span_edge.is_some() <= self.is_supernode(node) }),
"only supernodes can have a span edge",
);
debug_assert!(
counter_exprs.iter().all(|expr| !expr.is_empty()),
"after visiting all nodes, every node should have a non-empty expression",
counter_terms.iter().all(|terms| !terms.is_empty()),
"after visiting all nodes, every node should have at least one term",
);
counter_exprs
self.counter_terms
}
}

View file

@ -4,10 +4,12 @@ use rustc_data_structures::graph::vec_graph::VecGraph;
use rustc_index::Idx;
use rustc_middle::mir::coverage::Op;
use super::{CounterTerm, MergedNodeFlowGraph, NodeCounters};
use crate::coverage::counters::node_flow::{
CounterTerm, NodeCounters, NodeFlowData, make_node_counters, node_flow_data_for_balanced_graph,
};
fn merged_node_flow_graph<G: graph::Successors>(graph: G) -> MergedNodeFlowGraph<G::Node> {
MergedNodeFlowGraph::for_balanced_graph(graph)
fn node_flow_data<G: graph::Successors>(graph: G) -> NodeFlowData<G::Node> {
node_flow_data_for_balanced_graph(graph)
}
fn make_graph<Node: Idx + Ord>(num_nodes: usize, edge_pairs: Vec<(Node, Node)>) -> VecGraph<Node> {
@ -30,8 +32,8 @@ fn example_driver() {
(4, 0),
]);
let merged = merged_node_flow_graph(&graph);
let counters = merged.make_node_counters(&[3, 1, 2, 0, 4]);
let node_flow_data = node_flow_data(&graph);
let counters = make_node_counters(&node_flow_data, &[3, 1, 2, 0, 4]);
assert_eq!(format_counter_expressions(&counters), &[
// (comment to force vertical formatting for clarity)
@ -53,12 +55,12 @@ fn format_counter_expressions<Node: Idx>(counters: &NodeCounters<Node>) -> Vec<S
};
counters
.counter_exprs
.counter_terms
.indices()
.map(|node| {
let mut expr = counters.counter_expr(node).iter().collect::<Vec<_>>();
expr.sort_by_key(|item| item.node.index());
format!("[{node:?}]: {}", expr.into_iter().map(format_item).join(" "))
let mut terms = counters.counter_terms[node].iter().collect::<Vec<_>>();
terms.sort_by_key(|item| item.node.index());
format!("[{node:?}]: {}", terms.into_iter().map(format_item).join(" "))
})
.collect()
}

View file

@ -88,29 +88,9 @@ impl<Key: Idx> UnionFind<Key> {
a
}
/// Creates a snapshot of this disjoint-set forest that can no longer be
/// mutated, but can be queried without mutation.
pub(crate) fn freeze(&mut self) -> FrozenUnionFind<Key> {
// Just resolve each key to its actual root.
let roots = self.table.indices().map(|key| self.find(key)).collect();
FrozenUnionFind { roots }
}
}
/// Snapshot of a disjoint-set forest that can no longer be mutated, but can be
/// queried in O(1) time without mutation.
///
/// This is really just a wrapper around a direct mapping from keys to roots,
/// but with a [`Self::find`] method that resembles [`UnionFind::find`].
#[derive(Debug)]
pub(crate) struct FrozenUnionFind<Key: Idx> {
roots: IndexVec<Key, Key>,
}
impl<Key: Idx> FrozenUnionFind<Key> {
/// Returns the "root" key of the disjoint-set containing the given key.
/// If two keys have the same root, they belong to the same set.
pub(crate) fn find(&self, key: Key) -> Key {
self.roots[key]
/// Takes a "snapshot" of the current state of this disjoint-set forest, in
/// the form of a vector that directly maps each key to its current root.
pub(crate) fn snapshot(&mut self) -> IndexVec<Key, Key> {
self.table.indices().map(|key| self.find(key)).collect()
}
}

View file

@ -180,7 +180,12 @@ fn create_mappings(
));
for (decision, branches) in mcdc_mappings {
let num_conditions = branches.len() as u16;
// FIXME(#134497): Previously it was possible for some of these branch
// conversions to fail, in which case the remaining branches in the
// decision would be degraded to plain `MappingKind::Branch`.
// The changes in #134497 made that failure impossible, because the
// fallible step was deferred to codegen. But the corresponding code
// in codegen wasn't updated to detect the need for a degrade step.
let conditions = branches
.into_iter()
.map(
@ -206,24 +211,13 @@ fn create_mappings(
)
.collect::<Vec<_>>();
if conditions.len() == num_conditions as usize {
// LLVM requires end index for counter mapping regions.
let kind = MappingKind::MCDCDecision(DecisionInfo {
bitmap_idx: (decision.bitmap_idx + decision.num_test_vectors) as u32,
num_conditions,
});
let span = decision.span;
mappings.extend(std::iter::once(Mapping { kind, span }).chain(conditions.into_iter()));
} else {
mappings.extend(conditions.into_iter().map(|mapping| {
let MappingKind::MCDCBranch { true_term, false_term, mcdc_params: _ } =
mapping.kind
else {
unreachable!("all mappings here are MCDCBranch as shown above");
};
Mapping { kind: MappingKind::Branch { true_term, false_term }, span: mapping.span }
}))
}
// LLVM requires end index for counter mapping regions.
let kind = MappingKind::MCDCDecision(DecisionInfo {
bitmap_idx: (decision.bitmap_idx + decision.num_test_vectors) as u32,
num_conditions: u16::try_from(conditions.len()).unwrap(),
});
let span = decision.span;
mappings.extend(std::iter::once(Mapping { kind, span }).chain(conditions.into_iter()));
}
mappings

View file

@ -87,15 +87,9 @@ fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
fn coverage_ids_info<'tcx>(
tcx: TyCtxt<'tcx>,
instance_def: ty::InstanceKind<'tcx>,
) -> CoverageIdsInfo {
) -> Option<CoverageIdsInfo> {
let mir_body = tcx.instance_mir(instance_def);
let Some(fn_cov_info) = mir_body.function_coverage_info.as_deref() else {
return CoverageIdsInfo {
counters_seen: DenseBitSet::new_empty(0),
zero_expressions: DenseBitSet::new_empty(0),
};
};
let fn_cov_info = mir_body.function_coverage_info.as_deref()?;
let mut counters_seen = DenseBitSet::new_empty(fn_cov_info.num_counters);
let mut expressions_seen = DenseBitSet::new_filled(fn_cov_info.expressions.len());
@ -129,7 +123,7 @@ fn coverage_ids_info<'tcx>(
let zero_expressions =
identify_zero_expressions(fn_cov_info, &counters_seen, &expressions_seen);
CoverageIdsInfo { counters_seen, zero_expressions }
Some(CoverageIdsInfo { counters_seen, zero_expressions })
}
fn all_coverage_in_mir_body<'a, 'tcx>(

View file

@ -189,8 +189,9 @@ pub struct Parser<'a> {
}
// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with
// nonterminals. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_pointer_width = "64", not(target_arch = "s390x")))]
// nonterminals. Make sure it doesn't unintentionally get bigger. We only check a few arches
// though, because `TokenTypeSet(u128)` alignment varies on others, changing the total size.
#[cfg(all(target_pointer_width = "64", any(target_arch = "aarch64", target_arch = "x86_64")))]
rustc_data_structures::static_assert_size!(Parser<'_>, 288);
/// Stores span information about a closure.

View file

@ -2808,7 +2808,7 @@ fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool {
&& let Some(&[hir::GenericArg::Type(ty)]) =
path.segments.last().map(|last| last.args().args)
{
doc_fake_variadic_is_allowed_self_ty(ty)
doc_fake_variadic_is_allowed_self_ty(ty.as_unambig_ty())
} else {
false
})

View file

@ -460,7 +460,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
}
// mark self_ty live
intravisit::walk_ty(self, impl_ref.self_ty);
intravisit::walk_unambig_ty(self, impl_ref.self_ty);
if let Some(&impl_item_id) =
self.tcx.impl_item_implementor_ids(impl_id).get(&trait_item_id)
{

View file

@ -5,8 +5,7 @@
use rustc_ast::visit::BoundKind;
use rustc_ast::{self as ast, NodeId, visit as ast_visit};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::{HirId, intravisit as hir_visit};
use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::TyCtxt;
use rustc_middle::util::common::to_readable_str;
@ -363,7 +362,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
hir_visit::walk_expr_field(self, f)
}
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, t: &'v hir::Ty<'v, AmbigArg>) {
record_variants!((self, t, t.kind, Some(t.hir_id), hir, Ty, TyKind), [
InferDelegation,
Slice,
@ -476,7 +475,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
hir::GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
hir::GenericArg::Type(ty) => self.visit_ty(ty),
hir::GenericArg::Const(ct) => self.visit_const_arg(ct),
hir::GenericArg::Infer(inf) => self.visit_infer(inf),
hir::GenericArg::Infer(inf) => self.visit_id(inf.hir_id),
}
}

View file

@ -11,12 +11,11 @@ use rustc_attr_parsing::{
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
use rustc_middle::middle::privacy::EffectiveVisibilities;
@ -802,7 +801,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
)) = stab
{
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
c.visit_ty(self_ty);
c.visit_ty_unambig(self_ty);
c.visit_trait_ref(t);
// do not lint when the trait isn't resolved, since resolution error should
@ -1028,7 +1027,7 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
intravisit::walk_trait_ref(self, t)
}
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) {
if let TyKind::Never = t.kind {
self.fully_stable = false;
}
@ -1042,12 +1041,12 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
for ty in fd.inputs {
self.visit_ty(ty)
self.visit_ty_unambig(ty)
}
if let hir::FnRetTy::Return(output_ty) = fd.output {
match output_ty.kind {
TyKind::Never => {} // `-> !` is stable
_ => self.visit_ty(output_ty),
_ => self.visit_ty_unambig(output_ty),
}
}
}

View file

@ -27,8 +27,8 @@ use rustc_data_structures::intern::Interned;
use rustc_errors::MultiSpan;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind};
use rustc_hir::intravisit::{self, InferKind, Visitor};
use rustc_hir::{AmbigArg, AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind};
use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
use rustc_middle::query::Providers;
use rustc_middle::ty::print::PrintTraitRefExt as _;
@ -1179,7 +1179,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
self.maybe_typeck_results = old_maybe_typeck_results;
}
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
self.span = hir_ty.span;
if self
.visit(
@ -1195,12 +1195,17 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
intravisit::walk_ty(self, hir_ty);
}
fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
self.span = inf.span;
fn visit_infer(
&mut self,
inf_id: rustc_hir::HirId,
inf_span: Span,
_kind: InferKind<'tcx>,
) -> Self::Result {
self.span = inf_span;
if let Some(ty) = self
.maybe_typeck_results
.unwrap_or_else(|| span_bug!(inf.span, "`hir::InferArg` outside of a body"))
.node_type_opt(inf.hir_id)
.unwrap_or_else(|| span_bug!(inf_span, "Inference variable outside of a body"))
.node_type_opt(inf_id)
{
if self.visit(ty).is_break() {
return;
@ -1208,7 +1213,8 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
} else {
// FIXME: check types of const infers here.
}
intravisit::walk_inf(self, inf);
self.visit_id(inf_id)
}
// Check types of expressions

View file

@ -1853,6 +1853,8 @@ supported_targets! {
("armv7a-none-eabi", armv7a_none_eabi),
("armv7a-none-eabihf", armv7a_none_eabihf),
("armv7a-nuttx-eabi", armv7a_nuttx_eabi),
("armv7a-nuttx-eabihf", armv7a_nuttx_eabihf),
("msp430-none-elf", msp430_none_elf),
@ -1896,6 +1898,7 @@ supported_targets! {
("aarch64-unknown-none", aarch64_unknown_none),
("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat),
("aarch64-unknown-nuttx", aarch64_unknown_nuttx),
("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx),
@ -1971,6 +1974,8 @@ supported_targets! {
("x86_64-unknown-linux-none", x86_64_unknown_linux_none),
("thumbv6m-nuttx-eabi", thumbv6m_nuttx_eabi),
("thumbv7a-nuttx-eabi", thumbv7a_nuttx_eabi),
("thumbv7a-nuttx-eabihf", thumbv7a_nuttx_eabihf),
("thumbv7m-nuttx-eabi", thumbv7m_nuttx_eabi),
("thumbv7em-nuttx-eabi", thumbv7em_nuttx_eabi),
("thumbv7em-nuttx-eabihf", thumbv7em_nuttx_eabihf),

View file

@ -7,7 +7,8 @@
// For example, `-C target-cpu=cortex-a53`.
use crate::spec::{
Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, StackProbeType, Target, TargetOptions,
Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target,
TargetOptions,
};
pub(crate) fn target() -> Target {
@ -19,6 +20,7 @@ pub(crate) fn target() -> Target {
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
stack_probes: StackProbeType::Inline,
panic_strategy: PanicStrategy::Abort,
..Default::default()

View file

@ -0,0 +1,46 @@
// Generic AArch64 target for NuttX OS
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
//
// For example, `-C target-cpu=cortex-a53`.
use crate::spec::{
Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target,
TargetOptions, cvs,
};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
// Enable the Cortex-A53 errata 843419 mitigation by default
pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), &[
"--fix-cortex-a53-843419",
]),
features: "+v8a,+strict-align,+neon,+fp-armv8".into(),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(128),
stack_probes: StackProbeType::Inline,
panic_strategy: PanicStrategy::Abort,
families: cvs!["unix"],
os: "nuttx".into(),
..Default::default()
};
Target {
llvm_target: "aarch64-unknown-none".into(),
metadata: crate::spec::TargetMetadata {
description: Some("AArch64 NuttX".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 64,
data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
arch: "aarch64".into(),
options: opts,
}
}

View file

@ -0,0 +1,41 @@
// Targets Cortex-A7/A8/A9 processors (ARMv7-A) running NuttX
//
// This target assumes that the device does NOT have a FPU (Floating Point Unit)
// and will use software floating point operations. This matches the NuttX EABI
// configuration without hardware floating point support.
use crate::spec::{
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+v7,+thumb2,+soft-float,-neon,+strict-align".into(),
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(64),
panic_strategy: PanicStrategy::Abort,
emit_debug_gdb_scripts: false,
c_enum_min_bits: Some(8),
families: cvs!["unix"],
os: "nuttx".into(),
..Default::default()
};
Target {
llvm_target: "armv7a-none-eabi".into(),
metadata: crate::spec::TargetMetadata {
description: Some("ARMv7-A Cortex-A with NuttX".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: "arm".into(),
options: opts,
}
}

View file

@ -0,0 +1,41 @@
// Targets Cortex-A7/A8/A9 processors (ARMv7-A) running NuttX with hardware floating point
//
// This target assumes that the device has a FPU (Floating Point Unit)
// and will use hardware floating point operations. This matches the NuttX EABI
// configuration with hardware floating point support.
use crate::spec::{
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+v7,+thumb2,+vfp3,+neon,+strict-align".into(),
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(64),
panic_strategy: PanicStrategy::Abort,
emit_debug_gdb_scripts: false,
c_enum_min_bits: Some(8),
families: cvs!["unix"],
os: "nuttx".into(),
..Default::default()
};
Target {
llvm_target: "armv7a-none-eabihf".into(),
metadata: crate::spec::TargetMetadata {
description: Some("ARMv7-A Cortex-A with NuttX (hard float)".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: "arm".into(),
options: opts,
}
}

View file

@ -0,0 +1,33 @@
// Targets Cortex-A7/A8/A9 processors (ARMv7-A)
//
// This target assumes that the device does NOT have a FPU (Floating Point Unit)
// and will use software floating point operations. This matches the NuttX EABI
// configuration without hardware floating point support.
use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
pub(crate) fn target() -> Target {
Target {
llvm_target: "thumbv7a-none-eabi".into(),
metadata: crate::spec::TargetMetadata {
description: None,
tier: None,
host_tools: None,
std: None,
},
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: "arm".into(),
options: TargetOptions {
families: cvs!["unix"],
os: "nuttx".into(),
abi: "eabi".into(),
llvm_floatabi: Some(FloatAbi::Soft),
// Cortex-A7/A8/A9 with software floating point
features: "+soft-float,-neon".into(),
max_atomic_width: Some(64),
..base::thumb::opts()
},
}
}

View file

@ -0,0 +1,37 @@
// Targets Cortex-A7/A8/A9 processors (ARMv7-A)
//
// This target assumes that the device has a FPU (Floating Point Unit) and lowers all (single
// precision) floating point operations to hardware instructions. Cortex-A7/A8/A9 processors
// support VFPv3-D32 or VFPv4-D32 floating point units with optional double-precision support.
//
// This target uses the "hard" floating convention (ABI) where floating point values
// are passed to/from subroutines via FPU registers (S0, S1, D0, D1, etc.).
use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs};
pub(crate) fn target() -> Target {
Target {
llvm_target: "thumbv7a-none-eabihf".into(),
metadata: crate::spec::TargetMetadata {
description: None,
tier: None,
host_tools: None,
std: None,
},
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: "arm".into(),
options: TargetOptions {
families: cvs!["unix"],
os: "nuttx".into(),
abi: "eabihf".into(),
llvm_floatabi: Some(FloatAbi::Hard),
// Cortex-A7/A8/A9 support VFPv3-D32/VFPv4-D32 with optional double-precision
// and NEON SIMD instructions
features: "+vfp3,+neon".into(),
max_atomic_width: Some(64),
..base::thumb::opts()
},
}
}

View file

@ -435,6 +435,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
terr: TypeError<'tcx>,
param_env: Option<ParamEnv<'tcx>>,
path: &mut Option<PathBuf>,
) {
match *cause.code() {
ObligationCauseCode::Pattern {
@ -457,6 +458,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
format!("this is an iterator with items of type `{}`", args.type_at(0)),
);
} else {
let expected_ty = self.tcx.short_ty_string(expected_ty, path);
err.span_label(span, format!("this expression has type `{expected_ty}`"));
}
}
@ -717,53 +719,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
value: &mut DiagStyledString,
other_value: &mut DiagStyledString,
name: String,
sub: ty::GenericArgsRef<'tcx>,
args: &[ty::GenericArg<'tcx>],
pos: usize,
other_ty: Ty<'tcx>,
) {
// `value` and `other_value` hold two incomplete type representation for display.
// `name` is the path of both types being compared. `sub`
value.push_highlighted(name);
let len = sub.len();
if len > 0 {
value.push_highlighted("<");
if args.is_empty() {
return;
}
value.push_highlighted("<");
// Output the lifetimes for the first type
let lifetimes = sub
.regions()
.map(|lifetime| {
let s = lifetime.to_string();
if s.is_empty() { "'_".to_string() } else { s }
})
.collect::<Vec<_>>()
.join(", ");
if !lifetimes.is_empty() {
if sub.regions().count() < len {
value.push_normal(lifetimes + ", ");
} else {
value.push_normal(lifetimes);
}
}
// Highlight all the type arguments that aren't at `pos` and compare the type argument at
// `pos` and `other_ty`.
for (i, type_arg) in sub.types().enumerate() {
if i == pos {
let values = self.cmp(type_arg, other_ty);
value.0.extend((values.0).0);
other_value.0.extend((values.1).0);
} else {
value.push_highlighted(type_arg.to_string());
}
if len > 0 && i != len - 1 {
for (i, arg) in args.iter().enumerate() {
if i > 0 {
value.push_normal(", ");
}
match arg.unpack() {
ty::GenericArgKind::Lifetime(lt) => {
let s = lt.to_string();
value.push_normal(if s.is_empty() { "'_" } else { &s });
}
ty::GenericArgKind::Const(ct) => {
value.push_normal(ct.to_string());
}
// Highlight all the type arguments that aren't at `pos` and compare
// the type argument at `pos` and `other_ty`.
ty::GenericArgKind::Type(type_arg) => {
if i == pos {
let values = self.cmp(type_arg, other_ty);
value.0.extend((values.0).0);
other_value.0.extend((values.1).0);
} else {
value.push_highlighted(type_arg.to_string());
}
}
}
}
if len > 0 {
value.push_highlighted(">");
}
value.push_highlighted(">");
}
/// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`,
@ -791,27 +787,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
t1_out: &mut DiagStyledString,
t2_out: &mut DiagStyledString,
path: String,
sub: &'tcx [ty::GenericArg<'tcx>],
args: &'tcx [ty::GenericArg<'tcx>],
other_path: String,
other_ty: Ty<'tcx>,
) -> Option<()> {
// FIXME/HACK: Go back to `GenericArgsRef` to use its inherent methods,
// ideally that shouldn't be necessary.
let sub = self.tcx.mk_args(sub);
for (i, ta) in sub.types().enumerate() {
if ta == other_ty {
self.highlight_outer(t1_out, t2_out, path, sub, i, other_ty);
return Some(());
}
if let ty::Adt(def, _) = ta.kind() {
let path_ = self.tcx.def_path_str(def.did());
if path_ == other_path {
self.highlight_outer(t1_out, t2_out, path, sub, i, other_ty);
return Some(());
) -> bool {
for (i, arg) in args.iter().enumerate() {
if let Some(ta) = arg.as_type() {
if ta == other_ty {
self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
return true;
}
if let ty::Adt(def, _) = ta.kind() {
let path_ = self.tcx.def_path_str(def.did());
if path_ == other_path {
self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
return true;
}
}
}
}
None
false
}
/// Adds a `,` to the type representation only if it is appropriate.
@ -819,10 +814,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&self,
value: &mut DiagStyledString,
other_value: &mut DiagStyledString,
len: usize,
pos: usize,
) {
if len > 0 && pos != len - 1 {
if pos > 0 {
value.push_normal(", ");
other_value.push_normal(", ");
}
@ -899,10 +893,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let len2 = sig2.inputs().len();
if len1 == len2 {
for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() {
self.push_comma(&mut values.0, &mut values.1, i);
let (x1, x2) = self.cmp(*l, *r);
(values.0).0.extend(x1.0);
(values.1).0.extend(x2.0);
self.push_comma(&mut values.0, &mut values.1, len1, i);
}
} else {
for (i, l) in sig1.inputs().iter().enumerate() {
@ -1150,14 +1144,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let len1 = sub_no_defaults_1.len();
let len2 = sub_no_defaults_2.len();
let common_len = cmp::min(len1, len2);
let remainder1: Vec<_> = sub1.types().skip(common_len).collect();
let remainder2: Vec<_> = sub2.types().skip(common_len).collect();
let remainder1 = &sub1[common_len..];
let remainder2 = &sub2[common_len..];
let common_default_params =
iter::zip(remainder1.iter().rev(), remainder2.iter().rev())
.filter(|(a, b)| a == b)
.count();
let len = sub1.len() - common_default_params;
let consts_offset = len - sub1.consts().count();
// Only draw `<...>` if there are lifetime/type arguments.
if len > 0 {
@ -1169,70 +1162,68 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let s = lifetime.to_string();
if s.is_empty() { "'_".to_string() } else { s }
}
// At one point we'd like to elide all lifetimes here, they are irrelevant for
// all diagnostics that use this output
//
// Foo<'x, '_, Bar>
// Foo<'y, '_, Qux>
// ^^ ^^ --- type arguments are not elided
// | |
// | elided as they were the same
// not elided, they were different, but irrelevant
//
// For bound lifetimes, keep the names of the lifetimes,
// even if they are the same so that it's clear what's happening
// if we have something like
//
// for<'r, 's> fn(Inv<'r>, Inv<'s>)
// for<'r> fn(Inv<'r>, Inv<'r>)
let lifetimes = sub1.regions().zip(sub2.regions());
for (i, lifetimes) in lifetimes.enumerate() {
let l1 = lifetime_display(lifetimes.0);
let l2 = lifetime_display(lifetimes.1);
if lifetimes.0 != lifetimes.1 {
values.0.push_highlighted(l1);
values.1.push_highlighted(l2);
} else if lifetimes.0.is_bound() || self.tcx.sess.opts.verbose {
values.0.push_normal(l1);
values.1.push_normal(l2);
} else {
values.0.push_normal("'_");
values.1.push_normal("'_");
}
self.push_comma(&mut values.0, &mut values.1, len, i);
}
// We're comparing two types with the same path, so we compare the type
// arguments for both. If they are the same, do not highlight and elide from the
// output.
// Foo<_, Bar>
// Foo<_, Qux>
// ^ elided type as this type argument was the same in both sides
let type_arguments = sub1.types().zip(sub2.types());
let regions_len = sub1.regions().count();
let num_display_types = consts_offset - regions_len;
for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() {
let i = i + regions_len;
if ta1 == ta2 && !self.tcx.sess.opts.verbose {
values.0.push_normal("_");
values.1.push_normal("_");
} else {
recurse(ta1, ta2, &mut values);
}
self.push_comma(&mut values.0, &mut values.1, len, i);
}
for (i, (arg1, arg2)) in sub1.iter().zip(sub2).enumerate().take(len) {
self.push_comma(&mut values.0, &mut values.1, i);
match arg1.unpack() {
// At one point we'd like to elide all lifetimes here, they are
// irrelevant for all diagnostics that use this output.
//
// Foo<'x, '_, Bar>
// Foo<'y, '_, Qux>
// ^^ ^^ --- type arguments are not elided
// | |
// | elided as they were the same
// not elided, they were different, but irrelevant
//
// For bound lifetimes, keep the names of the lifetimes,
// even if they are the same so that it's clear what's happening
// if we have something like
//
// for<'r, 's> fn(Inv<'r>, Inv<'s>)
// for<'r> fn(Inv<'r>, Inv<'r>)
ty::GenericArgKind::Lifetime(l1) => {
let l1_str = lifetime_display(l1);
let l2 = arg2.expect_region();
let l2_str = lifetime_display(l2);
if l1 != l2 {
values.0.push_highlighted(l1_str);
values.1.push_highlighted(l2_str);
} else if l1.is_bound() || self.tcx.sess.opts.verbose {
values.0.push_normal(l1_str);
values.1.push_normal(l2_str);
} else {
values.0.push_normal("'_");
values.1.push_normal("'_");
}
}
ty::GenericArgKind::Type(ta1) => {
let ta2 = arg2.expect_ty();
if ta1 == ta2 && !self.tcx.sess.opts.verbose {
values.0.push_normal("_");
values.1.push_normal("_");
} else {
recurse(ta1, ta2, &mut values);
}
}
// We're comparing two types with the same path, so we compare the type
// arguments for both. If they are the same, do not highlight and elide
// from the output.
// Foo<_, Bar>
// Foo<_, Qux>
// ^ elided type as this type argument was the same in both sides
// Do the same for const arguments, if they are equal, do not highlight and
// elide them from the output.
let const_arguments = sub1.consts().zip(sub2.consts());
for (i, (ca1, ca2)) in const_arguments.enumerate() {
let i = i + consts_offset;
maybe_highlight(ca1, ca2, &mut values, self.tcx);
self.push_comma(&mut values.0, &mut values.1, len, i);
// Do the same for const arguments, if they are equal, do not highlight and
// elide them from the output.
ty::GenericArgKind::Const(ca1) => {
let ca2 = arg2.expect_const();
maybe_highlight(ca1, ca2, &mut values, self.tcx);
}
}
}
// Close the type argument bracket.
// Only draw `<...>` if there are lifetime/type arguments.
// Only draw `<...>` if there are arguments.
if len > 0 {
values.0.push_normal(">");
values.1.push_normal(">");
@ -1244,17 +1235,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// Foo<Bar<Qux>
// ------- this type argument is exactly the same as the other type
// Bar<Qux>
if self
.cmp_type_arg(
&mut values.0,
&mut values.1,
path1.clone(),
sub_no_defaults_1,
path2.clone(),
t2,
)
.is_some()
{
if self.cmp_type_arg(
&mut values.0,
&mut values.1,
path1.clone(),
sub_no_defaults_1,
path2.clone(),
t2,
) {
return values;
}
// Check for case:
@ -1262,17 +1250,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// Bar<Qux>
// Foo<Bar<Qux>>
// ------- this type argument is exactly the same as the other type
if self
.cmp_type_arg(
&mut values.1,
&mut values.0,
path2,
sub_no_defaults_2,
path1,
t1,
)
.is_some()
{
if self.cmp_type_arg(
&mut values.1,
&mut values.0,
path2,
sub_no_defaults_2,
path1,
t1,
) {
return values;
}
@ -1343,8 +1328,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut values = (DiagStyledString::normal("("), DiagStyledString::normal("("));
let len = args1.len();
for (i, (left, right)) in args1.iter().zip(args2).enumerate() {
self.push_comma(&mut values.0, &mut values.1, i);
recurse(left, right, &mut values);
self.push_comma(&mut values.0, &mut values.1, len, i);
}
if len == 1 {
// Keep the output for single element tuples as `(ty,)`.
@ -1611,7 +1596,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return;
}
if let Some((expected, found, path)) = expected_found {
let mut path = None;
if let Some((expected, found, p)) = expected_found {
path = p;
let (expected_label, found_label, exp_found) = match exp_found {
Mismatch::Variable(ef) => (
ef.expected.prefix_string(self.tcx),
@ -1792,13 +1779,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&sort_string(values.expected),
&sort_string(values.found),
);
if let Some(path) = path {
diag.note(format!(
"the full type name has been written to '{}'",
path.display(),
));
diag.note("consider using `--verbose` to print the full type name to the console");
}
}
}
}
@ -1894,7 +1874,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// It reads better to have the error origin as the final
// thing.
self.note_error_origin(diag, cause, exp_found, terr, param_env);
self.note_error_origin(diag, cause, exp_found, terr, param_env, &mut path);
if let Some(path) = path {
diag.note(format!("the full type name has been written to '{}'", path.display()));
diag.note("consider using `--verbose` to print the full type name to the console");
}
debug!(?diag);
}

View file

@ -1,8 +1,8 @@
use core::ops::ControlFlow;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
use rustc_hir::{self as hir, AmbigArg};
use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_bound_vars as rbv;
@ -48,7 +48,7 @@ fn find_component_for_bound_region<'tcx>(
region_def_id: DefId,
) -> Option<&'tcx hir::Ty<'tcx>> {
FindNestedTypeVisitor { tcx, region_def_id, current_index: ty::INNERMOST }
.visit_ty(arg)
.visit_ty_unambig(arg)
.break_value()
}
@ -74,7 +74,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
self.tcx.hir()
}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
match arg.kind {
hir::TyKind::BareFn(_) => {
self.current_index.shift_in(1);
@ -101,7 +101,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
Some(rbv::ResolvedArg::EarlyBound(id)) => {
debug!("EarlyBound id={:?}", id);
if id.to_def_id() == self.region_def_id {
return ControlFlow::Break(arg);
return ControlFlow::Break(arg.as_unambig_ty());
}
}
@ -117,7 +117,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
if debruijn_index == self.current_index
&& id.to_def_id() == self.region_def_id
{
return ControlFlow::Break(arg);
return ControlFlow::Break(arg.as_unambig_ty());
}
}
@ -147,7 +147,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
)
.is_break()
{
ControlFlow::Break(arg)
ControlFlow::Break(arg.as_unambig_ty())
} else {
ControlFlow::Continue(())
};
@ -210,7 +210,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
ControlFlow::Continue(())
}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
// ignore nested types
//
// If you have a type like `Foo<'a, &Ty>` we

View file

@ -4,7 +4,7 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::VisitorExt;
use rustc_middle::bug;
use rustc_middle::ty::TypeVisitor;
use tracing::debug;
@ -87,7 +87,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
for matching_def_id in v.0 {
let mut hir_v =
super::static_impl_trait::HirTraitObjectVisitor(&mut traits, matching_def_id);
hir_v.visit_ty(impl_self_ty);
hir_v.visit_ty_unambig(impl_self_ty);
}
if traits.is_empty() {

View file

@ -3,9 +3,9 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, Subdiagnostic};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
use rustc_hir::{
self as hir, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime,
self as hir, AmbigArg, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime,
LifetimeName, LifetimeParamKind, MissingLifetimeKind, Node, TyKind,
};
use rustc_middle::ty::{
@ -153,7 +153,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let mut add_label = true;
if let hir::FnRetTy::Return(ty) = fn_decl.output {
let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
v.visit_ty(ty);
v.visit_ty_unambig(ty);
if !v.0.is_empty() {
span = v.0.clone().into();
spans = v.0;
@ -374,7 +374,7 @@ pub fn suggest_new_region_bound(
}
}
}
TyKind::TraitObject(_, lt, _) => {
TyKind::TraitObject(_, lt) => {
if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
@ -500,7 +500,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// In that case, only the first one will get suggestions.
let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
hir_v.visit_ty(self_ty);
hir_v.visit_ty_unambig(self_ty);
!traits.is_empty()
})
{
@ -560,7 +560,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
for found_did in found_dids {
let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
hir_v.visit_ty(self_ty);
hir_v.visit_ty_unambig(self_ty);
for &span in &traits {
let subdiag = DynTraitConstraintSuggestion { span, ident };
subdiag.add_to_diag(err);
@ -591,12 +591,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for TraitObjectVisitor {
pub struct HirTraitObjectVisitor<'a>(pub &'a mut Vec<Span>, pub DefId);
impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
if let TyKind::TraitObject(
poly_trait_refs,
Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. },
_,
) = t.kind
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) {
if let TyKind::TraitObject(poly_trait_refs, lifetime_ptr) = t.kind
&& let Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. } =
lifetime_ptr.pointer()
{
for ptr in poly_trait_refs {
if Some(self.1) == ptr.trait_ref.trait_def_id() {

View file

@ -1,10 +1,10 @@
//! Error Reporting for `impl` items that do not match the obligations from their `trait`.
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::{self as hir, AmbigArg};
use rustc_middle::hir::nested_filter;
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::ExpectedFound;
@ -137,11 +137,13 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
self.tcx.hir()
}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
match arg.kind {
hir::TyKind::Ref(_, ref mut_ty) => {
// We don't want to suggest looking into borrowing `&T` or `&Self`.
hir::intravisit::walk_ty(self, mut_ty.ty);
if let Some(ambig_ty) = mut_ty.ty.try_as_ambig_ty() {
walk_ty(self, ambig_ty);
}
return;
}
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {

View file

@ -655,7 +655,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& let ty::Ref(found_region, _, _) = found.kind()
&& expected_region.is_bound()
&& !found_region.is_bound()
&& let hir::TyKind::Infer = arg_hir.kind
&& let hir::TyKind::Infer(()) = arg_hir.kind
{
// If the expected region is late bound, the found region is not, and users are asking compiler
// to infer the type, we can suggest adding `: &_`.

View file

@ -580,8 +580,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
self.tcx.hir_node_by_def_id(obligation.cause.body_id)
&& let hir::ItemKind::Impl(impl_) = item.kind
&& let None = impl_.of_trait
&& let hir::TyKind::TraitObject(_, _, syntax) = impl_.self_ty.kind
&& let TraitObjectSyntax::None = syntax
&& let hir::TyKind::TraitObject(_, tagged_ptr) = impl_.self_ty.kind
&& let TraitObjectSyntax::None = tagged_ptr.tag()
&& impl_.self_ty.span.edition().at_least_rust_2021()
{
// Silence the dyn-compatibility error in favor of the missing dyn on

View file

@ -11,7 +11,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{self as hir, LangItem};
use rustc_hir::{self as hir, AmbigArg, LangItem};
use rustc_infer::traits::{
DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
PredicateObligation, SelectionError,
@ -87,9 +87,9 @@ impl<'v> Visitor<'v> for FindExprBySpan<'v> {
}
}
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
if self.span == ty.span {
self.ty_result = Some(ty);
self.ty_result = Some(ty.as_unambig_ty());
} else {
hir::intravisit::walk_ty(self, ty);
}

View file

@ -14,14 +14,13 @@ use rustc_errors::{
Applicability, Diag, EmissionGuarantee, MultiSpan, Style, SuggestionStyle, pluralize,
struct_span_code_err,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::intravisit::{Visitor, VisitorExt};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node, expr_needs_parens,
is_range_literal,
self as hir, AmbigArg, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node,
expr_needs_parens, is_range_literal,
};
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};
use rustc_middle::hir::map;
@ -179,7 +178,7 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
let mut ty_spans = vec![];
for input in fn_sig.decl.inputs {
ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id }
.visit_ty(input);
.visit_ty_unambig(input);
}
// The type param `T: Trait` we will suggest to introduce.
let type_param = format!("{type_param_name}: {bound_str}");
@ -3074,7 +3073,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
if let Some(ty) = ty {
match ty.kind {
hir::TyKind::TraitObject(traits, _, _) => {
hir::TyKind::TraitObject(traits, _) => {
let (span, kw) = match traits {
[first, ..] if first.span.lo() == ty.span.lo() => {
// Missing `dyn` in front of trait object.
@ -5065,7 +5064,7 @@ pub struct SelfVisitor<'v> {
}
impl<'v> Visitor<'v> for SelfVisitor<'v> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
if let hir::TyKind::Path(path) = ty.kind
&& let hir::QPath::TypeRelative(inner_ty, segment) = path
&& (Some(segment.ident.name) == self.name || self.name.is_none())
@ -5073,7 +5072,7 @@ impl<'v> Visitor<'v> for SelfVisitor<'v> {
&& let hir::QPath::Resolved(None, inner_path) = inner_path
&& let Res::SelfTyAlias { .. } = inner_path.res
{
self.paths.push(ty);
self.paths.push(ty.as_unambig_ty());
}
hir::intravisit::walk_ty(self, ty);
}
@ -5187,7 +5186,7 @@ struct ReplaceImplTraitVisitor<'a> {
}
impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) {
fn visit_ty(&mut self, t: &'hir hir::Ty<'hir, AmbigArg>) {
if let hir::TyKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: Res::Def(_, segment_did), .. },
@ -5480,7 +5479,7 @@ impl<'v> Visitor<'v> for FindTypeParam {
// Skip where-clauses, to avoid suggesting indirection for type parameters found there.
}
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
fn visit_ty(&mut self, ty: &hir::Ty<'_, AmbigArg>) {
// We collect the spans of all uses of the "bare" type param, like in `field: T` or
// `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
// valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`

View file

@ -6,11 +6,10 @@ use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::{FnRetTy, GenericParamKind, Node};
use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, TyCtxt};
@ -579,7 +578,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
}
impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
let make_suggestion = |ident: Ident| {
if ident.name == kw::Empty && ident.span.is_empty() {
format!("{}, ", self.suggestion_param_name)
@ -642,16 +641,16 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
if let Some(fn_decl) = node.fn_decl()
&& let hir::FnRetTy::Return(ty) = fn_decl.output
{
visitor.visit_ty(ty);
visitor.visit_ty_unambig(ty);
}
if visitor.suggestions.is_empty() {
// Do not suggest constraining the `&self` param, but rather the return type.
// If that is wrong (because it is not sufficient), a follow up error will tell the
// user to fix it. This way we lower the chances of *over* constraining, but still
// get the cake of "correctly" contrained in two steps.
visitor.visit_ty(self.ty_sup);
visitor.visit_ty_unambig(self.ty_sup);
}
visitor.visit_ty(self.ty_sub);
visitor.visit_ty_unambig(self.ty_sub);
if visitor.suggestions.is_empty() {
return false;
}

View file

@ -6,8 +6,7 @@ use rustc_span::{DUMMY_SP, Span};
use tracing::{debug, instrument};
use crate::traits::query::NoSolution;
use crate::traits::query::normalize::QueryNormalizeExt;
use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
use crate::traits::{ObligationCause, ObligationCtxt};
/// This returns true if the type `ty` is "trivial" for
/// dropck-outlives -- that is, if it doesn't require any types to
@ -172,13 +171,18 @@ pub fn compute_dropck_outlives_inner<'tcx>(
// do not themselves define a destructor", more or less. We have
// to push them onto the stack to be expanded.
for ty in constraints.dtorck_types.drain(..) {
let Normalized { value: ty, obligations } =
ocx.infcx.at(&cause, param_env).query_normalize(ty)?;
ocx.register_obligations(obligations);
let normalized_ty = ocx.normalize(&cause, param_env, ty);
debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
let errors = ocx.select_where_possible();
if !errors.is_empty() {
debug!("failed to normalize dtorck type: {ty} ~> {errors:#?}");
return Err(NoSolution);
}
match ty.kind() {
let normalized_ty = ocx.infcx.resolve_vars_if_possible(normalized_ty);
debug!("dropck_outlives: ty from dtorck_types = {:?}", normalized_ty);
match normalized_ty.kind() {
// All parameters live for the duration of the
// function.
ty::Param(..) => {}
@ -186,12 +190,12 @@ pub fn compute_dropck_outlives_inner<'tcx>(
// A projection that we couldn't resolve - it
// might have a destructor.
ty::Alias(..) => {
result.kinds.push(ty.into());
result.kinds.push(normalized_ty.into());
}
_ => {
if ty_set.insert(ty) {
ty_stack.push((ty, depth + 1));
if ty_set.insert(normalized_ty) {
ty_stack.push((normalized_ty, depth + 1));
}
}
}

View file

@ -6,13 +6,12 @@ use rustc_middle::query::Providers;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::{Clause, FnSig, ParamEnvAnd, PolyFnSig, Ty, TyCtxt, TypeFoldable};
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{
AscribeUserType, type_op_ascribe_user_type_with_span,
};
use rustc_trait_selection::traits::query::type_op::normalize::Normalize;
use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate;
use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
pub(crate) fn provide(p: &mut Providers) {
*p = Providers {
@ -43,10 +42,7 @@ where
T: fmt::Debug + TypeFoldable<TyCtxt<'tcx>>,
{
let (param_env, Normalize { value }) = key.into_parts();
let Normalized { value, obligations } =
ocx.infcx.at(&ObligationCause::dummy(), param_env).query_normalize(value)?;
ocx.register_obligations(obligations);
Ok(value)
Ok(ocx.normalize(&ObligationCause::dummy(), param_env, value))
}
fn type_op_normalize_ty<'tcx>(

View file

@ -1,8 +1,8 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self as hir, AmbigArg};
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
use rustc_middle::{bug, span_bug};
@ -187,7 +187,7 @@ fn associated_types_for_impl_traits_in_associated_fn(
}
impl<'tcx> Visitor<'tcx> for RPITVisitor {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
if let hir::TyKind::OpaqueDef(opaq) = ty.kind
&& self.rpits.insert(opaq.def_id)
{

View file

@ -1735,6 +1735,52 @@ impl<T, A: Allocator> VecDeque<T, A> {
}
}
/// Removes and returns the first element from the deque if the predicate
/// returns `true`, or [`None`] if the predicate returns false or the deque
/// is empty (the predicate will not be called in that case).
///
/// # Examples
///
/// ```
/// #![feature(vec_deque_pop_if)]
/// use std::collections::VecDeque;
///
/// let mut deque: VecDeque<i32> = vec![0, 1, 2, 3, 4].into();
/// let pred = |x: &mut i32| *x % 2 == 0;
///
/// assert_eq!(deque.pop_front_if(pred), Some(0));
/// assert_eq!(deque, [1, 2, 3, 4]);
/// assert_eq!(deque.pop_front_if(pred), None);
/// ```
#[unstable(feature = "vec_deque_pop_if", issue = "135889")]
pub fn pop_front_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T> {
let first = self.front_mut()?;
if predicate(first) { self.pop_front() } else { None }
}
/// Removes and returns the last element from the deque if the predicate
/// returns `true`, or [`None`] if the predicate returns false or the deque
/// is empty (the predicate will not be called in that case).
///
/// # Examples
///
/// ```
/// #![feature(vec_deque_pop_if)]
/// use std::collections::VecDeque;
///
/// let mut deque: VecDeque<i32> = vec![0, 1, 2, 3, 4].into();
/// let pred = |x: &mut i32| *x % 2 == 0;
///
/// assert_eq!(deque.pop_back_if(pred), Some(4));
/// assert_eq!(deque, [0, 1, 2, 3]);
/// assert_eq!(deque.pop_back_if(pred), None);
/// ```
#[unstable(feature = "vec_deque_pop_if", issue = "135889")]
pub fn pop_back_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T> {
let first = self.back_mut()?;
if predicate(first) { self.pop_back() } else { None }
}
/// Prepends an element to the deque.
///
/// # Examples

View file

@ -2511,9 +2511,9 @@ impl<T, A: Allocator> Vec<T, A> {
}
}
/// Removes and returns the last element in a vector if the predicate
/// Removes and returns the last element from a vector if the predicate
/// returns `true`, or [`None`] if the predicate returns false or the vector
/// is empty.
/// is empty (the predicate will not be called in that case).
///
/// # Examples
///
@ -2528,12 +2528,9 @@ impl<T, A: Allocator> Vec<T, A> {
/// assert_eq!(vec.pop_if(pred), None);
/// ```
#[unstable(feature = "vec_pop_if", issue = "122741")]
pub fn pop_if<F>(&mut self, f: F) -> Option<T>
where
F: FnOnce(&mut T) -> bool,
{
pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T> {
let last = self.last_mut()?;
if f(last) { self.pop() } else { None }
if predicate(last) { self.pop() } else { None }
}
/// Moves all the elements of `other` into `self`, leaving `other` empty.
@ -2574,9 +2571,11 @@ impl<T, A: Allocator> Vec<T, A> {
self.len += count;
}
/// Removes the specified range from the vector in bulk, returning all
/// removed elements as an iterator. If the iterator is dropped before
/// being fully consumed, it drops the remaining removed elements.
/// Removes the subslice indicated by the given range from the vector,
/// returning a double-ended iterator over the removed subslice.
///
/// If the iterator is dropped before being fully consumed,
/// it drops the remaining removed elements.
///
/// The returned iterator keeps a mutable borrow on the vector to optimize
/// its implementation.
@ -3016,10 +3015,9 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
/// Iterates over the slice `other`, clones each element, and then appends
/// it to this `Vec`. The `other` slice is traversed in-order.
///
/// Note that this function is same as [`extend`] except that it is
/// specialized to work with slices instead. If and when Rust gets
/// specialization this function will likely be deprecated (but still
/// available).
/// Note that this function is the same as [`extend`],
/// except that it also works with slice elements that are Clone but not Copy.
/// If Rust gets specialization this function may be deprecated.
///
/// # Examples
///

View file

@ -38,6 +38,7 @@
#![feature(str_as_str)]
#![feature(strict_provenance_lints)]
#![feature(vec_pop_if)]
#![feature(vec_deque_pop_if)]
#![feature(unique_rc_arc)]
#![feature(macro_metavar_expr_concat)]
#![allow(internal_features)]

View file

@ -80,6 +80,45 @@ fn test_parameterized<T: Clone + PartialEq + Debug>(a: T, b: T, c: T, d: T) {
assert_eq!(deq[3].clone(), d.clone());
}
#[test]
fn test_pop_if() {
let mut deq: VecDeque<_> = vec![0, 1, 2, 3, 4].into();
let pred = |x: &mut i32| *x % 2 == 0;
assert_eq!(deq.pop_front_if(pred), Some(0));
assert_eq!(deq, [1, 2, 3, 4]);
assert_eq!(deq.pop_front_if(pred), None);
assert_eq!(deq, [1, 2, 3, 4]);
assert_eq!(deq.pop_back_if(pred), Some(4));
assert_eq!(deq, [1, 2, 3]);
assert_eq!(deq.pop_back_if(pred), None);
assert_eq!(deq, [1, 2, 3]);
}
#[test]
fn test_pop_if_empty() {
let mut deq = VecDeque::<i32>::new();
assert_eq!(deq.pop_front_if(|_| true), None);
assert_eq!(deq.pop_back_if(|_| true), None);
assert!(deq.is_empty());
}
#[test]
fn test_pop_if_mutates() {
let mut v: VecDeque<_> = vec![-1, 1].into();
let pred = |x: &mut i32| {
*x *= 2;
false
};
assert_eq!(v.pop_front_if(pred), None);
assert_eq!(v, [-2, 1]);
assert_eq!(v.pop_back_if(pred), None);
assert_eq!(v, [-2, 2]);
}
#[test]
fn test_push_front_grow() {
let mut deq = VecDeque::new();

View file

@ -156,7 +156,6 @@ pub const fn from_mut<T>(s: &mut T) -> &mut [T; 1] {
/// The error type returned when a conversion from a slice to an array fails.
#[stable(feature = "try_from", since = "1.34.0")]
#[rustc_allowed_through_unstable_modules]
#[derive(Debug, Copy, Clone)]
pub struct TryFromSliceError(());

View file

@ -90,6 +90,26 @@ impl_zeroable_primitive!(
///
/// assert_eq!(size_of::<Option<NonZero<u32>>>(), size_of::<u32>());
/// ```
///
/// # Layout
///
/// `NonZero<T>` is guaranteed to have the same layout and bit validity as `T`
/// with the exception that the all-zero bit pattern is invalid.
/// `Option<NonZero<T>>` is guaranteed to be compatible with `T`, including in
/// FFI.
///
/// Thanks to the [null pointer optimization], `NonZero<T>` and
/// `Option<NonZero<T>>` are guaranteed to have the same size and alignment:
///
/// ```
/// # use std::mem::{size_of, align_of};
/// use std::num::NonZero;
///
/// assert_eq!(size_of::<NonZero<u32>>(), size_of::<Option<NonZero<u32>>>());
/// assert_eq!(align_of::<NonZero<u32>>(), align_of::<Option<NonZero<u32>>>());
/// ```
///
/// [null pointer optimization]: crate::option#representation
#[stable(feature = "generic_nonzero", since = "1.79.0")]
#[repr(transparent)]
#[rustc_nonnull_optimization_guaranteed]

View file

@ -156,8 +156,8 @@
//!
//! In order to implement the second option, we must in some way enforce its key invariant,
//! *i.e.* prevent the value from being *moved* or otherwise invalidated (you may notice this
//! sounds an awful lot like the definition of *pinning* a value). There a few ways one might be
//! able to enforce this invariant in Rust:
//! sounds an awful lot like the definition of *pinning* a value). There are a few ways one might
//! be able to enforce this invariant in Rust:
//!
//! 1. Offer a wholly `unsafe` API to interact with the object, thus requiring every caller to
//! uphold the invariant themselves

View file

@ -3,7 +3,7 @@
use std::marker::PhantomData;
#[repr(C)]
pub struct Closure<'a, A, R> {
pub(super) struct Closure<'a, A, R> {
call: unsafe extern "C" fn(*mut Env, A) -> R,
env: *mut Env,
// Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing
@ -26,7 +26,7 @@ impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> {
}
impl<'a, A, R> Closure<'a, A, R> {
pub fn call(&mut self, arg: A) -> R {
pub(super) fn call(&mut self, arg: A) -> R {
unsafe { (self.call)(self.env, arg) }
}
}

View file

@ -9,7 +9,7 @@ use std::hash::{BuildHasherDefault, Hasher};
use std::ops::BitXor;
/// Type alias for a hashmap using the `fx` hash algorithm.
pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
pub(super) type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
/// A speedy hash algorithm for use within rustc. The hashmap in alloc by
/// default uses SipHash which isn't quite as speedy as we want. In the compiler
@ -23,7 +23,7 @@ pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
/// similar or slightly worse than FNV, but the speed of the hash function
/// itself is much higher because it works on up to 8 bytes at a time.
#[derive(Default)]
pub struct FxHasher {
pub(super) struct FxHasher {
hash: usize,
}

View file

@ -67,7 +67,7 @@ macro_rules! rpc_encode_decode {
mod tag {
#[repr(u8)] enum Tag { $($variant),* }
$(pub const $variant: u8 = Tag::$variant as u8;)*
$(pub(crate) const $variant: u8 = Tag::$variant as u8;)*
}
match self {
@ -89,7 +89,7 @@ macro_rules! rpc_encode_decode {
mod tag {
#[repr(u8)] enum Tag { $($variant),* }
$(pub const $variant: u8 = Tag::$variant as u8;)*
$(pub(crate) const $variant: u8 = Tag::$variant as u8;)*
}
match u8::decode(r, s) {

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