diff options
Diffstat (limited to 'compiler')
111 files changed, 1614 insertions, 1124 deletions
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 157f46501e1..21c6a2d26f4 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -277,8 +277,9 @@ pub struct RegisterConflict<'a> { pub struct SubTupleBinding<'a> { #[primary_span] #[label] - #[suggestion_verbose( + #[suggestion( ast_lowering_sub_tuple_binding_suggestion, + style = "verbose", code = "..", applicability = "maybe-incorrect" )] diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 02071ed6b36..dac6abe37f5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -5,14 +5,14 @@ use rustc_infer::infer::region_constraints::Constraint; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::RegionVariableOrigin; use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _}; -use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt}; +use rustc_infer::traits::ObligationCause; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::RegionVid; use rustc_middle::ty::UniverseIndex; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op; -use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _}; +use rustc_trait_selection::traits::ObligationCtxt; use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; use std::fmt; @@ -240,9 +240,9 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { let (ref infcx, key, _) = mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); - type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) + let ocx = ObligationCtxt::new(infcx); + type_op_prove_predicate_with_cause(&ocx, key, cause); + try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region) } } @@ -281,9 +281,7 @@ where ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { let (ref infcx, key, _) = mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); - - let mut selcx = SelectionContext::new(infcx); + let ocx = ObligationCtxt::new(infcx); // FIXME(lqd): Unify and de-duplicate the following with the actual // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the @@ -292,11 +290,9 @@ where // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check // after #85499 lands to see if its fixes have erased this difference. let (param_env, value) = key.into_parts(); - let Normalized { value: _, obligations } = - rustc_trait_selection::traits::normalize(&mut selcx, param_env, cause, value.value); - fulfill_cx.register_predicate_obligations(infcx, obligations); + let _ = ocx.normalize(cause, param_env, value.value); - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) + try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region) } } @@ -329,9 +325,9 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { let (ref infcx, key, _) = mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); - type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)).ok()?; - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) + let ocx = ObligationCtxt::new(infcx); + type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?; + try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region) } } @@ -372,25 +368,24 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { } } -#[instrument(skip(fulfill_cx, infcx), level = "debug")] +#[instrument(skip(ocx), level = "debug")] fn try_extract_error_from_fulfill_cx<'tcx>( - mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>, - infcx: &InferCtxt<'tcx>, + ocx: &ObligationCtxt<'_, 'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { // We generally shouldn't have errors here because the query was // already run, but there's no point using `delay_span_bug` // when we're going to emit an error here anyway. - let _errors = fulfill_cx.select_all_or_error(infcx); - let region_constraints = infcx.with_region_constraints(|r| r.clone()); + let _errors = ocx.select_all_or_error(); + let region_constraints = ocx.infcx.with_region_constraints(|r| r.clone()); try_extract_error_from_region_constraints( - infcx, + ocx.infcx, placeholder_region, error_region, ®ion_constraints, - |vid| infcx.region_var_origin(vid), - |vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))), + |vid| ocx.infcx.region_var_origin(vid), + |vid| ocx.infcx.universe_of_region(ocx.infcx.tcx.mk_region(ty::ReVar(vid))), ) } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index cff3089c397..fe24f85fae1 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -49,7 +49,7 @@ pub(crate) struct GenericDoesNotLiveLongEnough { #[derive(LintDiagnostic)] #[diag(borrowck_var_does_not_need_mut)] pub(crate) struct VarNeedNotMut { - #[suggestion_short(applicability = "machine-applicable", code = "")] + #[suggestion(style = "short", applicability = "machine-applicable", code = "")] pub span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs new file mode 100644 index 00000000000..eaf1b1167cf --- /dev/null +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -0,0 +1,104 @@ +use crate::util::check_builtin_macro_attribute; + +use rustc_ast::ptr::P; +use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind}; +use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe}; +use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::Span; +use thin_vec::thin_vec; + +pub fn expand( + ecx: &mut ExtCtxt<'_>, + _span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec<Annotatable> { + check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler); + + let orig_item = item.clone(); + let not_function = || { + ecx.sess + .parse_sess + .span_diagnostic + .span_err(item.span(), "alloc_error_handler must be a function"); + vec![orig_item.clone()] + }; + + // Allow using `#[alloc_error_handler]` on an item statement + // FIXME - if we get deref patterns, use them to reduce duplication here + let (item, is_stmt, sig_span) = match &item { + Annotatable::Item(item) => match item.kind { + ItemKind::Fn(ref fn_kind) => (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)), + _ => return not_function(), + }, + Annotatable::Stmt(stmt) => match &stmt.kind { + StmtKind::Item(item_) => match item_.kind { + ItemKind::Fn(ref fn_kind) => { + (item_, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) + } + _ => return not_function(), + }, + _ => return not_function(), + }, + _ => return not_function(), + }; + + // Generate a bunch of new items using the AllocFnFactory + let span = ecx.with_def_site_ctxt(item.span); + + // Generate item statements for the allocator methods. + let stmts = vec![generate_handler(ecx, item.ident, span, sig_span)]; + + // Generate anonymous constant serving as container for the allocator methods. + let const_ty = ecx.ty(sig_span, TyKind::Tup(Vec::new())); + let const_body = ecx.expr_block(ecx.block(span, stmts)); + let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); + let const_item = if is_stmt { + Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) + } else { + Annotatable::Item(const_item) + }; + + // Return the original item and the new methods. + vec![orig_item, const_item] +} + +// #[rustc_std_internal_symbol] +// unsafe fn __rg_oom(size: usize, align: usize) -> ! { +// handler(core::alloc::Layout::from_size_align_unchecked(size, align)) +// } +fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt { + let usize = cx.path_ident(span, Ident::new(sym::usize, span)); + let ty_usize = cx.ty_path(usize); + let size = Ident::from_str_and_span("size", span); + let align = Ident::from_str_and_span("align", span); + + let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]); + let layout_new = cx.expr_path(cx.path(span, layout_new)); + let layout = + cx.expr_call(span, layout_new, vec![cx.expr_ident(span, size), cx.expr_ident(span, align)]); + + let call = cx.expr_call_ident(sig_span, handler, vec![layout]); + + let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never)); + let params = vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)]; + let decl = cx.fn_decl(params, never); + let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() }; + let sig = FnSig { decl, header, span: span }; + + let body = Some(cx.block_expr(call)); + let kind = ItemKind::Fn(Box::new(Fn { + defaultness: ast::Defaultness::Final, + sig, + generics: Generics::default(), + body, + })); + + let special = sym::rustc_std_internal_symbol; + let special = cx.meta_word(span, special); + let attrs = thin_vec![cx.attribute(special)]; + + let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind); + cx.stmt_item(sig_span, item) +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index c7ea7de8f4e..bde0102186a 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -25,6 +25,7 @@ use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; use rustc_span::symbol::sym; +mod alloc_error_handler; mod assert; mod cfg; mod cfg_accessible; @@ -94,6 +95,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { } register_attr! { + alloc_error_handler: alloc_error_handler::expand, bench: test::expand_bench, cfg_accessible: cfg_accessible::Expander, cfg_eval: cfg_eval::expand, diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index bad8a87b9be..12bb00d346d 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -5,6 +5,7 @@ use crate::prelude::*; use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; use rustc_session::config::OomStrategy; +use rustc_span::symbol::sym; /// Returns whether an allocator shim was created pub(crate) fn codegen( @@ -23,7 +24,7 @@ pub(crate) fn codegen( module, unwind_context, kind, - tcx.lang_items().oom().is_some(), + tcx.alloc_error_handler_kind(()).unwrap(), tcx.sess.opts.unstable_opts.oom, ); true @@ -36,7 +37,7 @@ fn codegen_inner( module: &mut impl Module, unwind_context: &mut UnwindContext, kind: AllocatorKind, - has_alloc_error_handler: bool, + alloc_error_handler_kind: AllocatorKind, oom_strategy: OomStrategy, ) { let usize_ty = module.target_config().pointer_type(); @@ -108,12 +109,12 @@ fn codegen_inner( returns: vec![], }; - let callee_name = if has_alloc_error_handler { "__rg_oom" } else { "__rdl_oom" }; + let callee_name = alloc_error_handler_kind.fn_name(sym::oom); let func_id = module.declare_function("__rust_alloc_error_handler", Linkage::Export, &sig).unwrap(); - let callee_func_id = module.declare_function(callee_name, Linkage::Import, &sig).unwrap(); + let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap(); let mut ctx = Context::new(); ctx.func.signature = sig; diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index 58efb81e800..e2c9ffe9c1c 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -7,7 +7,7 @@ use rustc_span::symbol::sym; use crate::GccContext; -pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) { +pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) { let context = &mods.context; let usize = match tcx.sess.target.pointer_width { @@ -90,14 +90,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam .collect(); let func = context.new_function(None, FunctionType::Exported, void, &args, name, false); - let kind = - if has_alloc_error_handler { - AllocatorKind::Global - } - else { - AllocatorKind::Default - }; - let callee = kind.fn_name(sym::oom); + let callee = alloc_error_handler_kind.fn_name(sym::oom); let args: Vec<_> = types.iter().enumerate() .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) .collect(); diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index accd02ab002..dd0daf2c38b 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -153,11 +153,11 @@ impl CodegenBackend for GccCodegenBackend { } impl ExtraBackendMethods for GccCodegenBackend { - fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) -> Self::Module { + fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module { let mut mods = GccContext { context: Context::default(), }; - unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); } + unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); } mods } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 72961ae888e..fed56cdd438 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -15,7 +15,7 @@ pub(crate) unsafe fn codegen( module_llvm: &mut ModuleLlvm, module_name: &str, kind: AllocatorKind, - has_alloc_error_handler: bool, + alloc_error_handler_kind: AllocatorKind, ) { let llcx = &*module_llvm.llcx; let llmod = module_llvm.llmod(); @@ -117,8 +117,7 @@ pub(crate) unsafe fn codegen( attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); } - let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default }; - let callee = kind.fn_name(sym::oom); + let callee = alloc_error_handler_kind.fn_name(sym::oom); let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty); // -> ! DIFlagNoReturn attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index fca43a0d86d..9cb36ce7f18 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -365,11 +365,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { Int(I64) => "llvm.ssub.with.overflow.i64", Int(I128) => "llvm.ssub.with.overflow.i128", - Uint(U8) => "llvm.usub.with.overflow.i8", - Uint(U16) => "llvm.usub.with.overflow.i16", - Uint(U32) => "llvm.usub.with.overflow.i32", - Uint(U64) => "llvm.usub.with.overflow.i64", - Uint(U128) => "llvm.usub.with.overflow.i128", + Uint(_) => { + // Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these + // to be the canonical form. It will attempt to reform llvm.usub.with.overflow + // in the backend if profitable. + let sub = self.sub(lhs, rhs); + let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs); + return (sub, cmp); + } _ => unreachable!(), }, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 89c7e51d09e..d51aced85df 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -108,11 +108,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend { tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, - has_alloc_error_handler: bool, + alloc_error_handler_kind: AllocatorKind, ) -> ModuleLlvm { let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name); unsafe { - allocator::codegen(tcx, &mut module_llvm, module_name, kind, has_alloc_error_handler); + allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind); } module_llvm } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index c2ecc41601c..752f6b1ef40 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -193,8 +193,11 @@ fn exported_symbols_provider_local<'tcx>( } if tcx.allocator_kind(()).is_some() { - for method in ALLOCATOR_METHODS { - let symbol_name = format!("__rust_{}", method.name); + for symbol_name in ALLOCATOR_METHODS + .iter() + .map(|method| format!("__rust_{}", method.name)) + .chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()]) + { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); symbols.push(( diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 84b89cd71a6..c1411690f82 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -22,7 +22,6 @@ use rustc_data_structures::sync::ParallelIterator; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; -use rustc_hir::weak_lang_items::WEAK_ITEMS_SYMBOLS; use rustc_index::vec::Idx; use rustc_metadata::EncodedMetadata; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -639,7 +638,14 @@ pub fn codegen_crate<B: ExtraBackendMethods>( let llmod_id = cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); let module_llvm = tcx.sess.time("write_allocator_module", || { - backend.codegen_allocator(tcx, &llmod_id, kind, tcx.lang_items().oom().is_some()) + backend.codegen_allocator( + tcx, + &llmod_id, + kind, + // If allocator_kind is Some then alloc_error_handler_kind must + // also be Some. + tcx.alloc_error_handler_kind(()).unwrap(), + ) }); Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator }) @@ -887,14 +893,14 @@ impl CrateInfo { // by the compiler, but that's ok because all this stuff is unstable anyway. let target = &tcx.sess.target; if !are_upstream_rust_objects_already_included(tcx.sess) { - let missing_weak_lang_items: FxHashSet<&Symbol> = info + let missing_weak_lang_items: FxHashSet<Symbol> = info .used_crates .iter() - .flat_map(|cnum| { - tcx.missing_lang_items(*cnum) - .iter() - .filter(|l| lang_items::required(tcx, **l)) - .filter_map(|item| WEAK_ITEMS_SYMBOLS.get(item)) + .flat_map(|&cnum| tcx.missing_lang_items(cnum)) + .filter(|l| l.is_weak()) + .filter_map(|&l| { + let name = l.link_name()?; + lang_items::required(tcx, l).then_some(name) }) .collect(); let prefix = if target.is_like_windows && target.arch == "x86" { "_" } else { "" }; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 29b7c9b0a88..0802067cde6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -17,6 +17,7 @@ use rustc_middle::mir::{self, AssertKind, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty, TypeVisitable}; +use rustc_session::config::OptLevel; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; use rustc_symbol_mangling::typeid::typeid_for_fnabi; @@ -286,12 +287,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { assert_eq!(discr.layout.ty, switch_ty); let mut target_iter = targets.iter(); if target_iter.len() == 1 { - // If there are two targets (one conditional, one fallback), emit br instead of switch + // If there are two targets (one conditional, one fallback), emit `br` instead of + // `switch`. let (test_value, target) = target_iter.next().unwrap(); let lltrue = helper.llbb_with_cleanup(self, target); let llfalse = helper.llbb_with_cleanup(self, targets.otherwise()); if switch_ty == bx.tcx().types.bool { - // Don't generate trivial icmps when switching on bool + // Don't generate trivial icmps when switching on bool. match test_value { 0 => bx.cond_br(discr.immediate(), llfalse, lltrue), 1 => bx.cond_br(discr.immediate(), lltrue, llfalse), @@ -303,6 +305,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval); bx.cond_br(cmp, lltrue, llfalse); } + } else if self.cx.sess().opts.optimize == OptLevel::No + && target_iter.len() == 2 + && self.mir[targets.otherwise()].is_empty_unreachable() + { + // In unoptimized builds, if there are two normal targets and the `otherwise` target is + // an unreachable BB, emit `br` instead of `switch`. This leaves behind the unreachable + // BB, which will usually (but not always) be dead code. + // + // Why only in unoptimized builds? + // - In unoptimized builds LLVM uses FastISel which does not support switches, so it + // must fall back to the to the slower SelectionDAG isel. Therefore, using `br` gives + // significant compile time speedups for unoptimized builds. + // - In optimized builds the above doesn't hold, and using `br` sometimes results in + // worse generated code because LLVM can no longer tell that the value being switched + // on can only have two values, e.g. 0 and 1. + // + let (test_value1, target1) = target_iter.next().unwrap(); + let (_test_value2, target2) = target_iter.next().unwrap(); + let ll1 = helper.llbb_with_cleanup(self, target1); + let ll2 = helper.llbb_with_cleanup(self, target2); + let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty)); + let llval = bx.const_uint_big(switch_llty, test_value1); + let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval); + bx.cond_br(cmp, ll1, ll2); } else { bx.switch( discr.immediate(), diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 83407ee8f9d..a4368303de5 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -267,6 +267,7 @@ const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ // tidy-alphabetical-start ("atomics", Some(sym::wasm_target_feature)), ("bulk-memory", Some(sym::wasm_target_feature)), + ("multivalue", Some(sym::wasm_target_feature)), ("mutable-globals", Some(sym::wasm_target_feature)), ("nontrapping-fptoint", Some(sym::wasm_target_feature)), ("reference-types", Some(sym::wasm_target_feature)), diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 87e347c61e2..5c35070ea66 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -119,7 +119,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, - has_alloc_error_handler: bool, + alloc_error_handler_kind: AllocatorKind, ) -> Self::Module; /// This generates the codegen unit and returns it along with /// a `u64` giving an estimate of the unit's processing cost. diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index a9063ad31cf..f7d64f6d4f4 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -598,7 +598,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // the last field). Can't have foreign types here, how would we // adjust alignment and size for them? let field = layout.field(self, layout.fields.count() - 1); - let Some((unsized_size, unsized_align)) = self.size_and_align_of(metadata, &field)? else { + let Some((unsized_size, mut unsized_align)) = self.size_and_align_of(metadata, &field)? else { // A field with an extern type. We don't know the actual dynamic size // or the alignment. return Ok(None); @@ -614,6 +614,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Return the sum of sizes and max of aligns. let size = sized_size + unsized_size; // `Size` addition + // Packed types ignore the alignment of their fields. + if let ty::Adt(def, _) = layout.ty.kind() { + if def.repr().packed() { + unsized_align = sized_align; + } + } + // Choose max of two known alignments (combined value must // be aligned according to more restrictive of the two). let align = sized_align.max(unsized_align); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 8637d6a7767..b92a6878847 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -7,7 +7,9 @@ use std::convert::TryFrom; use rustc_hir::def_id::DefId; use rustc_middle::mir::{ self, - interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar}, + interpret::{ + Allocation, ConstAllocation, ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar, + }, BinOp, NonDivergingIntrinsic, }; use rustc_middle::ty; @@ -23,7 +25,6 @@ use super::{ }; mod caller_location; -mod type_name; fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<Prov> { let size = match kind { @@ -42,6 +43,13 @@ fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar< Scalar::from_uint(bits_out, size) } +/// Directly returns an `Allocation` containing an absolute path representation of the given type. +pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> { + let path = crate::util::type_name(tcx, ty); + let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes()); + tcx.intern_const_alloc(alloc) +} + /// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated /// inside an `InterpCx` and instead have their value computed directly from rustc internal info. pub(crate) fn eval_nullary_intrinsic<'tcx>( @@ -55,7 +63,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( Ok(match name { sym::type_name => { ensure_monomorphic_enough(tcx, tp_ty)?; - let alloc = type_name::alloc_type_name(tcx, tp_ty); + let alloc = alloc_type_name(tcx, tp_ty); ConstValue::Slice { data: alloc, start: 0, end: alloc.inner().len() } } sym::needs_drop => { diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs index af9d83f0609..5446ccb1a47 100644 --- a/compiler/rustc_const_eval/src/util/call_kind.rs +++ b/compiler/rustc_const_eval/src/util/call_kind.rs @@ -3,7 +3,7 @@ //! context. use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItemGroup; +use rustc_hir::lang_items; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt}; use rustc_span::symbol::Ident; @@ -74,22 +74,24 @@ pub fn call_kind<'tcx>( } }); - let fn_call = parent - .and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p)); + let fn_call = parent.and_then(|p| { + lang_items::FN_TRAITS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p) + }); - let operator = (!from_hir_call) - .then(|| parent) - .flatten() - .and_then(|p| tcx.lang_items().group(LangItemGroup::Op).iter().find(|did| **did == p)); + let operator = if !from_hir_call && let Some(p) = parent { + lang_items::OPERATORS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p) + } else { + None + }; let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); // Check for a 'special' use of 'self' - // an FnOnce call, an operator (e.g. `<<`), or a // deref coercion. - let kind = if let Some(&trait_id) = fn_call { + let kind = if let Some(trait_id) = fn_call { Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) }) - } else if let Some(&trait_id) = operator { + } else if let Some(trait_id) = operator { Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) }) } else if is_deref { let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 7a05cfd235f..4d0f81a4060 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -4,9 +4,11 @@ mod call_kind; pub mod collect_writes; mod find_self_call; mod might_permit_raw_init; +mod type_name; pub use self::aggregate::expand_aggregate; pub use self::alignment::is_disaligned; pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind}; pub use self::find_self_call::find_self_call; pub use self::might_permit_raw_init::might_permit_raw_init; +pub use self::type_name::type_name; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index ffdb8de5b6c..221efc6f981 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -1,10 +1,9 @@ use rustc_data_structures::intern::Interned; use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::DisambiguatedDefPathData; -use rustc_middle::mir::interpret::{Allocation, ConstAllocation}; use rustc_middle::ty::{ self, - print::{with_no_verbose_constants, PrettyPrinter, Print, Printer}, + print::{PrettyPrinter, Print, Printer}, subst::{GenericArg, GenericArgKind}, Ty, TyCtxt, }; @@ -179,6 +178,11 @@ impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { Ok(self) } + + fn should_print_verbose(&self) -> bool { + // `std::any::type_name` should never print verbose type names + false + } } impl Write for AbsolutePathPrinter<'_> { @@ -188,11 +192,6 @@ impl Write for AbsolutePathPrinter<'_> { } } -/// Directly returns an `Allocation` containing an absolute path representation of the given type. -pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> { - let path = with_no_verbose_constants!( - AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path - ); - let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes()); - tcx.intern_const_alloc(alloc) +pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String { + AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path } diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index cfa734c7df3..cf4bcc7c158 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1200,6 +1200,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { false, None, false, + false, )); let handler = rustc_errors::Handler::with_emitter(true, None, emitter); diff --git a/compiler/rustc_error_codes/src/error_codes/E0382.md b/compiler/rustc_error_codes/src/error_codes/E0382.md index d1408a06296..cbc4980f8ca 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0382.md +++ b/compiler/rustc_error_codes/src/error_codes/E0382.md @@ -61,7 +61,7 @@ with `#[derive(Clone)]`. Some types have no ownership semantics at all and are trivial to duplicate. An example is `i32` and the other number types. We don't have to call `.clone()` to -clone them, because they are marked `Copy` in addition to `Clone`. Implicit +clone them, because they are marked `Copy` in addition to `Clone`. Implicit cloning is more convenient in this case. We can mark our own types `Copy` if all their members also are marked `Copy`. diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl index 08e553d9f15..c292ae9b32a 100644 --- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl +++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl @@ -150,12 +150,28 @@ metadata_no_multiple_global_alloc = metadata_prev_global_alloc = previous global allocator defined here +metadata_no_multiple_alloc_error_handler = + cannot define multiple allocation error handlers + .label = cannot define a new allocation error handler + +metadata_prev_alloc_error_handler = + previous allocation error handler defined here + metadata_conflicting_global_alloc = the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name} +metadata_conflicting_alloc_error_handler = + the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name} + metadata_global_alloc_required = no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait +metadata_alloc_func_required = + `#[alloc_error_handler]` function required, but not found + +metadata_missing_alloc_error_handler = + use `#![feature(default_alloc_error_handler)]` for a default error handler + metadata_no_transitive_needs_dep = the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}` diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl index b9e4499d47f..81d8e8a473b 100644 --- a/compiler/rustc_error_messages/locales/en-US/middle.ftl +++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl @@ -27,3 +27,7 @@ middle_values_too_big = middle_cannot_be_normalized = unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized + +middle_strict_coherence_needs_negative_coherence = + to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled + .label = due to this attribute diff --git a/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl b/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl index 42c84fdd2d1..48ddb54b79e 100644 --- a/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl +++ b/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl @@ -21,6 +21,3 @@ monomorphize_large_assignments = moving {$size} bytes .label = value moved from here .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` - -monomorphize_requires_lang_item = - requires `{$lang_item}` lang_item diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 4bc6bd9fb22..bc5bfe2a244 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -367,12 +367,6 @@ passes_unknown_external_lang_item = passes_missing_panic_handler = `#[panic_handler]` function required, but not found -passes_alloc_func_required = - `#[alloc_error_handler]` function required, but not found - -passes_missing_alloc_error_handler = - use `#![feature(default_alloc_error_handler)]` for a default error handler - passes_missing_lang_item = language item required, but not found: `{$name}` .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 23f29a24fe7..45c017df918 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -12,6 +12,7 @@ use rustc_span::{Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt; use std::hash::{Hash, Hasher}; +use std::panic::Location; /// Error type for `Diagnostic`'s `suggestions` field, indicating that /// `.disable_suggestions()` was called on the `Diagnostic`. @@ -107,6 +108,31 @@ pub struct Diagnostic { /// If diagnostic is from Lint, custom hash function ignores notes /// otherwise hash is based on the all the fields pub is_lint: bool, + + /// With `-Ztrack_diagnostics` enabled, + /// we print where in rustc this error was emitted. + pub emitted_at: DiagnosticLocation, +} + +#[derive(Clone, Debug, Encodable, Decodable)] +pub struct DiagnosticLocation { + file: Cow<'static, str>, + line: u32, + col: u32, +} + +impl DiagnosticLocation { + #[track_caller] + fn caller() -> Self { + let loc = Location::caller(); + DiagnosticLocation { file: loc.file().into(), line: loc.line(), col: loc.column() } + } +} + +impl fmt::Display for DiagnosticLocation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}:{}:{}", self.file, self.line, self.col) + } } #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] @@ -173,10 +199,12 @@ impl StringPart { } impl Diagnostic { + #[track_caller] pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self { Diagnostic::new_with_code(level, None, message) } + #[track_caller] pub fn new_with_code<M: Into<DiagnosticMessage>>( level: Level, code: Option<DiagnosticId>, @@ -192,6 +220,7 @@ impl Diagnostic { args: Default::default(), sort_span: DUMMY_SP, is_lint: false, + emitted_at: DiagnosticLocation::caller(), } } diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 9b41234dcfb..ecf8570e81f 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -133,6 +133,7 @@ mod sealed_level_is_error { impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> { /// Convenience function for internal use, clients should use one of the /// `struct_*` methods on [`Handler`]. + #[track_caller] pub(crate) fn new_guaranteeing_error<M: Into<DiagnosticMessage>, const L: Level>( handler: &'a Handler, message: M, @@ -196,6 +197,7 @@ impl EmissionGuarantee for ErrorGuaranteed { } } + #[track_caller] fn make_diagnostic_builder( handler: &Handler, msg: impl Into<DiagnosticMessage>, @@ -209,6 +211,7 @@ impl EmissionGuarantee for ErrorGuaranteed { impl<'a> DiagnosticBuilder<'a, ()> { /// Convenience function for internal use, clients should use one of the /// `struct_*` methods on [`Handler`]. + #[track_caller] pub(crate) fn new<M: Into<DiagnosticMessage>>( handler: &'a Handler, level: Level, @@ -220,6 +223,7 @@ impl<'a> DiagnosticBuilder<'a, ()> { /// Creates a new `DiagnosticBuilder` with an already constructed /// diagnostic. + #[track_caller] pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self { debug!("Created new diagnostic"); Self { @@ -308,6 +312,7 @@ impl EmissionGuarantee for Noted { impl<'a> DiagnosticBuilder<'a, !> { /// Convenience function for internal use, clients should use one of the /// `struct_*` methods on [`Handler`]. + #[track_caller] pub(crate) fn new_fatal(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self { let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message); Self::new_diagnostic_fatal(handler, diagnostic) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index cd6413bc3ec..b7b8fe3f25a 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -16,10 +16,10 @@ use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Styl use crate::styled_buffer::StyledBuffer; use crate::translation::{to_fluent_args, Translate}; use crate::{ - CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler, - LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle, + diagnostic::DiagnosticLocation, CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, + FluentBundle, Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, + SubstitutionHighlight, SuggestionStyle, }; - use rustc_lint_defs::pluralize; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; @@ -64,6 +64,7 @@ impl HumanReadableErrorType { teach: bool, diagnostic_width: Option<usize>, macro_backtrace: bool, + track_diagnostics: bool, ) -> EmitterWriter { let (short, color_config) = self.unzip(); let color = color_config.suggests_using_colors(); @@ -77,6 +78,7 @@ impl HumanReadableErrorType { color, diagnostic_width, macro_backtrace, + track_diagnostics, ) } } @@ -557,6 +559,7 @@ impl Emitter for EmitterWriter { &primary_span, &children, &suggestions, + self.track_diagnostics.then_some(&diag.emitted_at), ); } @@ -650,6 +653,7 @@ pub struct EmitterWriter { diagnostic_width: Option<usize>, macro_backtrace: bool, + track_diagnostics: bool, } #[derive(Debug)] @@ -669,6 +673,7 @@ impl EmitterWriter { teach: bool, diagnostic_width: Option<usize>, macro_backtrace: bool, + track_diagnostics: bool, ) -> EmitterWriter { let dst = Destination::from_stderr(color_config); EmitterWriter { @@ -681,6 +686,7 @@ impl EmitterWriter { ui_testing: false, diagnostic_width, macro_backtrace, + track_diagnostics, } } @@ -694,6 +700,7 @@ impl EmitterWriter { colored: bool, diagnostic_width: Option<usize>, macro_backtrace: bool, + track_diagnostics: bool, ) -> EmitterWriter { EmitterWriter { dst: Raw(dst, colored), @@ -705,6 +712,7 @@ impl EmitterWriter { ui_testing: false, diagnostic_width, macro_backtrace, + track_diagnostics, } } @@ -1327,6 +1335,7 @@ impl EmitterWriter { level: &Level, max_line_num_len: usize, is_secondary: bool, + emitted_at: Option<&DiagnosticLocation>, ) -> io::Result<()> { let mut buffer = StyledBuffer::new(); @@ -1377,7 +1386,6 @@ impl EmitterWriter { } } } - let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp); // Make sure our primary file comes first @@ -1653,6 +1661,12 @@ impl EmitterWriter { } } + if let Some(tracked) = emitted_at { + let track = format!("-Ztrack-diagnostics: created at {tracked}"); + let len = buffer.num_lines(); + buffer.append(len, &track, Style::NoStyle); + } + // final step: take our styled buffer, render it, then output it emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; @@ -1977,6 +1991,7 @@ impl EmitterWriter { span: &MultiSpan, children: &[SubDiagnostic], suggestions: &[CodeSuggestion], + emitted_at: Option<&DiagnosticLocation>, ) { let max_line_num_len = if self.ui_testing { ANONYMIZED_LINE_NUM.len() @@ -1985,7 +2000,16 @@ impl EmitterWriter { num_decimal_digits(n) }; - match self.emit_message_default(span, message, args, code, level, max_line_num_len, false) { + match self.emit_message_default( + span, + message, + args, + code, + level, + max_line_num_len, + false, + emitted_at, + ) { Ok(()) => { if !children.is_empty() || suggestions.iter().any(|s| s.style != SuggestionStyle::CompletelyHidden) @@ -2014,6 +2038,7 @@ impl EmitterWriter { &child.level, max_line_num_len, true, + None, ) { panic!("failed to emit error: {}", err); } @@ -2030,6 +2055,7 @@ impl EmitterWriter { &Level::Help, max_line_num_len, true, + None, ) { panic!("failed to emit error: {}", e); } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 4cc7be47fc2..c4498eafa4e 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -45,6 +45,7 @@ pub struct JsonEmitter { json_rendered: HumanReadableErrorType, diagnostic_width: Option<usize>, macro_backtrace: bool, + track_diagnostics: bool, } impl JsonEmitter { @@ -57,6 +58,7 @@ impl JsonEmitter { json_rendered: HumanReadableErrorType, diagnostic_width: Option<usize>, macro_backtrace: bool, + track_diagnostics: bool, ) -> JsonEmitter { JsonEmitter { dst: Box::new(io::BufWriter::new(io::stderr())), @@ -69,6 +71,7 @@ impl JsonEmitter { json_rendered, diagnostic_width, macro_backtrace, + track_diagnostics, } } @@ -79,6 +82,7 @@ impl JsonEmitter { fallback_bundle: LazyFallbackBundle, diagnostic_width: Option<usize>, macro_backtrace: bool, + track_diagnostics: bool, ) -> JsonEmitter { let file_path_mapping = FilePathMapping::empty(); JsonEmitter::stderr( @@ -90,6 +94,7 @@ impl JsonEmitter { json_rendered, diagnostic_width, macro_backtrace, + track_diagnostics, ) } @@ -103,6 +108,7 @@ impl JsonEmitter { json_rendered: HumanReadableErrorType, diagnostic_width: Option<usize>, macro_backtrace: bool, + track_diagnostics: bool, ) -> JsonEmitter { JsonEmitter { dst, @@ -115,6 +121,7 @@ impl JsonEmitter { json_rendered, diagnostic_width, macro_backtrace, + track_diagnostics, } } @@ -350,6 +357,7 @@ impl Diagnostic { false, je.diagnostic_width, je.macro_backtrace, + je.track_diagnostics, ) .ui_testing(je.ui_testing) .emit_diagnostic(diag); diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs index d940d14e1db..f131468971b 100644 --- a/compiler/rustc_errors/src/json/tests.rs +++ b/compiler/rustc_errors/src/json/tests.rs @@ -59,6 +59,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { HumanReadableErrorType::Short(ColorConfig::Never), None, false, + false, ); let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1)); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 0963ea71f80..f390495b53d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -492,6 +492,8 @@ pub struct HandlerFlags { pub macro_backtrace: bool, /// If true, identical diagnostics are reported only once. pub deduplicate_diagnostics: bool, + /// Track where errors are created. Enabled with `-Ztrack-diagnostics`. + pub track_diagnostics: bool, } impl Drop for HandlerInner { @@ -559,6 +561,7 @@ impl Handler { false, None, flags.macro_backtrace, + flags.track_diagnostics, )); Self::with_emitter_and_flags(emitter, flags) } @@ -664,6 +667,7 @@ impl Handler { /// Construct a builder with the `msg` at the level appropriate for the specific `EmissionGuarantee`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_diagnostic<G: EmissionGuarantee>( &self, msg: impl Into<DiagnosticMessage>, @@ -677,6 +681,7 @@ impl Handler { /// * `can_emit_warnings` is `true` /// * `is_force_warn` was set in `DiagnosticId::Lint` #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_warn( &self, span: impl Into<MultiSpan>, @@ -693,6 +698,7 @@ impl Handler { /// Attempting to `.emit()` the builder will only emit if either: /// * `can_emit_warnings` is `true` /// * `is_force_warn` was set in `DiagnosticId::Lint` + #[track_caller] pub fn struct_span_warn_with_expectation( &self, span: impl Into<MultiSpan>, @@ -706,6 +712,7 @@ impl Handler { /// Construct a builder at the `Allow` level at the given `span` and with the `msg`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_allow( &self, span: impl Into<MultiSpan>, @@ -719,6 +726,7 @@ impl Handler { /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. /// Also include a code. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_warn_with_code( &self, span: impl Into<MultiSpan>, @@ -736,6 +744,7 @@ impl Handler { /// * `can_emit_warnings` is `true` /// * `is_force_warn` was set in `DiagnosticId::Lint` #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Warning(None), msg) } @@ -746,6 +755,7 @@ impl Handler { /// Attempting to `.emit()` the builder will only emit if either: /// * `can_emit_warnings` is `true` /// * `is_force_warn` was set in `DiagnosticId::Lint` + #[track_caller] pub fn struct_warn_with_expectation( &self, msg: impl Into<DiagnosticMessage>, @@ -756,12 +766,14 @@ impl Handler { /// Construct a builder at the `Allow` level with the `msg`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Allow, msg) } /// Construct a builder at the `Expect` level with the `msg`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_expect( &self, msg: impl Into<DiagnosticMessage>, @@ -772,6 +784,7 @@ impl Handler { /// Construct a builder at the `Error` level at the given `span` and with the `msg`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_err( &self, span: impl Into<MultiSpan>, @@ -784,6 +797,7 @@ impl Handler { /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_err_with_code( &self, span: impl Into<MultiSpan>, @@ -798,6 +812,7 @@ impl Handler { /// Construct a builder at the `Error` level with the `msg`. // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_err( &self, msg: impl Into<DiagnosticMessage>, @@ -807,12 +822,14 @@ impl Handler { /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors. #[doc(hidden)] + #[track_caller] pub fn struct_err_lint(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Error { lint: true }, msg) } /// Construct a builder at the `Error` level with the `msg` and the `code`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_err_with_code( &self, msg: impl Into<DiagnosticMessage>, @@ -825,6 +842,7 @@ impl Handler { /// Construct a builder at the `Warn` level with the `msg` and the `code`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_warn_with_code( &self, msg: impl Into<DiagnosticMessage>, @@ -837,6 +855,7 @@ impl Handler { /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_fatal( &self, span: impl Into<MultiSpan>, @@ -849,6 +868,7 @@ impl Handler { /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_fatal_with_code( &self, span: impl Into<MultiSpan>, @@ -862,6 +882,7 @@ impl Handler { /// Construct a builder at the `Error` level with the `msg`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> { DiagnosticBuilder::new_fatal(self, msg) } @@ -874,6 +895,7 @@ impl Handler { /// Construct a builder at the `Note` level with the `msg`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_note_without_error( &self, msg: impl Into<DiagnosticMessage>, @@ -882,12 +904,14 @@ impl Handler { } #[rustc_lint_diagnostics] + #[track_caller] pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! { self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span); FatalError.raise() } #[rustc_lint_diagnostics] + #[track_caller] pub fn span_fatal_with_code( &self, span: impl Into<MultiSpan>, @@ -899,6 +923,7 @@ impl Handler { } #[rustc_lint_diagnostics] + #[track_caller] pub fn span_err( &self, span: impl Into<MultiSpan>, @@ -908,6 +933,7 @@ impl Handler { } #[rustc_lint_diagnostics] + #[track_caller] pub fn span_err_with_code( &self, span: impl Into<MultiSpan>, @@ -921,11 +947,13 @@ impl Handler { } #[rustc_lint_diagnostics] + #[track_caller] pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) { self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span); } #[rustc_lint_diagnostics] + #[track_caller] pub fn span_warn_with_code( &self, span: impl Into<MultiSpan>, @@ -954,10 +982,12 @@ impl Handler { self.inner.borrow_mut().delay_good_path_bug(msg) } + #[track_caller] pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) { self.emit_diag_at_span(Diagnostic::new(Bug, msg), span); } + #[track_caller] pub fn span_note_without_error( &self, span: impl Into<MultiSpan>, @@ -966,6 +996,7 @@ impl Handler { self.emit_diag_at_span(Diagnostic::new(Note, msg), span); } + #[track_caller] pub fn span_note_diag( &self, span: Span, @@ -1452,6 +1483,7 @@ impl HandlerInner { } } + #[track_caller] fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! { self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp); panic::panic_any(ExplicitBug); diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs index e44f0608196..d82a7a54030 100644 --- a/compiler/rustc_expand/src/tests.rs +++ b/compiler/rustc_expand/src/tests.rs @@ -151,6 +151,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: & false, None, false, + false, ); let handler = Handler::with_emitter(true, None, Box::new(emitter)); handler.span_err(msp, "foo"); diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 96645d40086..7900f150048 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -388,6 +388,9 @@ declare_features! ( (active, exclusive_range_pattern, "1.11.0", Some(37854), None), /// Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", Some(51085), None), + /// Allows using `efiapi`, `sysv64` and `win64` as calling convention + /// for functions with varargs. + (active, extended_varargs_abi_support, "1.65.0", Some(100189), None), /// Allows defining `extern type`s. (active, extern_types, "1.23.0", Some(43467), None), /// Allows the use of `#[ffi_const]` on foreign functions. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 2ead3c2c8d4..14c8e3c458c 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -555,10 +555,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), gated!( - alloc_error_handler, Normal, template!(Word), WarnFollowing, - experimental!(alloc_error_handler) - ), - gated!( default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals, experimental!(default_lib_allocator), ), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index be77e6fd36a..9ee5e25c9bf 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -410,12 +410,7 @@ pub trait Visitor<'v>: Sized { walk_inf(self, inf); } fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) { - match generic_arg { - GenericArg::Lifetime(lt) => self.visit_lifetime(lt), - GenericArg::Type(ty) => self.visit_ty(ty), - GenericArg::Const(ct) => self.visit_anon_const(&ct.value), - GenericArg::Infer(inf) => self.visit_infer(inf), - } + walk_generic_arg(self, generic_arg); } fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { walk_lifetime(self, lifetime) @@ -480,6 +475,15 @@ pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) { visitor.visit_ident(label.ident); } +pub fn walk_generic_arg<'v, V: Visitor<'v>>(visitor: &mut V, generic_arg: &'v GenericArg<'v>) { + match generic_arg { + GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt), + GenericArg::Type(ty) => visitor.visit_ty(ty), + GenericArg::Const(ct) => visitor.visit_anon_const(&ct.value), + GenericArg::Infer(inf) => visitor.visit_infer(inf), + } +} + pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { visitor.visit_id(lifetime.hir_id); match lifetime.name { diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index ca615a4912a..a55224d1097 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -12,35 +12,56 @@ use crate::errors::LangItemError; use crate::{MethodKind, Target}; use rustc_ast as ast; -use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable_Generic; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use std::sync::LazyLock; - -pub enum LangItemGroup { - Op, - Fn, +/// All of the language items, defined or not. +/// Defined lang items can come from the current crate or its dependencies. +#[derive(HashStable_Generic, Debug)] +pub struct LanguageItems { + /// Mappings from lang items to their possibly found [`DefId`]s. + /// The index corresponds to the order in [`LangItem`]. + items: [Option<DefId>; std::mem::variant_count::<LangItem>()], + /// Lang items that were not found during collection. + pub missing: Vec<LangItem>, } -const NUM_GROUPS: usize = 2; +impl LanguageItems { + /// Construct an empty collection of lang items and no missing ones. + pub fn new() -> Self { + Self { items: [None; std::mem::variant_count::<LangItem>()], missing: Vec::new() } + } + + pub fn get(&self, item: LangItem) -> Option<DefId> { + self.items[item as usize] + } -macro_rules! expand_group { - () => { - None - }; - ($group:expr) => { - Some($group) - }; + pub fn set(&mut self, item: LangItem, def_id: DefId) { + self.items[item as usize] = Some(def_id); + } + + /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`. + /// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`, + /// returns an error encapsulating the `LangItem`. + pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> { + self.get(it).ok_or_else(|| LangItemError(it)) + } + + pub fn iter<'a>(&'a self) -> impl Iterator<Item = (LangItem, DefId)> + 'a { + self.items + .iter() + .enumerate() + .filter_map(|(i, id)| id.map(|id| (LangItem::from_u32(i as u32).unwrap(), id))) + } } // The actual lang items defined come at the end of this file in one handy table. // So you probably just want to nip down to the end. macro_rules! language_item_table { ( - $( $(#[$attr:meta])* $variant:ident $($group:expr)?, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )* + $( $(#[$attr:meta])* $variant:ident, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )* ) => { enum_from_u32! { @@ -66,12 +87,17 @@ macro_rules! language_item_table { } } - /// The [group](LangItemGroup) that this lang item belongs to, - /// or `None` if it doesn't belong to a group. - pub fn group(self) -> Option<LangItemGroup> { - use LangItemGroup::*; + /// Opposite of [`LangItem::name`] + pub fn from_name(name: Symbol) -> Option<Self> { + match name { + $( $module::$name => Some(LangItem::$variant), )* + _ => None, + } + } + + pub fn target(self) -> Target { match self { - $( LangItem::$variant => expand_group!($($group)*), )* + $( LangItem::$variant => $target, )* } } @@ -82,50 +108,7 @@ macro_rules! language_item_table { } } - /// All of the language items, defined or not. - /// Defined lang items can come from the current crate or its dependencies. - #[derive(HashStable_Generic, Debug)] - pub struct LanguageItems { - /// Mappings from lang items to their possibly found [`DefId`]s. - /// The index corresponds to the order in [`LangItem`]. - pub items: Vec<Option<DefId>>, - /// Lang items that were not found during collection. - pub missing: Vec<LangItem>, - /// Mapping from [`LangItemGroup`] discriminants to all - /// [`DefId`]s of lang items in that group. - pub groups: [Vec<DefId>; NUM_GROUPS], - } - impl LanguageItems { - /// Construct an empty collection of lang items and no missing ones. - pub fn new() -> Self { - fn init_none(_: LangItem) -> Option<DefId> { None } - const EMPTY: Vec<DefId> = Vec::new(); - - Self { - items: vec![$(init_none(LangItem::$variant)),*], - missing: Vec::new(), - groups: [EMPTY; NUM_GROUPS], - } - } - - /// Returns the mappings to the possibly found `DefId`s for each lang item. - pub fn items(&self) -> &[Option<DefId>] { - &*self.items - } - - /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`. - /// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`, - /// returns an error encapsulating the `LangItem`. - pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> { - self.items[it as usize].ok_or_else(|| LangItemError(it)) - } - - /// Returns the [`DefId`]s of all lang items in a group. - pub fn group(&self, group: LangItemGroup) -> &[DefId] { - self.groups[group as usize].as_ref() - } - $( #[doc = concat!("Returns the [`DefId`] of the `", stringify!($name), "` lang item if it is defined.")] pub fn $method(&self) -> Option<DefId> { @@ -133,15 +116,6 @@ macro_rules! language_item_table { } )* } - - /// A mapping from the name of the lang item to its order and the form it must be of. - pub static ITEM_REFS: LazyLock<FxIndexMap<Symbol, (usize, Target)>> = LazyLock::new(|| { - let mut item_refs = FxIndexMap::default(); - $( item_refs.insert($module::$name, (LangItem::$variant as usize, $target)); )* - item_refs - }); - -// End of the macro } } @@ -152,14 +126,12 @@ impl<CTX> HashStable<CTX> for LangItem { } /// Extracts the first `lang = "$name"` out of a list of attributes. -/// The attributes `#[panic_handler]` and `#[alloc_error_handler]` -/// are also extracted out when found. +/// The `#[panic_handler]` attribute is also extracted out when found. pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { attrs.iter().find_map(|attr| { Some(match attr { _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span), _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span), - _ if attr.has_name(sym::alloc_error_handler) => (sym::oom, attr.span), _ => return None, }) }) @@ -196,30 +168,30 @@ language_item_table! { TransmuteOpts, sym::transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0); TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(3); - Add(Op), sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1); - Sub(Op), sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1); - Mul(Op), sym::mul, mul_trait, Target::Trait, GenericRequirement::Exact(1); - Div(Op), sym::div, div_trait, Target::Trait, GenericRequirement::Exact(1); - Rem(Op), sym::rem, rem_trait, Target::Trait, GenericRequirement::Exact(1); - Neg(Op), sym::neg, neg_trait, Target::Trait, GenericRequirement::Exact(0); - Not(Op), sym::not, not_trait, Target::Trait, GenericRequirement::Exact(0); - BitXor(Op), sym::bitxor, bitxor_trait, Target::Trait, GenericRequirement::Exact(1); - BitAnd(Op), sym::bitand, bitand_trait, Target::Trait, GenericRequirement::Exact(1); - BitOr(Op), sym::bitor, bitor_trait, Target::Trait, GenericRequirement::Exact(1); - Shl(Op), sym::shl, shl_trait, Target::Trait, GenericRequirement::Exact(1); - Shr(Op), sym::shr, shr_trait, Target::Trait, GenericRequirement::Exact(1); - AddAssign(Op), sym::add_assign, add_assign_trait, Target::Trait, GenericRequirement::Exact(1); - SubAssign(Op), sym::sub_assign, sub_assign_trait, Target::Trait, GenericRequirement::Exact(1); - MulAssign(Op), sym::mul_assign, mul_assign_trait, Target::Trait, GenericRequirement::Exact(1); - DivAssign(Op), sym::div_assign, div_assign_trait, Target::Trait, GenericRequirement::Exact(1); - RemAssign(Op), sym::rem_assign, rem_assign_trait, Target::Trait, GenericRequirement::Exact(1); - BitXorAssign(Op), sym::bitxor_assign, bitxor_assign_trait, Target::Trait, GenericRequirement::Exact(1); - BitAndAssign(Op), sym::bitand_assign, bitand_assign_trait, Target::Trait, GenericRequirement::Exact(1); - BitOrAssign(Op), sym::bitor_assign, bitor_assign_trait, Target::Trait, GenericRequirement::Exact(1); - ShlAssign(Op), sym::shl_assign, shl_assign_trait, Target::Trait, GenericRequirement::Exact(1); - ShrAssign(Op), sym::shr_assign, shr_assign_trait, Target::Trait, GenericRequirement::Exact(1); - Index(Op), sym::index, index_trait, Target::Trait, GenericRequirement::Exact(1); - IndexMut(Op), sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1); + Add, sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1); + Sub, sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1); + Mul, sym::mul, mul_trait, Target::Trait, GenericRequirement::Exact(1); + Div, sym::div, div_trait, Target::Trait, GenericRequirement::Exact(1); + Rem, sym::rem, rem_trait, Target::Trait, GenericRequirement::Exact(1); + Neg, sym::neg, neg_trait, Target::Trait, GenericRequirement::Exact(0); + Not, sym::not, not_trait, Target::Trait, GenericRequirement::Exact(0); + BitXor, sym::bitxor, bitxor_trait, Target::Trait, GenericRequirement::Exact(1); + BitAnd, sym::bitand, bitand_trait, Target::Trait, GenericRequirement::Exact(1); + BitOr, sym::bitor, bitor_trait, Target::Trait, GenericRequirement::Exact(1); + Shl, sym::shl, shl_trait, Target::Trait, GenericRequirement::Exact(1); + Shr, sym::shr, shr_trait, Target::Trait, GenericRequirement::Exact(1); + AddAssign, sym::add_assign, add_assign_trait, Target::Trait, GenericRequirement::Exact(1); + SubAssign, sym::sub_assign, sub_assign_trait, Target::Trait, GenericRequirement::Exact(1); + MulAssign, sym::mul_assign, mul_assign_trait, Target::Trait, GenericRequirement::Exact(1); + DivAssign, sym::div_assign, div_assign_trait, Target::Trait, GenericRequirement::Exact(1); + RemAssign, sym::rem_assign, rem_assign_trait, Target::Trait, GenericRequirement::Exact(1); + BitXorAssign, sym::bitxor_assign, bitxor_assign_trait, Target::Trait, GenericRequirement::Exact(1); + BitAndAssign, sym::bitand_assign, bitand_assign_trait, Target::Trait, GenericRequirement::Exact(1); + BitOrAssign, sym::bitor_assign, bitor_assign_trait, Target::Trait, GenericRequirement::Exact(1); + ShlAssign, sym::shl_assign, shl_assign_trait, Target::Trait, GenericRequirement::Exact(1); + ShrAssign, sym::shr_assign, shr_assign_trait, Target::Trait, GenericRequirement::Exact(1); + Index, sym::index, index_trait, Target::Trait, GenericRequirement::Exact(1); + IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1); UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None; VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None; @@ -229,9 +201,9 @@ language_item_table! { DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None; Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None; - Fn(Fn), kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1); - FnMut(Fn), sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); - FnOnce(Fn), sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1); + FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); + FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; @@ -241,8 +213,8 @@ language_item_table! { Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None; - PartialEq(Op), sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1); - PartialOrd(Op), sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1); + PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1); + PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1); // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays. @@ -266,7 +238,6 @@ language_item_table! { ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None; BoxFree, sym::box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1); DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); - Oom, sym::oom, oom, Target::Fn, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); @@ -338,3 +309,34 @@ pub enum GenericRequirement { Minimum(usize), Exact(usize), } + +pub static FN_TRAITS: &'static [LangItem] = &[LangItem::Fn, LangItem::FnMut, LangItem::FnOnce]; + +pub static OPERATORS: &'static [LangItem] = &[ + LangItem::Add, + LangItem::Sub, + LangItem::Mul, + LangItem::Div, + LangItem::Rem, + LangItem::Neg, + LangItem::Not, + LangItem::BitXor, + LangItem::BitAnd, + LangItem::BitOr, + LangItem::Shl, + LangItem::Shr, + LangItem::AddAssign, + LangItem::SubAssign, + LangItem::MulAssign, + LangItem::DivAssign, + LangItem::RemAssign, + LangItem::BitXorAssign, + LangItem::BitAndAssign, + LangItem::BitOrAssign, + LangItem::ShlAssign, + LangItem::ShrAssign, + LangItem::Index, + LangItem::IndexMut, + LangItem::PartialEq, + LangItem::PartialOrd, +]; diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 1c4aa420c9b..1c55cd8fee8 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -5,10 +5,10 @@ #![feature(associated_type_defaults)] #![feature(closure_track_caller)] #![feature(const_btree_len)] -#![feature(once_cell)] #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] +#![feature(variant_count)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index da9c9c1216e..0cc50c6dd85 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -1,53 +1,30 @@ //! Validity checking for weak lang items -use crate::def_id::DefId; -use crate::{lang_items, LangItem, LanguageItems}; +use crate::LangItem; -use rustc_ast as ast; -use rustc_data_structures::fx::FxIndexMap; use rustc_span::symbol::{sym, Symbol}; -use std::sync::LazyLock; - macro_rules! weak_lang_items { - ($($name:ident, $item:ident, $sym:ident;)*) => ( - -pub static WEAK_ITEMS_REFS: LazyLock<FxIndexMap<Symbol, LangItem>> = LazyLock::new(|| { - let mut map = FxIndexMap::default(); - $(map.insert(sym::$name, LangItem::$item);)* - map -}); - -pub static WEAK_ITEMS_SYMBOLS: LazyLock<FxIndexMap<LangItem, Symbol>> = LazyLock::new(|| { - let mut map = FxIndexMap::default(); - $(map.insert(LangItem::$item, sym::$sym);)* - map -}); - -pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol> -{ - lang_items::extract(attrs).and_then(|(name, _)| { - $(if name == sym::$name { - Some(sym::$sym) - } else)* { - None + ($($item:ident, $sym:ident;)*) => { + pub static WEAK_LANG_ITEMS: &[LangItem] = &[$(LangItem::$item,)*]; + + impl LangItem { + pub fn is_weak(self) -> bool { + matches!(self, $(LangItem::$item)|*) + } + + pub fn link_name(self) -> Option<Symbol> { + match self { + $( LangItem::$item => Some(sym::$sym),)* + _ => None, + } + } } - }) -} - -impl LanguageItems { - pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool { - let did = Some(item_def_id); - - $(self.$name() == did)||* } } -) } - weak_lang_items! { - panic_impl, PanicImpl, rust_begin_unwind; - eh_personality, EhPersonality, rust_eh_personality; - eh_catch_typeinfo, EhCatchTypeinfo, rust_eh_catch_typeinfo; - oom, Oom, rust_oom; + PanicImpl, rust_begin_unwind; + EhPersonality, rust_eh_personality; + EhCatchTypeinfo, rust_eh_catch_typeinfo; } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 38f195dabb9..39b178f5976 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -23,7 +23,6 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{walk_generics, Visitor as _}; -use rustc_hir::lang_items::LangItem; use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; @@ -884,9 +883,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - let sized_def_id = tcx.lang_items().require(LangItem::Sized); + let sized_def_id = tcx.lang_items().sized_trait(); match (&sized_def_id, unbound) { - (Ok(sized_def_id), Some(tpb)) + (Some(sized_def_id), Some(tpb)) if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) => { // There was in fact a `?Sized` bound, return without doing anything @@ -906,7 +905,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // There was no `?Sized` bound; add implicitly sized if `Sized` is available. } } - if sized_def_id.is_err() { + if sized_def_id.is_none() { // No lang item for `Sized`, so we can't add it as a bound. return; } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index b70ac02058d..133bbd52b91 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -6,7 +6,7 @@ use super::*; use rustc_attr as attr; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{ItemKind, Node, PathSegment}; @@ -75,7 +75,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_simd(tcx, span, def_id); } - check_transparent(tcx, span, def); + check_transparent(tcx, def); check_packed(tcx, span, def); } @@ -83,7 +83,7 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); def.destructor(tcx); // force the destructor to be evaluated - check_transparent(tcx, span, def); + check_transparent(tcx, def); check_union_fields(tcx, span, def_id); check_packed(tcx, span, def); } @@ -506,11 +506,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { tcx.ensure().typeck(id.owner_id.def_id); } DefKind::Enum => { - let item = tcx.hir().item(id); - let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else { - return; - }; - check_enum(tcx, &enum_definition.variants, item.owner_id.def_id); + check_enum(tcx, id.owner_id.def_id); } DefKind::Fn => {} // entirely within check_item_body DefKind::Impl => { @@ -1026,7 +1022,7 @@ pub(super) fn check_packed_inner( None } -pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtDef<'tcx>) { +pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) { if !adt.repr().transparent() { return; } @@ -1035,14 +1031,14 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD feature_err( &tcx.sess.parse_sess, sym::transparent_unions, - sp, + tcx.def_span(adt.did()), "transparent unions are unstable", ) .emit(); } if adt.variants().len() != 1 { - bad_variant_count(tcx, adt, sp, adt.did()); + bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did()); if adt.variants().is_empty() { // Don't bother checking the fields. No variants (and thus no fields) exist. return; @@ -1103,7 +1099,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD .filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None }); let non_zst_count = non_zst_fields.clone().count(); if non_zst_count >= 2 { - bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp); + bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did())); } let incompatible_zst_fields = field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count(); @@ -1143,12 +1139,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD } #[allow(trivial_numeric_casts)] -fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: LocalDefId) { +fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); - let sp = tcx.def_span(def_id); def.destructor(tcx); // force the destructor to be evaluated - if vs.is_empty() { + if def.variants().is_empty() { if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() { struct_span_err!( tcx.sess, @@ -1156,7 +1151,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L E0084, "unsupported representation for zero-variant enum" ) - .span_label(sp, "zero-variant enum") + .span_label(tcx.def_span(def_id), "zero-variant enum") .emit(); } } @@ -1167,88 +1162,96 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L feature_err( &tcx.sess.parse_sess, sym::repr128, - sp, + tcx.def_span(def_id), "repr with 128-bit type is unstable", ) .emit(); } } - for v in vs { - if let Some(ref e) = v.disr_expr { - tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id)); + for v in def.variants() { + if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr { + tcx.ensure().typeck(discr_def_id.expect_local()); } } - if tcx.adt_def(def_id).repr().int.is_none() { - let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..)); + if def.repr().int.is_none() { + let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind, CtorKind::Const); + let has_disr = |var: &ty::VariantDef| matches!(var.discr, ty::VariantDiscr::Explicit(_)); - let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); - let has_non_units = vs.iter().any(|var| !is_unit(var)); - let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var)); - let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var)); + let has_non_units = def.variants().iter().any(|var| !is_unit(var)); + let disr_units = def.variants().iter().any(|var| is_unit(&var) && has_disr(&var)); + let disr_non_unit = def.variants().iter().any(|var| !is_unit(&var) && has_disr(&var)); if disr_non_unit || (disr_units && has_non_units) { - let mut err = - struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified"); + let mut err = struct_span_err!( + tcx.sess, + tcx.def_span(def_id), + E0732, + "`#[repr(inttype)]` must be specified" + ); err.emit(); } } - detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp); - - check_transparent(tcx, sp, def); + detect_discriminant_duplicate(tcx, def); + check_transparent(tcx, def); } /// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal -fn detect_discriminant_duplicate<'tcx>( - tcx: TyCtxt<'tcx>, - mut discrs: Vec<(VariantIdx, Discr<'tcx>)>, - vs: &'tcx [hir::Variant<'tcx>], - self_span: Span, -) { +fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) { // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate. // Here `idx` refers to the order of which the discriminant appears, and its index in `vs` - let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| { - let var = &vs[idx]; // HIR for the duplicate discriminant - let (span, display_discr) = match var.disr_expr { - Some(ref expr) => { + let report = |dis: Discr<'tcx>, idx, err: &mut Diagnostic| { + let var = adt.variant(idx); // HIR for the duplicate discriminant + let (span, display_discr) = match var.discr { + ty::VariantDiscr::Explicit(discr_def_id) => { // In the case the discriminant is both a duplicate and overflowed, let the user know - if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind + if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local()) + && let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node && *lit_value != dis.val { - (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)")) - // Otherwise, format the value as-is + (tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)")) } else { - (tcx.hir().span(expr.hir_id), format!("`{dis}`")) + // Otherwise, format the value as-is + (tcx.def_span(discr_def_id), format!("`{dis}`")) } } - None => { + // This should not happen. + ty::VariantDiscr::Relative(0) => (tcx.def_span(var.def_id), format!("`{dis}`")), + ty::VariantDiscr::Relative(distance_to_explicit) => { // At this point we know this discriminant is a duplicate, and was not explicitly // assigned by the user. Here we iterate backwards to fetch the HIR for the last // explicitly assigned discriminant, and letting the user know that this was the // increment startpoint, and how many steps from there leading to the duplicate - if let Some((n, hir::Variant { span, ident, .. })) = - vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some()) + if let Some(explicit_idx) = + idx.as_u32().checked_sub(distance_to_explicit).map(VariantIdx::from_u32) { - let ve_ident = var.ident; - let n = n + 1; - let sp = if n > 1 { "variants" } else { "variant" }; + let explicit_variant = adt.variant(explicit_idx); + let ve_ident = var.name; + let ex_ident = explicit_variant.name; + let sp = if distance_to_explicit > 1 { "variants" } else { "variant" }; err.span_label( - *span, - format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"), + tcx.def_span(explicit_variant.def_id), + format!( + "discriminant for `{ve_ident}` incremented from this startpoint \ + (`{ex_ident}` + {distance_to_explicit} {sp} later \ + => `{ve_ident}` = {dis})" + ), ); } - (vs[idx].span, format!("`{dis}`")) + (tcx.def_span(var.def_id), format!("`{dis}`")) } }; err.span_label(span, format!("{display_discr} assigned here")); }; + let mut discrs = adt.discriminants(tcx).collect::<Vec<_>>(); + // Here we loop through the discriminants, comparing each discriminant to another. // When a duplicate is detected, we instantiate an error and point to both // initial and duplicate value. The duplicate discriminant is then discarded by swapping @@ -1257,29 +1260,29 @@ fn detect_discriminant_duplicate<'tcx>( // style as we are mutating `discrs` on the fly). let mut i = 0; while i < discrs.len() { - let hir_var_i_idx = discrs[i].0.index(); + let var_i_idx = discrs[i].0; let mut error: Option<DiagnosticBuilder<'_, _>> = None; let mut o = i + 1; while o < discrs.len() { - let hir_var_o_idx = discrs[o].0.index(); + let var_o_idx = discrs[o].0; if discrs[i].1.val == discrs[o].1.val { let err = error.get_or_insert_with(|| { let mut ret = struct_span_err!( tcx.sess, - self_span, + tcx.def_span(adt.did()), E0081, "discriminant value `{}` assigned more than once", discrs[i].1, ); - report(discrs[i].1, hir_var_i_idx, &mut ret); + report(discrs[i].1, var_i_idx, &mut ret); ret }); - report(discrs[o].1, hir_var_o_idx, err); + report(discrs[o].1, var_o_idx, err); // Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty discrs[o] = *discrs.last().unwrap(); diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index 32f66b06f83..aeaf7a6cfe1 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -290,10 +290,7 @@ fn compare_predicate_entailment<'tcx>( // type would be more appropriate. In other places we have a `Vec<Span>` // corresponding to their `Vec<Predicate>`, but we don't have that here. // Fixing this would improve the output of test `issue-83765.rs`. - let mut result = infcx - .at(&cause, param_env) - .sup(trait_fty, impl_fty) - .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok)); + let mut result = ocx.sup(&cause, param_env, trait_fty, impl_fty); // HACK(RPITIT): #101614. When we are trying to infer the hidden types for // RPITITs, we need to equate the output tys instead of just subtyping. If @@ -301,12 +298,8 @@ fn compare_predicate_entailment<'tcx>( // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets // fixed up to `ReEmpty`, and which is certainly not what we want. if trait_fty.has_infer_types() { - result = result.and_then(|()| { - infcx - .at(&cause, param_env) - .eq(trait_sig.output(), impl_sig.output()) - .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok)) - }); + result = + result.and_then(|()| ocx.eq(&cause, param_env, trait_sig.output(), impl_sig.output())); } if let Err(terr) = result { @@ -1389,10 +1382,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>( debug!("compare_const_impl: trait_ty={:?}", trait_ty); - let err = infcx - .at(&cause, param_env) - .sup(trait_ty, impl_ty) - .map(|ok| ocx.register_infer_ok_obligations(ok)); + let err = ocx.sup(&cause, param_env, trait_ty, impl_ty); if let Err(terr) = err { debug!( diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index a2357500465..0117bdd0ba8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -218,19 +218,16 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { hir::ItemKind::Const(ty, ..) => { check_item_type(tcx, def_id, ty.span, false); } - hir::ItemKind::Struct(ref struct_def, ref ast_generics) => { - check_type_defn(tcx, item, false, |wfcx| vec![wfcx.non_enum_variant(struct_def)]); - + hir::ItemKind::Struct(_, ref ast_generics) => { + check_type_defn(tcx, item, false); check_variances_for_type_defn(tcx, item, ast_generics); } - hir::ItemKind::Union(ref struct_def, ref ast_generics) => { - check_type_defn(tcx, item, true, |wfcx| vec![wfcx.non_enum_variant(struct_def)]); - + hir::ItemKind::Union(_, ref ast_generics) => { + check_type_defn(tcx, item, true); check_variances_for_type_defn(tcx, item, ast_generics); } - hir::ItemKind::Enum(ref enum_def, ref ast_generics) => { - check_type_defn(tcx, item, true, |wfcx| wfcx.enum_variants(enum_def)); - + hir::ItemKind::Enum(_, ref ast_generics) => { + check_type_defn(tcx, item, true); check_variances_for_type_defn(tcx, item, ast_generics); } hir::ItemKind::Trait(..) => { @@ -1037,27 +1034,25 @@ fn item_adt_kind(kind: &ItemKind<'_>) -> Option<AdtKind> { } /// In a type definition, we check that to ensure that the types of the fields are well-formed. -fn check_type_defn<'tcx, F>( - tcx: TyCtxt<'tcx>, - item: &hir::Item<'tcx>, - all_sized: bool, - mut lookup_fields: F, -) where - F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>, -{ +fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: bool) { let _ = tcx.representability(item.owner_id.def_id); + let adt_def = tcx.adt_def(item.owner_id); enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| { - let variants = lookup_fields(wfcx); - let packed = tcx.adt_def(item.owner_id).repr().packed(); + let variants = adt_def.variants(); + let packed = adt_def.repr().packed(); - for variant in &variants { + for variant in variants.iter() { // All field types must be well-formed. for field in &variant.fields { + let field_id = field.did.expect_local(); + let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) + else { bug!() }; + let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_wf_obligation( - field.span, - Some(WellFormedLoc::Ty(field.def_id)), - field.ty.into(), + hir_ty.span, + Some(WellFormedLoc::Ty(field_id)), + ty.into(), ) } @@ -1065,7 +1060,7 @@ fn check_type_defn<'tcx, F>( // intermediate types must be sized. let needs_drop_copy = || { packed && { - let ty = variant.fields.last().unwrap().ty; + let ty = tcx.type_of(variant.fields.last().unwrap().did); let ty = tcx.erase_regions(ty); if ty.needs_infer() { tcx.sess @@ -1084,27 +1079,31 @@ fn check_type_defn<'tcx, F>( variant.fields[..variant.fields.len() - unsized_len].iter().enumerate() { let last = idx == variant.fields.len() - 1; + let field_id = field.did.expect_local(); + let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) + else { bug!() }; + let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_bound( traits::ObligationCause::new( - field.span, + hir_ty.span, wfcx.body_id, traits::FieldSized { adt_kind: match item_adt_kind(&item.kind) { Some(i) => i, None => bug!(), }, - span: field.span, + span: hir_ty.span, last, }, ), wfcx.param_env, - field.ty, + ty, tcx.require_lang_item(LangItem::Sized, None), ); } // Explicit `enum` discriminant values must const-evaluate successfully. - if let Some(discr_def_id) = variant.explicit_discr { + if let ty::VariantDiscr::Explicit(discr_def_id) = variant.discr { let cause = traits::ObligationCause::new( tcx.def_span(discr_def_id), wfcx.body_id, @@ -1114,7 +1113,7 @@ fn check_type_defn<'tcx, F>( cause, wfcx.param_env, ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable( - ty::Const::from_anon_const(tcx, discr_def_id), + ty::Const::from_anon_const(tcx, discr_def_id.expect_local()), )) .to_predicate(tcx), )); @@ -1675,7 +1674,7 @@ fn receiver_is_valid<'tcx>( // `self: Self` is always valid. if can_eq_self(receiver_ty) { - if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) { + if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, receiver_ty) { infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit(); } return true; @@ -1705,9 +1704,7 @@ fn receiver_is_valid<'tcx>( if can_eq_self(potential_self_ty) { wfcx.register_obligations(autoderef.into_obligations()); - if let Err(err) = - wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty) - { + if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty) { infcx .err_ctxt() .report_mismatched_types(&cause, self_ty, potential_self_ty, err) @@ -1925,56 +1922,6 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) { items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)); } -/////////////////////////////////////////////////////////////////////////// -// ADT - -// FIXME(eddyb) replace this with getting fields/discriminants through `ty::AdtDef`. -struct AdtVariant<'tcx> { - /// Types of fields in the variant, that must be well-formed. - fields: Vec<AdtField<'tcx>>, - - /// Explicit discriminant of this variant (e.g. `A = 123`), - /// that must evaluate to a constant value. - explicit_discr: Option<LocalDefId>, -} - -struct AdtField<'tcx> { - ty: Ty<'tcx>, - def_id: LocalDefId, - span: Span, -} - -impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> { - // FIXME(eddyb) replace this with getting fields through `ty::AdtDef`. - fn non_enum_variant(&self, struct_def: &hir::VariantData<'_>) -> AdtVariant<'tcx> { - let fields = struct_def - .fields() - .iter() - .map(|field| { - let def_id = self.tcx().hir().local_def_id(field.hir_id); - let field_ty = self.tcx().type_of(def_id); - let field_ty = self.normalize(field.ty.span, None, field_ty); - debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty); - AdtField { ty: field_ty, span: field.ty.span, def_id } - }) - .collect(); - AdtVariant { fields, explicit_discr: None } - } - - fn enum_variants(&self, enum_def: &hir::EnumDef<'_>) -> Vec<AdtVariant<'tcx>> { - enum_def - .variants - .iter() - .map(|variant| AdtVariant { - fields: self.non_enum_variant(&variant.data).fields, - explicit_discr: variant - .disr_expr - .map(|explicit_discr| self.tcx().hir().local_def_id(explicit_discr.hir_id)), - }) - .collect() - } -} - fn error_392( tcx: TyCtxt<'_>, span: Span, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 346d2e2fc4b..46db0f74d4d 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -27,8 +27,8 @@ use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::weak_lang_items; -use rustc_hir::{GenericParamKind, Node}; +use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; +use rustc_hir::{lang_items, GenericParamKind, LangItem, Node}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::Linkage; @@ -604,11 +604,11 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } } } - hir::ItemKind::Enum(ref enum_definition, _) => { + hir::ItemKind::Enum(..) => { tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); tcx.ensure().predicates_of(def_id); - convert_enum_variant_types(tcx, def_id.to_def_id(), enum_definition.variants); + convert_enum_variant_types(tcx, def_id.to_def_id()); } hir::ItemKind::Impl { .. } => { tcx.ensure().generics_of(def_id); @@ -640,7 +640,8 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { - convert_variant_ctor(tcx, ctor_hir_id); + let ctor_def_id = tcx.hir().local_def_id(ctor_hir_id); + convert_variant_ctor(tcx, ctor_def_id); } } @@ -750,37 +751,34 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { } } -fn convert_variant_ctor(tcx: TyCtxt<'_>, ctor_id: hir::HirId) { - let def_id = tcx.hir().local_def_id(ctor_id); +fn convert_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) { tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); tcx.ensure().predicates_of(def_id); } -fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::Variant<'_>]) { +fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { let def = tcx.adt_def(def_id); let repr_type = def.repr().discr_type(); let initial = repr_type.initial_discriminant(tcx); let mut prev_discr = None::<Discr<'_>>; // fill the discriminant values and field types - for variant in variants { + for variant in def.variants() { let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx)); prev_discr = Some( - if let Some(ref e) = variant.disr_expr { - let expr_did = tcx.hir().local_def_id(e.hir_id); - def.eval_explicit_discr(tcx, expr_did.to_def_id()) + if let ty::VariantDiscr::Explicit(const_def_id) = variant.discr { + def.eval_explicit_discr(tcx, const_def_id) } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) { Some(discr) } else { - struct_span_err!(tcx.sess, variant.span, E0370, "enum discriminant overflowed") - .span_label( - variant.span, - format!("overflowed on value after {}", prev_discr.unwrap()), - ) + let span = tcx.def_span(variant.def_id); + struct_span_err!(tcx.sess, span, E0370, "enum discriminant overflowed") + .span_label(span, format!("overflowed on value after {}", prev_discr.unwrap())) .note(&format!( "explicitly set `{} = {}` if that is desired outcome", - variant.ident, wrapped_discr + tcx.item_name(variant.def_id), + wrapped_discr )) .emit(); None @@ -788,17 +786,16 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::V .unwrap_or(wrapped_discr), ); - for f in variant.data.fields() { - let def_id = tcx.hir().local_def_id(f.hir_id); - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + for f in &variant.fields { + tcx.ensure().generics_of(f.did); + tcx.ensure().type_of(f.did); + tcx.ensure().predicates_of(f.did); } // Convert the ctor, if any. This also registers the variant as // an item. - if let Some(ctor_hir_id) = variant.data.ctor_hir_id() { - convert_variant_ctor(tcx, ctor_hir_id); + if let Some(ctor_def_id) = variant.ctor_def_id { + convert_variant_ctor(tcx, ctor_def_id.expect_local()); } } } @@ -2104,12 +2101,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { // strippable by the linker. // // Additionally weak lang items have predetermined symbol names. - if tcx.is_weak_lang_item(did.to_def_id()) { + if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } - if let Some(name) = weak_lang_items::link_name(attrs) { - codegen_fn_attrs.export_name = Some(name); - codegen_fn_attrs.link_name = Some(name); + if let Some((name, _)) = lang_items::extract(attrs) + && let Some(lang_item) = LangItem::from_name(name) + && let Some(link_name) = lang_item.link_name() + { + codegen_fn_attrs.export_name = Some(link_name); + codegen_fn_attrs.link_name = Some(link_name); } check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index d5b1a7ce1c2..afbb27155a2 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -120,7 +120,7 @@ pub struct TypeofReservedKeywordUsed<'tcx> { #[primary_span] #[label] pub span: Span, - #[suggestion_verbose(code = "{ty}")] + #[suggestion(style = "verbose", code = "{ty}")] pub opt_sugg: Option<(Span, Applicability)>, } @@ -156,6 +156,7 @@ pub struct MissingTypeParams { // Manual implementation of `IntoDiagnostic` to be able to call `span_to_snippet`. impl<'a> IntoDiagnostic<'a> for MissingTypeParams { + #[track_caller] fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut err = handler.struct_span_err_with_code( self.span, @@ -238,7 +239,11 @@ pub struct UnusedExternCrate { #[derive(LintDiagnostic)] #[diag(hir_analysis_extern_crate_not_idiomatic)] pub struct ExternCrateNotIdiomatic { - #[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")] + #[suggestion( + style = "short", + applicability = "machine-applicable", + code = "{suggestion_code}" + )] pub span: Span, pub msg_code: String, pub suggestion_code: String, diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 525cd24190a..bd1a461b935 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -106,7 +106,7 @@ use rustc_middle::middle; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::util; -use rustc_session::config::EntryFnType; +use rustc_session::{config::EntryFnType, parse::feature_err}; use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; @@ -118,20 +118,40 @@ use astconv::AstConv; use bounds::Bounds; fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { - match (decl.c_variadic, abi) { - // The function has the correct calling convention, or isn't a "C-variadic" function. - (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {} - // The function is a "C-variadic" function with an incorrect calling convention. - (true, _) => { - let mut err = struct_span_err!( - tcx.sess, + const ERROR_HEAD: &str = "C-variadic function must have a compatible calling convention"; + const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`"; + const CONVENTIONS_STABLE: &str = "`C` or `cdecl`"; + const UNSTABLE_EXPLAIN: &str = + "using calling conventions other than `C` or `cdecl` for varargs functions is unstable"; + + if !decl.c_variadic || matches!(abi, Abi::C { .. } | Abi::Cdecl { .. }) { + return; + } + + let extended_abi_support = tcx.features().extended_varargs_abi_support; + let conventions = match (extended_abi_support, abi.supports_varargs()) { + // User enabled additional ABI support for varargs and function ABI matches those ones. + (true, true) => return, + + // Using this ABI would be ok, if the feature for additional ABI support was enabled. + // Return CONVENTIONS_STABLE, because we want the other error to look the same. + (false, true) => { + feature_err( + &tcx.sess.parse_sess, + sym::extended_varargs_abi_support, span, - E0045, - "C-variadic function must have C or cdecl calling convention" - ); - err.span_label(span, "C-variadics require C or cdecl calling convention").emit(); + UNSTABLE_EXPLAIN, + ) + .emit(); + CONVENTIONS_STABLE } - } + + (false, false) => CONVENTIONS_STABLE, + (true, false) => CONVENTIONS_UNSTABLE, + }; + + let mut err = struct_span_err!(tcx.sess, span, E0045, "{}, like {}", ERROR_HEAD, conventions); + err.span_label(span, ERROR_HEAD).emit(); } fn require_same_types<'tcx>( diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 7f76364e15a..b706d786b52 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -211,13 +211,6 @@ pub(super) fn check_fn<'a, 'tcx>( check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty); } - // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` - if let Some(alloc_error_handler_did) = tcx.lang_items().oom() - && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() - { - check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty); - } - (fcx, gen_ty) } @@ -273,52 +266,3 @@ fn check_panic_info_fn( tcx.sess.span_err(span, "should have no const parameters"); } } - -fn check_alloc_error_fn( - tcx: TyCtxt<'_>, - fn_id: LocalDefId, - fn_sig: ty::FnSig<'_>, - decl: &hir::FnDecl<'_>, - declared_ret_ty: Ty<'_>, -) { - let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else { - tcx.sess.err("language item required, but not found: `alloc_layout`"); - return; - }; - - if *declared_ret_ty.kind() != ty::Never { - tcx.sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - if inputs.len() != 1 { - tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument"); - return; - } - - let arg_is_alloc_layout = match inputs[0].kind() { - ty::Adt(ref adt, _) => adt.did() == alloc_layout_did, - _ => false, - }; - - if !arg_is_alloc_layout { - tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); - } - - let DefKind::Fn = tcx.def_kind(fn_id) else { - let span = tcx.def_span(fn_id); - tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function"); - return; - }; - - let generic_counts = tcx.generics_of(fn_id).own_counts(); - if generic_counts.types != 0 { - let span = tcx.def_span(fn_id); - tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters"); - } - if generic_counts.consts != 0 { - let span = tcx.def_span(fn_id); - tcx.sess - .span_err(span, "`#[alloc_error_handler]` function should have no const parameters"); - } -} diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 175037f9b3a..cfb408396da 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -113,8 +113,9 @@ pub struct MissingParentheseInRange { } #[derive(Subdiagnostic)] -#[multipart_suggestion_verbose( +#[multipart_suggestion( hir_analysis_add_missing_parentheses_in_range, + style = "verbose", applicability = "maybe-incorrect" )] pub struct AddMissingParenthesesInRange { diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 2131d19068e..bb04e1c49ba 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -109,8 +109,9 @@ pub struct InferenceBadError<'a> { #[derive(Subdiagnostic)] pub enum SourceKindSubdiag<'a> { - #[suggestion_verbose( + #[suggestion( infer_source_kind_subdiag_let, + style = "verbose", code = ": {type_name}", applicability = "has-placeholders" )] @@ -135,8 +136,9 @@ pub enum SourceKindSubdiag<'a> { parent_prefix: String, parent_name: String, }, - #[suggestion_verbose( + #[suggestion( infer_source_kind_subdiag_generic_suggestion, + style = "verbose", code = "::<{args}>", applicability = "has-placeholders" )] @@ -150,8 +152,9 @@ pub enum SourceKindSubdiag<'a> { #[derive(Subdiagnostic)] pub enum SourceKindMultiSuggestion<'a> { - #[multipart_suggestion_verbose( + #[multipart_suggestion( infer_source_kind_fully_qualified, + style = "verbose", applicability = "has-placeholders" )] FullyQualified { @@ -163,8 +166,9 @@ pub enum SourceKindMultiSuggestion<'a> { adjustment: &'a str, successor_pos: &'a str, }, - #[multipart_suggestion_verbose( + #[multipart_suggestion( infer_source_kind_closure_return, + style = "verbose", applicability = "has-placeholders" )] ClosureReturn { @@ -478,8 +482,9 @@ pub enum ImplicitStaticLifetimeSubdiag { #[primary_span] span: Span, }, - #[suggestion_verbose( + #[suggestion( infer_implicit_static_lifetime_suggestion, + style = "verbose", code = " + '_", applicability = "maybe-incorrect" )] diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 06ca2534d5c..cbd6481f9cb 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -43,7 +43,7 @@ impl<'tcx> InferCtxt<'tcx> { /// /// This is only meant to be invoked as part of constructing an /// inference context at the start of a query (see - /// `InferCtxtBuilder::enter_with_canonical`). It basically + /// `InferCtxtBuilder::build_with_canonical`). It basically /// brings the canonical value "into scope" within your new infcx. /// /// At the end of processing, the substitution S (once diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index eb8e65a6d59..a03e7b0dae5 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -690,6 +690,7 @@ fn test_unstable_options_tracking_hash() { untracked!(time_llvm_passes, true); untracked!(time_passes, true); untracked!(trace_macros, true); + untracked!(track_diagnostics, true); untracked!(trim_diagnostic_paths, false); untracked!(ui_testing, true); untracked!(unpretty, Some("expanded".to_string())); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index d425adf47f0..27c04d82811 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -40,7 +40,7 @@ use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, Gate use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; -use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind, PredicateOrigin}; +use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin}; use rustc_index::vec::Idx; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::{LayoutError, LayoutOf}; @@ -1423,7 +1423,11 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub { } fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) { - let def_id = cx.tcx.hir().local_def_id(field.hir_id); + let map = cx.tcx.hir(); + let def_id = map.local_def_id(field.hir_id); + if matches!(map.get(map.get_parent_node(field.hir_id)), Node::Variant(_)) { + return; + } self.perform_lint(cx, "field", def_id, field.vis_span, false); } diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index a49d1bdacc2..1a769893f55 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -83,7 +83,7 @@ pub struct UnknownToolInScopedLint { pub struct BuiltinEllpisisInclusiveRangePatterns { #[primary_span] pub span: Span, - #[suggestion_short(code = "{replace}", applicability = "machine-applicable")] + #[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")] pub suggestion: Span, pub replace: String, } diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 00bf287ba6b..7443d131c64 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -150,8 +150,9 @@ struct OpaqueHiddenInferredBoundLint<'tcx> { } #[derive(Subdiagnostic)] -#[suggestion_verbose( +#[suggestion( lint_opaque_hidden_inferred_bound_sugg, + style = "verbose", applicability = "machine-applicable", code = " + {trait_ref}" )] diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 61ee467f595..389f3ccf72a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1983,73 +1983,6 @@ declare_lint! { } declare_lint! { - /// The `proc_macro_derive_resolution_fallback` lint detects proc macro - /// derives using inaccessible names from parent modules. - /// - /// ### Example - /// - /// ```rust,ignore (proc-macro) - /// // foo.rs - /// #![crate_type = "proc-macro"] - /// - /// extern crate proc_macro; - /// - /// use proc_macro::*; - /// - /// #[proc_macro_derive(Foo)] - /// pub fn foo1(a: TokenStream) -> TokenStream { - /// drop(a); - /// "mod __bar { static mut BAR: Option<Something> = None; }".parse().unwrap() - /// } - /// ``` - /// - /// ```rust,ignore (needs-dependency) - /// // bar.rs - /// #[macro_use] - /// extern crate foo; - /// - /// struct Something; - /// - /// #[derive(Foo)] - /// struct Another; - /// - /// fn main() {} - /// ``` - /// - /// This will produce: - /// - /// ```text - /// warning: cannot find type `Something` in this scope - /// --> src/main.rs:8:10 - /// | - /// 8 | #[derive(Foo)] - /// | ^^^ names from parent modules are not accessible without an explicit import - /// | - /// = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default - /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - /// = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504> - /// ``` - /// - /// ### Explanation - /// - /// If a proc-macro generates a module, the compiler unintentionally - /// allowed items in that module to refer to items in the crate root - /// without importing them. This is a [future-incompatible] lint to - /// transition this to a hard error in the future. See [issue #50504] for - /// more details. - /// - /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504 - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - Deny, - "detects proc macro derives using inaccessible names from parent modules", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>", - reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, - }; -} - -declare_lint! { /// The `macro_use_extern_crate` lint detects the use of the /// [`macro_use` attribute]. /// @@ -3287,7 +3220,6 @@ declare_lint_pass! { UNSTABLE_NAME_COLLISIONS, IRREFUTABLE_LET_PATTERNS, WHERE_CLAUSES_OBJECT_SAFETY, - PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, MACRO_USE_EXTERN_CRATE, MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, ILL_FORMED_ATTRIBUTE_INPUT, diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index ef1985b960e..ab38a9ccc8f 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -69,6 +69,8 @@ impl<'a> DiagnosticDerive<'a> { for @Self where G: rustc_errors::EmissionGuarantee { + + #[track_caller] fn into_diagnostic( self, #handler: &'__diagnostic_handler_sess rustc_errors::Handler @@ -133,6 +135,7 @@ impl<'a> LintDiagnosticDerive<'a> { let diag = &builder.diag; structure.gen_impl(quote! { gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self { + #[track_caller] fn decorate_lint<'__b>( self, #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index 860340b4390..78df0cd1d34 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -129,7 +129,7 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// } /// /// #[derive(Subdiagnostic)] -/// #[suggestion_verbose(parser::raw_identifier)] +/// #[suggestion(style = "verbose",parser::raw_identifier)] /// pub struct RawIdentifierSuggestion<'tcx> { /// #[primary_span] /// span: Span, diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 374c795d0a6..ba06f61299f 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -12,7 +12,7 @@ use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple}; use syn::{MetaList, MetaNameValue, NestedMeta, Path}; use synstructure::{BindingInfo, VariantInfo}; -use super::error::invalid_nested_attr; +use super::error::{invalid_attr, invalid_nested_attr}; thread_local! { pub static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0); @@ -472,16 +472,13 @@ pub(super) fn build_suggestion_code( } /// Possible styles for suggestion subdiagnostics. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] pub(super) enum SuggestionKind { - /// `#[suggestion]` Normal, - /// `#[suggestion_short]` Short, - /// `#[suggestion_hidden]` Hidden, - /// `#[suggestion_verbose]` Verbose, + ToolOnly, } impl FromStr for SuggestionKind { @@ -489,15 +486,28 @@ impl FromStr for SuggestionKind { fn from_str(s: &str) -> Result<Self, Self::Err> { match s { - "" => Ok(SuggestionKind::Normal), - "_short" => Ok(SuggestionKind::Short), - "_hidden" => Ok(SuggestionKind::Hidden), - "_verbose" => Ok(SuggestionKind::Verbose), + "normal" => Ok(SuggestionKind::Normal), + "short" => Ok(SuggestionKind::Short), + "hidden" => Ok(SuggestionKind::Hidden), + "verbose" => Ok(SuggestionKind::Verbose), + "tool-only" => Ok(SuggestionKind::ToolOnly), _ => Err(()), } } } +impl fmt::Display for SuggestionKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SuggestionKind::Normal => write!(f, "normal"), + SuggestionKind::Short => write!(f, "short"), + SuggestionKind::Hidden => write!(f, "hidden"), + SuggestionKind::Verbose => write!(f, "verbose"), + SuggestionKind::ToolOnly => write!(f, "tool-only"), + } + } +} + impl SuggestionKind { pub fn to_suggestion_style(&self) -> TokenStream { match self { @@ -513,6 +523,19 @@ impl SuggestionKind { SuggestionKind::Verbose => { quote! { rustc_errors::SuggestionStyle::ShowAlways } } + SuggestionKind::ToolOnly => { + quote! { rustc_errors::SuggestionStyle::CompletelyHidden } + } + } + } + + fn from_suffix(s: &str) -> Option<Self> { + match s { + "" => Some(SuggestionKind::Normal), + "_short" => Some(SuggestionKind::Short), + "_hidden" => Some(SuggestionKind::Hidden), + "_verbose" => Some(SuggestionKind::Verbose), + _ => None, } } } @@ -565,25 +588,49 @@ impl SubdiagnosticKind { let name = name.as_str(); let meta = attr.parse_meta()?; + let mut kind = match name { "label" => SubdiagnosticKind::Label, "note" => SubdiagnosticKind::Note, "help" => SubdiagnosticKind::Help, "warning" => SubdiagnosticKind::Warn, _ => { + // Recover old `#[(multipart_)suggestion_*]` syntaxes + // FIXME(#100717): remove if let Some(suggestion_kind) = - name.strip_prefix("suggestion").and_then(|s| s.parse().ok()) + name.strip_prefix("suggestion").and_then(SuggestionKind::from_suffix) { + if suggestion_kind != SuggestionKind::Normal { + invalid_attr(attr, &meta) + .help(format!( + r#"Use `#[suggestion(..., style = "{}")]` instead"#, + suggestion_kind + )) + .emit(); + } + SubdiagnosticKind::Suggestion { - suggestion_kind, + suggestion_kind: SuggestionKind::Normal, applicability: None, code_field: new_code_ident(), code_init: TokenStream::new(), } } else if let Some(suggestion_kind) = - name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok()) + name.strip_prefix("multipart_suggestion").and_then(SuggestionKind::from_suffix) { - SubdiagnosticKind::MultipartSuggestion { suggestion_kind, applicability: None } + if suggestion_kind != SuggestionKind::Normal { + invalid_attr(attr, &meta) + .help(format!( + r#"Use `#[multipart_suggestion(..., style = "{}")]` instead"#, + suggestion_kind + )) + .emit(); + } + + SubdiagnosticKind::MultipartSuggestion { + suggestion_kind: SuggestionKind::Normal, + applicability: None, + } } else { throw_invalid_attr!(attr, &meta); } @@ -621,6 +668,7 @@ impl SubdiagnosticKind { }; let mut code = None; + let mut suggestion_kind = None; let mut nested_iter = nested.into_iter().peekable(); @@ -682,16 +730,37 @@ impl SubdiagnosticKind { }); applicability.set_once(value, span); } + ( + "style", + SubdiagnosticKind::Suggestion { .. } + | SubdiagnosticKind::MultipartSuggestion { .. }, + ) => { + let Some(value) = string_value else { + invalid_nested_attr(attr, &nested_attr).emit(); + continue; + }; + + let value = value.value().parse().unwrap_or_else(|()| { + span_err(value.span().unwrap(), "invalid suggestion style") + .help("valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`") + .emit(); + SuggestionKind::Normal + }); + + suggestion_kind.set_once(value, span); + } // Invalid nested attribute (_, SubdiagnosticKind::Suggestion { .. }) => { invalid_nested_attr(attr, &nested_attr) - .help("only `code` and `applicability` are valid nested attributes") + .help( + "only `style`, `code` and `applicability` are valid nested attributes", + ) .emit(); } (_, SubdiagnosticKind::MultipartSuggestion { .. }) => { invalid_nested_attr(attr, &nested_attr) - .help("only `applicability` is a valid nested attributes") + .help("only `style` and `applicability` are valid nested attributes") .emit() } _ => { @@ -701,7 +770,16 @@ impl SubdiagnosticKind { } match kind { - SubdiagnosticKind::Suggestion { ref code_field, ref mut code_init, .. } => { + SubdiagnosticKind::Suggestion { + ref code_field, + ref mut code_init, + suggestion_kind: ref mut kind_field, + .. + } => { + if let Some(kind) = suggestion_kind.value() { + *kind_field = kind; + } + *code_init = if let Some(init) = code.value() { init } else { @@ -709,11 +787,17 @@ impl SubdiagnosticKind { quote! { let #code_field = std::iter::empty(); } }; } + SubdiagnosticKind::MultipartSuggestion { + suggestion_kind: ref mut kind_field, .. + } => { + if let Some(kind) = suggestion_kind.value() { + *kind_field = kind; + } + } SubdiagnosticKind::Label | SubdiagnosticKind::Note | SubdiagnosticKind::Help - | SubdiagnosticKind::Warn - | SubdiagnosticKind::MultipartSuggestion { .. } => {} + | SubdiagnosticKind::Warn => {} } Ok(Some((kind, slug))) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index cfcceecbef4..d4c457975a8 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1,8 +1,10 @@ //! Validates all used crates and extern libraries and loads their metadata use crate::errors::{ - ConflictingGlobalAlloc, CrateNotPanicRuntime, GlobalAllocRequired, NoMultipleGlobalAlloc, - NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore, + AllocFuncRequired, ConflictingAllocErrorHandler, ConflictingGlobalAlloc, CrateNotPanicRuntime, + GlobalAllocRequired, MissingAllocErrorHandler, NoMultipleAllocErrorHandler, + NoMultipleGlobalAlloc, NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime, + ProfilerBuiltinsNeedsCore, }; use crate::locator::{CrateError, CrateLocator, CratePaths}; use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob}; @@ -41,8 +43,13 @@ pub struct CStore { /// This crate needs an allocator and either provides it itself, or finds it in a dependency. /// If the above is true, then this field denotes the kind of the found allocator. allocator_kind: Option<AllocatorKind>, + /// This crate needs an allocation error handler and either provides it itself, or finds it in a dependency. + /// If the above is true, then this field denotes the kind of the found allocator. + alloc_error_handler_kind: Option<AllocatorKind>, /// This crate has a `#[global_allocator]` item. has_global_allocator: bool, + /// This crate has a `#[alloc_error_handler]` item. + has_alloc_error_handler: bool, /// This map is used to verify we get no hash conflicts between /// `StableCrateId` values. @@ -197,10 +204,18 @@ impl CStore { self.allocator_kind } + pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> { + self.alloc_error_handler_kind + } + pub(crate) fn has_global_allocator(&self) -> bool { self.has_global_allocator } + pub(crate) fn has_alloc_error_handler(&self) -> bool { + self.has_alloc_error_handler + } + pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) { let json_unused_externs = tcx.sess.opts.json_unused_externs; @@ -247,7 +262,9 @@ impl<'a> CrateLoader<'a> { metas: IndexVec::from_elem_n(None, 1), injected_panic_runtime: None, allocator_kind: None, + alloc_error_handler_kind: None, has_global_allocator: false, + has_alloc_error_handler: false, stable_crate_ids, unused_externs: Vec::new(), }, @@ -792,6 +809,13 @@ impl<'a> CrateLoader<'a> { } spans => !spans.is_empty(), }; + self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) { + [span1, span2, ..] => { + self.sess.emit_err(NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 }); + true + } + spans => !spans.is_empty(), + }; // Check to see if we actually need an allocator. This desire comes // about through the `#![needs_allocator]` attribute and is typically @@ -832,22 +856,48 @@ impl<'a> CrateLoader<'a> { } } } + let mut alloc_error_handler = + self.cstore.has_alloc_error_handler.then(|| Symbol::intern("this crate")); + for (_, data) in self.cstore.iter_crate_data() { + if data.has_alloc_error_handler() { + match alloc_error_handler { + Some(other_crate) => { + self.sess.emit_err(ConflictingAllocErrorHandler { + crate_name: data.name(), + other_crate_name: other_crate, + }); + } + None => alloc_error_handler = Some(data.name()), + } + } + } if global_allocator.is_some() { self.cstore.allocator_kind = Some(AllocatorKind::Global); - return; + } else { + // Ok we haven't found a global allocator but we still need an + // allocator. At this point our allocator request is typically fulfilled + // by the standard library, denoted by the `#![default_lib_allocator]` + // attribute. + if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator) + && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) + { + self.sess.emit_err(GlobalAllocRequired); + } + self.cstore.allocator_kind = Some(AllocatorKind::Default); } - // Ok we haven't found a global allocator but we still need an - // allocator. At this point our allocator request is typically fulfilled - // by the standard library, denoted by the `#![default_lib_allocator]` - // attribute. - if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator) - && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) - { - self.sess.emit_err(GlobalAllocRequired); + if alloc_error_handler.is_some() { + self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global); + } else { + // The alloc crate provides a default allocation error handler if + // one isn't specified. + if !self.sess.features_untracked().default_alloc_error_handler { + self.sess.emit_err(AllocFuncRequired); + self.sess.emit_note(MissingAllocErrorHandler); + } + self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default); } - self.cstore.allocator_kind = Some(AllocatorKind::Default); } fn inject_dependency_if( @@ -1023,3 +1073,26 @@ fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { visit::walk_crate(&mut f, krate); f.spans } + +fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { + struct Finder<'a> { + sess: &'a Session, + name: Symbol, + spans: Vec<Span>, + } + impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> { + fn visit_item(&mut self, item: &'ast ast::Item) { + if item.ident.name == self.name + && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol) + { + self.spans.push(item.span); + } + visit::walk_item(self, item) + } + } + + let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom)); + let mut f = Finder { sess, name, spans: Vec::new() }; + visit::walk_crate(&mut f, krate); + f.spans +} diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 7c387b9a9ec..e5b91d566e5 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -344,6 +344,16 @@ pub struct NoMultipleGlobalAlloc { } #[derive(Diagnostic)] +#[diag(metadata_no_multiple_alloc_error_handler)] +pub struct NoMultipleAllocErrorHandler { + #[primary_span] + #[label] + pub span2: Span, + #[label(metadata_prev_alloc_error_handler)] + pub span1: Span, +} + +#[derive(Diagnostic)] #[diag(metadata_conflicting_global_alloc)] pub struct ConflictingGlobalAlloc { pub crate_name: Symbol, @@ -351,10 +361,25 @@ pub struct ConflictingGlobalAlloc { } #[derive(Diagnostic)] +#[diag(metadata_conflicting_alloc_error_handler)] +pub struct ConflictingAllocErrorHandler { + pub crate_name: Symbol, + pub other_crate_name: Symbol, +} + +#[derive(Diagnostic)] #[diag(metadata_global_alloc_required)] pub struct GlobalAllocRequired; #[derive(Diagnostic)] +#[diag(metadata_alloc_func_required)] +pub struct AllocFuncRequired; + +#[derive(Diagnostic)] +#[diag(metadata_missing_alloc_error_handler)] +pub struct MissingAllocErrorHandler; + +#[derive(Diagnostic)] #[diag(metadata_no_transitive_needs_dep)] pub struct NoTransitiveNeedsDep<'a> { pub crate_name: Symbol, @@ -578,6 +603,7 @@ pub struct InvalidMetadataFiles { } impl IntoDiagnostic<'_> for InvalidMetadataFiles { + #[track_caller] fn into_diagnostic( self, handler: &'_ rustc_errors::Handler, @@ -606,6 +632,7 @@ pub struct CannotFindCrate { } impl IntoDiagnostic<'_> for CannotFindCrate { + #[track_caller] fn into_diagnostic( self, handler: &'_ rustc_errors::Handler, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 691e3d0f8f9..8e80d794a13 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -15,7 +15,6 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc_hir::diagnostic_items::DiagnosticItems; -use rustc_hir::lang_items; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; @@ -967,7 +966,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over the language items in the given crate. - fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { + fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, LangItem)] { tcx.arena.alloc_from_iter( self.root .lang_items @@ -1319,7 +1318,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] { + fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [LangItem] { tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self)) } @@ -1765,6 +1764,10 @@ impl CrateMetadata { self.root.has_global_allocator } + pub(crate) fn has_alloc_error_handler(&self) -> bool { + self.root.has_alloc_error_handler + } + pub(crate) fn has_default_lib_allocator(&self) -> bool { self.root.has_default_lib_allocator } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index a0a0855251b..f475b0b3981 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -255,6 +255,7 @@ provide! { tcx, def_id, other, cdata, is_panic_runtime => { cdata.root.panic_runtime } is_compiler_builtins => { cdata.root.compiler_builtins } has_global_allocator => { cdata.root.has_global_allocator } + has_alloc_error_handler => { cdata.root.has_alloc_error_handler } has_panic_handler => { cdata.root.has_panic_handler } is_profiler_runtime => { cdata.root.profiler_runtime } required_panic_strategy => { cdata.root.required_panic_strategy } @@ -339,6 +340,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // resolve! Does this work? Unsure! That's what the issue is about *providers = Providers { allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(), + alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(), is_private_dep: |_tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); false @@ -464,6 +466,10 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { assert_eq!(cnum, LOCAL_CRATE); CStore::from_tcx(tcx).has_global_allocator() }, + has_alloc_error_handler: |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + CStore::from_tcx(tcx).has_alloc_error_handler() + }, postorder_cnums: |tcx, ()| { tcx.arena .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 049514ec7b2..6a73e14e9f5 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -17,7 +17,7 @@ use rustc_hir::def_id::{ }; use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_middle::hir::nested_filter; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ @@ -670,6 +670,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop, edition: tcx.sess.edition(), has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), + has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE), has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), has_default_lib_allocator: tcx .sess @@ -787,8 +788,7 @@ fn should_encode_attr( } else if attr.doc_str().is_some() { // We keep all public doc comments because they might be "imported" into downstream crates // if they use `#[doc(inline)]` to copy an item's documentation into their own. - *is_def_id_public - .get_or_insert_with(|| tcx.effective_visibilities(()).effective_vis(def_id).is_some()) + *is_def_id_public.get_or_insert_with(|| tcx.effective_visibilities(()).is_exported(def_id)) } else if attr.has_name(sym::doc) { // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can // remove it. It won't be inlinable in downstream crates. @@ -1905,22 +1905,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) } - fn encode_lang_items(&mut self) -> LazyArray<(DefIndex, usize)> { + fn encode_lang_items(&mut self) -> LazyArray<(DefIndex, LangItem)> { empty_proc_macro!(self); - let tcx = self.tcx; - let lang_items = tcx.lang_items(); - let lang_items = lang_items.items().iter(); - self.lazy_array(lang_items.enumerate().filter_map(|(i, &opt_def_id)| { - if let Some(def_id) = opt_def_id { - if def_id.is_local() { - return Some((def_id.index, i)); - } - } - None + let lang_items = self.tcx.lang_items().iter(); + self.lazy_array(lang_items.filter_map(|(lang_item, def_id)| { + def_id.as_local().map(|id| (id.local_def_index, lang_item)) })) } - fn encode_lang_items_missing(&mut self) -> LazyArray<lang_items::LangItem> { + fn encode_lang_items_missing(&mut self) -> LazyArray<LangItem> { empty_proc_macro!(self); let tcx = self.tcx; self.lazy_array(&tcx.lang_items().missing) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 27dc8ff16ac..aa6d378a43a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -12,7 +12,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId}; use rustc_hir::definitions::DefKey; -use rustc_hir::lang_items; +use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::{BitSet, FiniteBitSet}; use rustc_index::vec::IndexVec; use rustc_middle::metadata::ModChild; @@ -223,6 +223,7 @@ pub(crate) struct CrateRoot { panic_in_drop_strategy: PanicStrategy, edition: Edition, has_global_allocator: bool, + has_alloc_error_handler: bool, has_panic_handler: bool, has_default_lib_allocator: bool, @@ -230,8 +231,8 @@ pub(crate) struct CrateRoot { dylib_dependency_formats: LazyArray<Option<LinkagePreference>>, lib_features: LazyArray<(Symbol, Option<Symbol>)>, stability_implications: LazyArray<(Symbol, Symbol)>, - lang_items: LazyArray<(DefIndex, usize)>, - lang_items_missing: LazyArray<lang_items::LangItem>, + lang_items: LazyArray<(DefIndex, LangItem)>, + lang_items_missing: LazyArray<LangItem>, diagnostic_items: LazyArray<(Symbol, DefIndex)>, native_libraries: LazyArray<NativeLib>, foreign_modules: LazyArray<ForeignModule>, diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index a7a7ac0599d..43903e6739f 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -55,3 +55,12 @@ pub struct ConstEvalNonIntError { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(middle_strict_coherence_needs_negative_coherence)] +pub(crate) struct StrictCoherenceNeedsNegativeCoherence { + #[primary_span] + pub span: Span, + #[label] + pub attr_span: Option<Span>, +} diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 31c20fa14aa..dd4332d0db6 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -36,10 +36,6 @@ impl<'tcx> TyCtxt<'tcx> { _ => None, } } - - pub fn is_weak_lang_item(self, item_def_id: DefId) -> bool { - self.lang_items().is_weak_lang_item(item_def_id) - } } /// Returns `true` if the specified `lang_item` must be present for this diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 79db35a764a..068daaadbda 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1186,6 +1186,11 @@ impl<'tcx> BasicBlockData<'tcx> { pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { if index < self.statements.len() { &self.statements[index] } else { &self.terminator } } + + /// Does the block have no statements and an unreachable terminator? + pub fn is_empty_unreachable(&self) -> bool { + self.statements.is_empty() && matches!(self.terminator().kind, TerminatorKind::Unreachable) + } } impl<O> AssertKind<O> { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3d720f09b4f..33acaed435b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1391,6 +1391,13 @@ rustc_queries! { desc { "checking if the crate has_global_allocator" } separate_provide_extern } + query has_alloc_error_handler(_: CrateNum) -> bool { + // This query depends on untracked global state in CStore + eval_always + fatal_cycle + desc { "checking if the crate has_alloc_error_handler" } + separate_provide_extern + } query has_panic_handler(_: CrateNum) -> bool { fatal_cycle desc { "checking if the crate has_panic_handler" } @@ -1705,7 +1712,7 @@ rustc_queries! { } /// Returns the lang items defined in another crate by loading it from metadata. - query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] { + query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, LangItem)] { desc { "calculating the lang items defined in a crate" } separate_provide_extern } @@ -1761,6 +1768,10 @@ rustc_queries! { eval_always desc { "getting the allocator kind for the current crate" } } + query alloc_error_handler_kind(_: ()) -> Option<AllocatorKind> { + eval_always + desc { "alloc error handler kind for the current crate" } + } query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> { desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) } diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index 0a2819feecf..f1c21588261 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -1,3 +1,4 @@ +use crate::error::StrictCoherenceNeedsNegativeCoherence; use crate::ty::fast_reject::SimplifiedType; use crate::ty::visit::TypeVisitable; use crate::ty::{self, TyCtxt}; @@ -65,9 +66,21 @@ impl OverlapMode { if with_negative_coherence { if strict_coherence { OverlapMode::Strict } else { OverlapMode::WithNegative } - } else if strict_coherence { - bug!("To use strict_coherence you need to set with_negative_coherence feature flag"); } else { + if strict_coherence { + let attr_span = trait_id + .as_local() + .into_iter() + .flat_map(|local_def_id| { + tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(local_def_id)) + }) + .find(|attr| attr.has_name(sym::rustc_strict_coherence)) + .map(|attr| attr.span); + tcx.sess.emit_err(StrictCoherenceNeedsNegativeCoherence { + span: tcx.def_span(trait_id), + attr_span, + }); + } OverlapMode::Stable } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3d7e2a0839a..8e24f4813a7 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2456,7 +2456,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_lang_item(self, ty: Ty<'tcx>, item: LangItem) -> Option<Ty<'tcx>> { - let def_id = self.lang_items().require(item).ok()?; + let def_id = self.lang_items().get(item)?; Some(self.mk_generic_adt(def_id, ty)) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ef9aa236bac..f07c60af248 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -63,7 +63,6 @@ thread_local! { static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) }; static NO_QUERIES: Cell<bool> = const { Cell::new(false) }; static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) }; - static NO_VERBOSE_CONSTANTS: Cell<bool> = const { Cell::new(false) }; } macro_rules! define_helper { @@ -118,9 +117,6 @@ define_helper!( /// Prevent selection of visible paths. `Display` impl of DefId will prefer /// visible (public) reexports of types as paths. fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH); - /// Prevent verbose printing of constants. Verbose printing of constants is - /// never desirable in some contexts like `std::any::type_name`. - fn with_no_verbose_constants(NoVerboseConstantsGuard, NO_VERBOSE_CONSTANTS); ); /// The "region highlights" are used to control region printing during @@ -600,7 +596,7 @@ pub trait PrettyPrinter<'tcx>: } ty::FnPtr(ref bare_fn) => p!(print(bare_fn)), ty::Infer(infer_ty) => { - let verbose = self.tcx().sess.verbose(); + let verbose = self.should_print_verbose(); if let ty::TyVar(ty_vid) = infer_ty { if let Some(name) = self.ty_infer_name(ty_vid) { p!(write("{}", name)) @@ -642,7 +638,7 @@ pub trait PrettyPrinter<'tcx>: p!(print_def_path(def_id, &[])); } ty::Projection(ref data) => { - if !(self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get())) + if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get())) && self.tcx().def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder { return self.pretty_print_opaque_impl_type(data.item_def_id, data.substs); @@ -658,7 +654,7 @@ pub trait PrettyPrinter<'tcx>: // only affect certain debug messages (e.g. messages printed // from `rustc_middle::ty` during the computation of `tcx.predicates_of`), // and should have no effect on any compiler output. - if self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get()) { + if self.should_print_verbose() || NO_QUERIES.with(|q| q.get()) { p!(write("Opaque({:?}, {:?})", def_id, substs)); return Ok(self); } @@ -689,7 +685,7 @@ pub trait PrettyPrinter<'tcx>: hir::Movability::Static => p!("static "), } - if !self.tcx().sess.verbose() { + if !self.should_print_verbose() { p!("generator"); // FIXME(eddyb) should use `def_span`. if let Some(did) = did.as_local() { @@ -725,7 +721,7 @@ pub trait PrettyPrinter<'tcx>: } ty::Closure(did, substs) => { p!(write("[")); - if !self.tcx().sess.verbose() { + if !self.should_print_verbose() { p!(write("closure")); // FIXME(eddyb) should use `def_span`. if let Some(did) = did.as_local() { @@ -763,7 +759,7 @@ pub trait PrettyPrinter<'tcx>: } ty::Array(ty, sz) => { p!("[", print(ty), "; "); - if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() { + if self.should_print_verbose() { p!(write("{:?}", sz)); } else if let ty::ConstKind::Unevaluated(..) = sz.kind() { // Do not try to evaluate unevaluated constants. If we are const evaluating an @@ -1077,7 +1073,7 @@ pub trait PrettyPrinter<'tcx>: // Special-case `Fn(...) -> ...` and re-sugar it. let fn_trait_kind = cx.tcx().fn_trait_kind_from_lang_item(principal.def_id); - if !cx.tcx().sess.verbose() && fn_trait_kind.is_some() { + if !cx.should_print_verbose() && fn_trait_kind.is_some() { if let ty::Tuple(tys) = principal.substs.type_at(0).kind() { let mut projections = predicates.projection_bounds(); if let (Some(proj), None) = (projections.next(), projections.next()) { @@ -1185,7 +1181,7 @@ pub trait PrettyPrinter<'tcx>: ) -> Result<Self::Const, Self::Error> { define_scoped_cx!(self); - if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() { + if self.should_print_verbose() { p!(write("Const({:?}: {:?})", ct.kind(), ct.ty())); return Ok(self); } @@ -1420,7 +1416,7 @@ pub trait PrettyPrinter<'tcx>: ) -> Result<Self::Const, Self::Error> { define_scoped_cx!(self); - if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() { + if self.should_print_verbose() { p!(write("ValTree({:?}: ", valtree), print(ty), ")"); return Ok(self); } @@ -1564,6 +1560,10 @@ pub trait PrettyPrinter<'tcx>: Ok(cx) }) } + + fn should_print_verbose(&self) -> bool { + self.tcx().sess.verbose() + } } // HACK(eddyb) boxed to avoid moving around a large struct by-value. @@ -1839,7 +1839,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { } } - let verbose = self.tcx.sess.verbose(); + let verbose = self.should_print_verbose(); disambiguated_data.fmt_maybe_verbose(&mut self, verbose)?; self.empty_path = false; @@ -1940,7 +1940,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { return true; } - if self.tcx.sess.verbose() { + if self.should_print_verbose() { return true; } @@ -2012,7 +2012,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { return Ok(self); } - if self.tcx.sess.verbose() { + if self.should_print_verbose() { p!(write("{:?}", region)); return Ok(self); } @@ -2218,7 +2218,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { // aren't named. Eventually, we might just want this as the default, but // this is not *quite* right and changes the ordering of some output // anyways. - let (new_value, map) = if self.tcx().sess.verbose() { + let (new_value, map) = if self.should_print_verbose() { let regions: Vec<_> = value .bound_vars() .into_iter() diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 3dafdcb7887..5c82fb1ddc0 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -2,6 +2,7 @@ use rustc_index::vec::Idx; use rustc_middle::ty::util::IntTypeExt; +use rustc_target::abi::{Abi, Primitive}; use crate::build::expr::as_place::PlaceBase; use crate::build::expr::category::{Category, RvalueFunc}; @@ -198,6 +199,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let (source, ty) = if let ty::Adt(adt_def, ..) = source.ty.kind() && adt_def.is_enum() { let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx); let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not)); + let layout = this.tcx.layout_of(this.param_env.and(source.ty)); let discr = this.temp(discr_ty, source.span); this.cfg.push_assign( block, @@ -205,8 +207,55 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { discr, Rvalue::Discriminant(temp.into()), ); + let (op,ty) = (Operand::Move(discr), discr_ty); + + if let Abi::Scalar(scalar) = layout.unwrap().abi{ + if let Primitive::Int(_, signed) = scalar.primitive() { + let range = scalar.valid_range(&this.tcx); + // FIXME: Handle wraparound cases too. + if range.end >= range.start { + let mut assumer = |range: u128, bin_op: BinOp| { + // We will be overwriting this val if our scalar is signed value + // because sign extension on unsigned types might cause unintended things + let mut range_val = + ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty)); + let bool_ty = this.tcx.types.bool; + if signed { + let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range); + let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty)); + let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend); + range_val = ConstantKind::from_bits( + this.tcx, + truncated_val, + ty::ParamEnv::empty().and(discr_ty), + ); + } + let lit_op = this.literal_operand(expr.span, range_val); + let is_bin_op = this.temp(bool_ty, expr_span); + this.cfg.push_assign( + block, + source_info, + is_bin_op, + Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))), + ); + this.cfg.push( + block, + Statement { + source_info, + kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume( + Operand::Copy(is_bin_op), + ))), + }, + ) + }; + assumer(range.end, BinOp::Ge); + assumer(range.start, BinOp::Le); + } + } + } + + (op,ty) - (Operand::Move(discr), discr_ty) } else { let ty = source.ty; let source = unpack!( diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index a9e5e438cf5..93a3dd8962a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -79,7 +79,10 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { intravisit::walk_local(self, loc); let els = loc.els; if let Some(init) = loc.init && els.is_some() { - self.check_let(&loc.pat, init, loc.span); + // Build a span without the else { ... } as we don't want to underline + // the entire else block in the IDE setting. + let span = loc.span.with_hi(init.span.hi()); + self.check_let(&loc.pat, init, span); } let (msg, sp) = match loc.source { @@ -630,11 +633,6 @@ fn irrefutable_let_patterns( count: usize, span: Span, ) { - let span = match source { - LetSource::LetElse(span) => span, - _ => span, - }; - macro_rules! emit_diag { ( $lint:expr, @@ -680,7 +678,7 @@ fn irrefutable_let_patterns( "removing the guard and adding a `let` inside the match arm" ); } - LetSource::LetElse(..) => { + LetSource::LetElse => { emit_diag!( lint, "`let...else`", @@ -1127,7 +1125,7 @@ pub enum LetSource { GenericLet, IfLet, IfLetGuard, - LetElse(Span), + LetElse, WhileLet, } @@ -1156,8 +1154,8 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L let parent_parent = hir.get_parent_node(parent); let parent_parent_node = hir.get(parent_parent); match parent_parent_node { - hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) => { - return LetSource::LetElse(*span); + hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), .. }) => { + return LetSource::LetElse; } hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::If(_)), .. }) => { return LetSource::IfLetGuard; diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index f8f04214a2c..959fcf8d89e 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -101,12 +101,10 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { | StatementKind::Retag { .. } | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) + | StatementKind::Intrinsic(..) | StatementKind::Nop => { // safe (at least as emitted during MIR construction) } - - // Move to above list once mir construction uses it. - StatementKind::Intrinsic(..) => unreachable!(), } self.super_statement(statement, location); } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 5be2232547b..4791be1306c 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -288,7 +288,7 @@ fn mir_const<'tcx>( let mut body = tcx.mir_built(def).steal(); - rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(())); + pass_manager::dump_mir_for_phase_change(tcx, &body); pm::run_passes( tcx, diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 4e8798b7a55..bf590674144 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -845,7 +845,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { span, ); - rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(())); + crate::pass_manager::dump_mir_for_phase_change(tcx, &body); body } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index a71218e6997..3cfddd75462 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -201,7 +201,7 @@ use std::iter; use std::ops::Range; use std::path::PathBuf; -use crate::errors::{LargeAssignmentsLint, RecursionLimit, RequiresLangItem, TypeLengthLimit}; +use crate::errors::{LargeAssignmentsLint, RecursionLimit, TypeLengthLimit}; #[derive(PartialEq)] pub enum MonoItemCollectionMode { @@ -1298,14 +1298,7 @@ impl<'v> RootCollector<'_, 'v> { return; }; - let start_def_id = match self.tcx.lang_items().require(LangItem::Start) { - Ok(s) => s, - Err(lang_item_err) => { - self.tcx - .sess - .emit_fatal(RequiresLangItem { lang_item: lang_item_err.0.name().to_string() }); - } - }; + let start_def_id = self.tcx.require_lang_item(LangItem::Start, None); let main_ret_ty = self.tcx.fn_sig(main_def_id).output(); // Given that `main()` has no arguments, diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index ce097b8d846..f1ca72de8db 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -32,12 +32,6 @@ pub struct TypeLengthLimit { pub type_length: usize, } -#[derive(Diagnostic)] -#[diag(monomorphize_requires_lang_item)] -pub struct RequiresLangItem { - pub lang_item: String, -} - pub struct UnusedGenericParams { pub span: Span, pub param_spans: Vec<Span>, @@ -45,6 +39,7 @@ pub struct UnusedGenericParams { } impl IntoDiagnostic<'_> for UnusedGenericParams { + #[track_caller] fn into_diagnostic( self, handler: &'_ rustc_errors::Handler, diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 9b177c5189b..dc204902842 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -64,7 +64,7 @@ pub(crate) struct BadQPathStage2 { #[diag(parser_incorrect_semicolon)] pub(crate) struct IncorrectSemicolon<'a> { #[primary_span] - #[suggestion_short(code = "", applicability = "machine-applicable")] + #[suggestion(style = "short", code = "", applicability = "machine-applicable")] pub span: Span, #[help] pub opt_help: Option<()>, @@ -136,7 +136,12 @@ pub(crate) struct InvalidComparisonOperator { #[derive(Subdiagnostic)] pub(crate) enum InvalidComparisonOperatorSub { - #[suggestion_short(use_instead, applicability = "machine-applicable", code = "{correct}")] + #[suggestion( + use_instead, + style = "short", + applicability = "machine-applicable", + code = "{correct}" + )] Correctable { #[primary_span] span: Span, @@ -160,14 +165,16 @@ pub(crate) struct InvalidLogicalOperator { #[derive(Subdiagnostic)] pub(crate) enum InvalidLogicalOperatorSub { - #[suggestion_short( + #[suggestion( use_amp_amp_for_conjunction, + style = "short", applicability = "machine-applicable", code = "&&" )] Conjunction(#[primary_span] Span), - #[suggestion_short( + #[suggestion( use_pipe_pipe_for_disjunction, + style = "short", applicability = "machine-applicable", code = "||" )] @@ -178,7 +185,7 @@ pub(crate) enum InvalidLogicalOperatorSub { #[diag(parser_tilde_is_not_unary_operator)] pub(crate) struct TildeAsUnaryOperator( #[primary_span] - #[suggestion_short(applicability = "machine-applicable", code = "!")] + #[suggestion(style = "short", applicability = "machine-applicable", code = "!")] pub Span, ); @@ -194,22 +201,25 @@ pub(crate) struct NotAsNegationOperator { #[derive(Subdiagnostic)] pub enum NotAsNegationOperatorSub { - #[suggestion_short( + #[suggestion( parser_unexpected_token_after_not_default, + style = "short", applicability = "machine-applicable", code = "!" )] SuggestNotDefault(#[primary_span] Span), - #[suggestion_short( + #[suggestion( parser_unexpected_token_after_not_bitwise, + style = "short", applicability = "machine-applicable", code = "!" )] SuggestNotBitwise(#[primary_span] Span), - #[suggestion_short( + #[suggestion( parser_unexpected_token_after_not_logical, + style = "short", applicability = "machine-applicable", code = "!" )] @@ -249,7 +259,7 @@ pub(crate) struct UnexpectedTokenAfterLabel { #[primary_span] #[label(parser_unexpected_token_after_label)] pub span: Span, - #[suggestion_verbose(suggestion_remove_label, code = "")] + #[suggestion(suggestion_remove_label, style = "verbose", code = "")] pub remove_label: Option<Span>, #[subdiagnostic] pub enclose_in_block: Option<UnexpectedTokenAfterLabelSugg>, @@ -272,7 +282,7 @@ pub(crate) struct RequireColonAfterLabeledExpression { pub span: Span, #[label] pub label: Span, - #[suggestion_short(applicability = "machine-applicable", code = ": ")] + #[suggestion(style = "short", applicability = "machine-applicable", code = ": ")] pub label_end: Span, } @@ -354,7 +364,7 @@ pub(crate) struct IntLiteralTooLarge { pub(crate) struct MissingSemicolonBeforeArray { #[primary_span] pub open_delim: Span, - #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")] + #[suggestion(style = "verbose", applicability = "maybe-incorrect", code = ";")] pub semicolon: Span, } @@ -442,9 +452,9 @@ pub(crate) struct MissingInInForLoop { #[derive(Subdiagnostic)] pub(crate) enum MissingInInForLoopSub { // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect - #[suggestion_short(use_in_not_of, applicability = "maybe-incorrect", code = "in")] + #[suggestion(use_in_not_of, style = "short", applicability = "maybe-incorrect", code = "in")] InNotOf(#[primary_span] Span), - #[suggestion_short(add_in, applicability = "maybe-incorrect", code = " in ")] + #[suggestion(add_in, style = "short", applicability = "maybe-incorrect", code = " in ")] AddIn(#[primary_span] Span), } @@ -470,7 +480,7 @@ pub(crate) struct CatchAfterTry { pub(crate) struct CommaAfterBaseStruct { #[primary_span] pub span: Span, - #[suggestion_short(applicability = "machine-applicable", code = "")] + #[suggestion(style = "short", applicability = "machine-applicable", code = "")] pub comma: Span, } @@ -512,7 +522,7 @@ pub(crate) struct RemoveLet { #[diag(parser_use_eq_instead)] pub(crate) struct UseEqInstead { #[primary_span] - #[suggestion_short(applicability = "machine-applicable", code = "=")] + #[suggestion(style = "short", applicability = "machine-applicable", code = "=")] pub span: Span, } @@ -520,7 +530,7 @@ pub(crate) struct UseEqInstead { #[diag(parser_use_empty_block_not_semi)] pub(crate) struct UseEmptyBlockNotSemi { #[primary_span] - #[suggestion_hidden(applicability = "machine-applicable", code = "{{}}")] + #[suggestion(style = "hidden", applicability = "machine-applicable", code = "{{}}")] pub span: Span, } @@ -576,7 +586,12 @@ pub(crate) struct LeadingPlusNotSupported { #[primary_span] #[label] pub span: Span, - #[suggestion_verbose(suggestion_remove_plus, code = "", applicability = "machine-applicable")] + #[suggestion( + suggestion_remove_plus, + style = "verbose", + code = "", + applicability = "machine-applicable" + )] pub remove_plus: Option<Span>, #[subdiagnostic] pub add_parentheses: Option<ExprParenthesesNeeded>, @@ -843,7 +858,7 @@ pub(crate) struct InvalidCurlyInLetElse { #[help] pub(crate) struct CompoundAssignmentExpressionInLet { #[primary_span] - #[suggestion_short(code = "=", applicability = "maybe-incorrect")] + #[suggestion(style = "short", code = "=", applicability = "maybe-incorrect")] pub span: Span, } @@ -864,8 +879,9 @@ pub(crate) struct InvalidMetaItem { } #[derive(Subdiagnostic)] -#[suggestion_verbose( +#[suggestion( parser_sugg_escape_to_use_as_identifier, + style = "verbose", applicability = "maybe-incorrect", code = "r#" )] @@ -918,6 +934,7 @@ pub(crate) struct ExpectedIdentifier { } impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { + #[track_caller] fn into_diagnostic( self, handler: &'a rustc_errors::Handler, @@ -963,6 +980,7 @@ pub(crate) struct ExpectedSemi { } impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi { + #[track_caller] fn into_diagnostic( self, handler: &'a rustc_errors::Handler, @@ -1003,7 +1021,12 @@ pub(crate) enum ExpectedSemiSugg { applicability = "machine-applicable" )] ChangeToSemi(#[primary_span] Span), - #[suggestion_short(parser_sugg_add_semi, code = ";", applicability = "machine-applicable")] + #[suggestion( + parser_sugg_add_semi, + style = "short", + code = ";", + applicability = "machine-applicable" + )] AddSemi(#[primary_span] Span), } @@ -1057,8 +1080,9 @@ pub(crate) struct GenericParamsWithoutAngleBracketsSugg { pub(crate) struct ComparisonOperatorsCannotBeChained { #[primary_span] pub span: Vec<Span>, - #[suggestion_verbose( + #[suggestion( parser_sugg_turbofish_syntax, + style = "verbose", code = "::", applicability = "maybe-incorrect" )] @@ -1072,8 +1096,9 @@ pub(crate) struct ComparisonOperatorsCannotBeChained { #[derive(Subdiagnostic)] pub(crate) enum ComparisonOperatorsCannotBeChainedSugg { - #[suggestion_verbose( + #[suggestion( sugg_split_comparison, + style = "verbose", code = " && {middle_term}", applicability = "maybe-incorrect" )] @@ -1215,7 +1240,7 @@ pub(crate) enum UnexpectedConstParamDeclarationSugg { pub(crate) struct UnexpectedConstInGenericParam { #[primary_span] pub span: Span, - #[suggestion_verbose(code = "", applicability = "maybe-incorrect")] + #[suggestion(style = "verbose", code = "", applicability = "maybe-incorrect")] pub to_remove: Option<Span>, } @@ -1223,7 +1248,7 @@ pub(crate) struct UnexpectedConstInGenericParam { #[diag(parser_async_move_order_incorrect)] pub(crate) struct AsyncMoveOrderIncorrect { #[primary_span] - #[suggestion_verbose(code = "async move", applicability = "maybe-incorrect")] + #[suggestion(style = "verbose", code = "async move", applicability = "maybe-incorrect")] pub span: Span, } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 753d01f46ca..b779edbc30f 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -470,11 +470,6 @@ fn has_allow_dead_code_or_lang_attr_helper( return true; } - // (To be) stable attribute for #[lang = "oom"] - if tcx.sess.contains_name(attrs, sym::alloc_error_handler) { - return true; - } - let def_id = tcx.hir().local_def_id(id); if tcx.def_kind(def_id).has_codegen_attrs() { let cg_attrs = tcx.codegen_fn_attrs(def_id); diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index adaaf539242..fb883ae2ed0 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -291,7 +291,7 @@ pub struct DocTestUnknownAny { #[note(no_op_note)] pub struct DocTestUnknownSpotlight { pub path: String, - #[suggestion_short(applicability = "machine-applicable", code = "notable_trait")] + #[suggestion(style = "short", applicability = "machine-applicable", code = "notable_trait")] pub span: Span, } @@ -702,14 +702,6 @@ pub struct UnknownExternLangItem { pub struct MissingPanicHandler; #[derive(Diagnostic)] -#[diag(passes_alloc_func_required)] -pub struct AllocFuncRequired; - -#[derive(Diagnostic)] -#[diag(passes_missing_alloc_error_handler)] -pub struct MissingAllocErrorHandler; - -#[derive(Diagnostic)] #[diag(passes_missing_lang_item)] #[note] #[help] @@ -744,6 +736,7 @@ pub struct InvalidAttrAtCrateLevel { } impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { + #[track_caller] fn into_diagnostic( self, handler: &'_ rustc_errors::Handler, @@ -876,6 +869,7 @@ pub struct BreakNonLoop<'a> { } impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> { + #[track_caller] fn into_diagnostic( self, handler: &rustc_errors::Handler, @@ -1013,6 +1007,7 @@ pub struct NakedFunctionsAsmBlock { } impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock { + #[track_caller] fn into_diagnostic( self, handler: &rustc_errors::Handler, @@ -1136,6 +1131,7 @@ pub struct NoMainErr { } impl<'a> IntoDiagnostic<'a> for NoMainErr { + #[track_caller] fn into_diagnostic( self, handler: &'a rustc_errors::Handler, @@ -1196,6 +1192,7 @@ pub struct DuplicateLangItem { } impl IntoDiagnostic<'_> for DuplicateLangItem { + #[track_caller] fn into_diagnostic( self, handler: &rustc_errors::Handler, diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index df811be2a7e..188efc528ef 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -16,7 +16,7 @@ use crate::weak_lang_items; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS}; +use rustc_hir::lang_items::{extract, GenericRequirement}; use rustc_hir::{HirId, LangItem, LanguageItems, Target}; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::ExternCrate; @@ -43,17 +43,17 @@ impl<'tcx> LanguageItemCollector<'tcx> { fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) { let attrs = self.tcx.hir().attrs(hir_id); if let Some((name, span)) = extract(&attrs) { - match ITEM_REFS.get(&name).cloned() { + match LangItem::from_name(name) { // Known lang item with attribute on correct target. - Some((item_index, expected_target)) if actual_target == expected_target => { - self.collect_item_extended(item_index, hir_id, span); + Some(lang_item) if actual_target == lang_item.target() => { + self.collect_item_extended(lang_item, hir_id, span); } // Known lang item with attribute on incorrect target. - Some((_, expected_target)) => { + Some(lang_item) => { self.tcx.sess.emit_err(LangItemOnIncorrectTarget { span, name, - expected_target, + expected_target: lang_item.target(), actual_target, }); } @@ -65,12 +65,12 @@ impl<'tcx> LanguageItemCollector<'tcx> { } } - fn collect_item(&mut self, item_index: usize, item_def_id: DefId) { + fn collect_item(&mut self, lang_item: LangItem, item_def_id: DefId) { // Check for duplicates. - if let Some(original_def_id) = self.items.items[item_index] { + if let Some(original_def_id) = self.items.get(lang_item) { if original_def_id != item_def_id { let local_span = self.tcx.hir().span_if_local(item_def_id); - let lang_item_name = LangItem::from_u32(item_index as u32).unwrap().name(); + let lang_item_name = lang_item.name(); let crate_name = self.tcx.crate_name(item_def_id.krate); let mut dependency_of = Empty; let is_local = item_def_id.is_local(); @@ -139,17 +139,13 @@ impl<'tcx> LanguageItemCollector<'tcx> { } // Matched. - self.items.items[item_index] = Some(item_def_id); - if let Some(group) = LangItem::from_u32(item_index as u32).unwrap().group() { - self.items.groups[group as usize].push(item_def_id); - } + self.items.set(lang_item, item_def_id); } // Like collect_item() above, but also checks whether the lang item is declared // with the right number of generic arguments. - fn collect_item_extended(&mut self, item_index: usize, hir_id: HirId, span: Span) { + fn collect_item_extended(&mut self, lang_item: LangItem, hir_id: HirId, span: Span) { let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id(); - let lang_item = LangItem::from_u32(item_index as u32).unwrap(); let name = lang_item.name(); // Now check whether the lang_item has the expected number of generic @@ -197,7 +193,7 @@ impl<'tcx> LanguageItemCollector<'tcx> { } } - self.collect_item(item_index, item_def_id); + self.collect_item(lang_item, item_def_id); } } @@ -208,8 +204,8 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { // Collect lang items in other crates. for &cnum in tcx.crates(()).iter() { - for &(def_id, item_index) in tcx.defined_lang_items(cnum).iter() { - collector.collect_item(item_index, def_id); + for &(def_id, lang_item) in tcx.defined_lang_items(cnum).iter() { + collector.collect_item(lang_item, def_id); } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 10d5fc5d671..73ea06a6370 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -380,11 +380,9 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> { }) .collect::<Vec<_>>(); - for item in tcx.lang_items().items().iter() { - if let Some(def_id) = *item { - if let Some(def_id) = def_id.as_local() { - reachable_context.worklist.push(def_id); - } + for (_, def_id) in tcx.lang_items().iter() { + if let Some(def_id) = def_id.as_local() { + reachable_context.worklist.push(def_id); } } { diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 959ee600c07..f0815fcd8db 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -2,15 +2,12 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::lang_items::{self, LangItem}; -use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS; +use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; -use crate::errors::{ - AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler, - UnknownExternLangItem, -}; +use crate::errors::{MissingLangItem, MissingPanicHandler, UnknownExternLangItem}; /// Checks the crate for usage of weak lang items, returning a vector of all the /// language items required by this crate, but not defined yet. @@ -29,8 +26,8 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem for id in crate_items.foreign_items() { let attrs = tcx.hir().attrs(id.hir_id()); if let Some((lang_item, _)) = lang_items::extract(attrs) { - if let Some(&item) = WEAK_ITEMS_REFS.get(&lang_item) { - if items.require(item).is_err() { + if let Some(item) = LangItem::from_name(lang_item) && item.is_weak() { + if items.get(item).is_none() { items.missing.push(item); } } else { @@ -65,17 +62,12 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { } } - for (name, &item) in WEAK_ITEMS_REFS.iter() { - if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() { + for &item in WEAK_LANG_ITEMS.iter() { + if missing.contains(&item) && required(tcx, item) && items.get(item).is_none() { if item == LangItem::PanicImpl { tcx.sess.emit_err(MissingPanicHandler); - } else if item == LangItem::Oom { - if !tcx.features().default_alloc_error_handler { - tcx.sess.emit_err(AllocFuncRequired); - tcx.sess.emit_note(MissingAllocErrorHandler); - } } else { - tcx.sess.emit_err(MissingLangItem { name: *name }); + tcx.sess.emit_err(MissingLangItem { name: item.name() }); } } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index a17793ecd99..423c5727533 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -56,21 +56,7 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a> impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Res(self.0, false), - ambiguity: None, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - -struct IsMacroExport; - -impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId, IsMacroExport) { - fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { - arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Res(self.0, true), + kind: NameBindingKind::Res(self.0), ambiguity: None, vis: self.1.to_def_id(), span: self.2, @@ -364,7 +350,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { module_path: Vec<Segment>, kind: ImportKind<'a>, span: Span, - id: NodeId, item: &ast::Item, root_span: Span, root_id: NodeId, @@ -377,7 +362,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { module_path, imported_module: Cell::new(None), span, - id, use_span: item.span, use_span_with_attributes: item.span_with_attributes(), has_attributes: !item.attrs.is_empty(), @@ -574,27 +558,20 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }, type_ns_only, nested, + id, additional_ids: (id1, id2), }; - self.add_import( - module_path, - kind, - use_tree.span, - id, - item, - root_span, - item.id, - vis, - ); + self.add_import(module_path, kind, use_tree.span, item, root_span, item.id, vis); } ast::UseTreeKind::Glob => { let kind = ImportKind::Glob { is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import), max_vis: Cell::new(None), + id, }; self.r.visibilities.insert(self.r.local_def_id(id), vis); - self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis); + self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis); } ast::UseTreeKind::Nested(ref items) => { // Ensure there is at most one `self` in the list @@ -881,9 +858,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }) .unwrap_or((true, None, self.r.dummy_binding)); let import = self.r.arenas.alloc_import(Import { - kind: ImportKind::ExternCrate { source: orig_name, target: ident }, + kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id }, root_id: item.id, - id: item.id, parent_scope: self.parent_scope, imported_module: Cell::new(module), has_attributes: !item.attrs.is_empty(), @@ -1118,7 +1094,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { this.r.arenas.alloc_import(Import { kind: ImportKind::MacroUse, root_id: item.id, - id: item.id, parent_scope: this.parent_scope, imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), use_span_with_attributes: item.span_with_attributes(), @@ -1278,8 +1253,22 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); self.r.set_binding_parent_module(binding, parent_scope.module); if is_macro_export { - let module = self.r.graph_root; - self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport)); + let import = self.r.arenas.alloc_import(Import { + kind: ImportKind::MacroExport, + root_id: item.id, + parent_scope: self.parent_scope, + imported_module: Cell::new(None), + has_attributes: false, + use_span_with_attributes: span, + use_span: span, + root_span: span, + span: span, + module_path: Vec::new(), + vis: Cell::new(Some(vis)), + used: Cell::new(true), + }); + let import_binding = self.r.import(binding, import); + self.r.define(self.r.graph_root, ident, MacroNS, import_binding); } else { self.r.check_reserved_macro_name(ident, res); self.insert_unused_macro(ident, def_id, item.id, &rule_spans); diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 01c3801f223..32fb5e18276 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -234,7 +234,7 @@ impl Resolver<'_> { if !import.span.is_dummy() { self.lint_buffer.buffer_lint( MACRO_USE_EXTERN_CRATE, - import.id, + import.root_id, import.span, "deprecated `#[macro_use]` attribute used to \ import macros should be replaced at use sites \ @@ -244,13 +244,13 @@ impl Resolver<'_> { } } } - ImportKind::ExternCrate { .. } => { - let def_id = self.local_def_id(import.id); + ImportKind::ExternCrate { id, .. } => { + let def_id = self.local_def_id(id); self.maybe_unused_extern_crates.push((def_id, import.span)); } ImportKind::MacroUse => { let msg = "unused `#[macro_use]` import"; - self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg); + self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.root_id, import.span, msg); } _ => {} } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5029c339963..7961e3f1194 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -190,12 +190,12 @@ impl<'a> Resolver<'a> { ModuleKind::Block => "block", }; - let old_noun = match old_binding.is_import() { + let old_noun = match old_binding.is_import_user_facing() { true => "import", false => "definition", }; - let new_participle = match new_binding.is_import() { + let new_participle = match new_binding.is_import_user_facing() { true => "imported", false => "defined", }; @@ -226,7 +226,7 @@ impl<'a> Resolver<'a> { true => struct_span_err!(self.session, span, E0254, "{}", msg), false => struct_span_err!(self.session, span, E0260, "{}", msg), }, - _ => match (old_binding.is_import(), new_binding.is_import()) { + _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) { (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg), (true, true) => struct_span_err!(self.session, span, E0252, "{}", msg), _ => struct_span_err!(self.session, span, E0255, "{}", msg), @@ -248,14 +248,18 @@ impl<'a> Resolver<'a> { // See https://github.com/rust-lang/rust/issues/32354 use NameBindingKind::Import; + let can_suggest = |binding: &NameBinding<'_>, import: &self::Import<'_>| { + !binding.span.is_dummy() + && !matches!(import.kind, ImportKind::MacroUse | ImportKind::MacroExport) + }; let import = match (&new_binding.kind, &old_binding.kind) { // If there are two imports where one or both have attributes then prefer removing the // import without attributes. (Import { import: new, .. }, Import { import: old, .. }) if { - !new_binding.span.is_dummy() - && !old_binding.span.is_dummy() - && (new.has_attributes || old.has_attributes) + (new.has_attributes || old.has_attributes) + && can_suggest(old_binding, old) + && can_suggest(new_binding, new) } => { if old.has_attributes { @@ -265,10 +269,10 @@ impl<'a> Resolver<'a> { } } // Otherwise prioritize the new binding. - (Import { import, .. }, other) if !new_binding.span.is_dummy() => { + (Import { import, .. }, other) if can_suggest(new_binding, import) => { Some((import, new_binding.span, other.is_import())) } - (other, Import { import, .. }) if !old_binding.span.is_dummy() => { + (other, Import { import, .. }) if can_suggest(old_binding, import) => { Some((import, old_binding.span, other.is_import())) } _ => None, @@ -353,7 +357,7 @@ impl<'a> Resolver<'a> { } } } - ImportKind::ExternCrate { source, target } => { + ImportKind::ExternCrate { source, target, .. } => { suggestion = Some(format!( "extern crate {} as {};", source.unwrap_or(target.name), @@ -1202,7 +1206,7 @@ impl<'a> Resolver<'a> { let root_module = this.resolve_crate_root(root_ident); this.add_module_candidates(root_module, &mut suggestions, filter_fn, None); } - Scope::Module(module, _) => { + Scope::Module(module) => { this.add_module_candidates(module, &mut suggestions, filter_fn, None); } Scope::MacroUsePrelude => { @@ -1683,7 +1687,7 @@ impl<'a> Resolver<'a> { let a = if built_in.is_empty() { res.article() } else { "a" }; format!("{a}{built_in} {thing}{from}", thing = res.descr()) } else { - let introduced = if b.is_import() { "imported" } else { "defined" }; + let introduced = if b.is_import_user_facing() { "imported" } else { "defined" }; format!("the {thing} {introduced} here", thing = res.descr()) } } @@ -1742,10 +1746,10 @@ impl<'a> Resolver<'a> { /// If the binding refers to a tuple struct constructor with fields, /// returns the span of its fields. fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option<Span> { - if let NameBindingKind::Res( - Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id), - _, - ) = binding.kind + if let NameBindingKind::Res(Res::Def( + DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), + ctor_def_id, + )) = binding.kind { let def_id = self.parent(ctor_def_id); let fields = self.field_names.get(&def_id)?; @@ -1789,7 +1793,9 @@ impl<'a> Resolver<'a> { next_ident = source; Some(binding) } - ImportKind::Glob { .. } | ImportKind::MacroUse => Some(binding), + ImportKind::Glob { .. } | ImportKind::MacroUse | ImportKind::MacroExport => { + Some(binding) + } ImportKind::ExternCrate { .. } => None, }, _ => None, diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index c40669ac95b..17ce854cb43 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -57,26 +57,45 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { while let NameBindingKind::Import { binding: nested_binding, import, .. } = binding.kind { - let mut update = |node_id| self.update( - self.r.local_def_id(node_id), - binding.vis.expect_local(), - prev_parent_id, - level, - ); - // In theory all the import IDs have individual visibilities and effective - // visibilities, but in practice these IDs go straigth to HIR where all - // their few uses assume that their (effective) visibility applies to the - // whole syntactic `use` item. So we update them all to the maximum value - // among the potential individual effective visibilities. Maybe HIR for - // imports shouldn't use three IDs at all. - update(import.id); - if let ImportKind::Single { additional_ids, .. } = import.kind { - update(additional_ids.0); - update(additional_ids.1); + let mut update = |node_id| { + self.update( + self.r.local_def_id(node_id), + binding.vis.expect_local(), + prev_parent_id, + level, + ) + }; + match import.kind { + ImportKind::Single { id, additional_ids, .. } => { + // In theory all the import IDs have individual visibilities and + // effective visibilities, but in practice these IDs go straigth to + // HIR where all their few uses assume that their (effective) + // visibility applies to the whole syntactic `use` item. So we + // update them all to the maximum value among the potential + // individual effective visibilities. Maybe HIR for imports + // shouldn't use three IDs at all. + update(id); + update(additional_ids.0); + update(additional_ids.1); + prev_parent_id = self.r.local_def_id(id); + } + ImportKind::Glob { id, .. } | ImportKind::ExternCrate { id, .. } => { + update(id); + prev_parent_id = self.r.local_def_id(id); + } + ImportKind::MacroUse => { + // In theory we should reset the parent id to something private + // here, but `macro_use` imports always refer to external items, + // so it doesn't matter and we can just do nothing. + } + ImportKind::MacroExport => { + // In theory we should reset the parent id to something public + // here, but it has the same effect as leaving the previous parent, + // so we can just do nothing. + } } level = Level::Reexported; - prev_parent_id = self.r.local_def_id(import.id); binding = nested_binding; } } @@ -138,13 +157,6 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> { self.update(def_id, Visibility::Public, parent_id, Level::Direct); } - // Only exported `macro_rules!` items are public, but they always are - ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => { - let parent_id = self.r.local_parent(def_id); - let vis = self.r.visibilities[&def_id]; - self.update(def_id, vis, parent_id, Level::Direct); - } - ast::ItemKind::Mod(..) => { self.set_bindings_effective_visibilities(def_id); visit::walk_item(self, item); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e0542d5479f..0c4b35b8833 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1,11 +1,9 @@ -use rustc_ast::{self as ast, NodeId}; +use rustc_ast as ast; use rustc_feature::is_builtin_attr_name; use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::PrimTy; use rustc_middle::bug; use rustc_middle::ty; -use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; -use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::def_id::LocalDefId; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; @@ -19,7 +17,7 @@ use crate::late::{ }; use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; -use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{Import, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res}; use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak}; @@ -101,7 +99,7 @@ impl<'a> Resolver<'a> { }; let mut scope = match ns { _ if is_absolute_path => Scope::CrateRoot, - TypeNS | ValueNS => Scope::Module(module, None), + TypeNS | ValueNS => Scope::Module(module), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; let mut ctxt = ctxt.normalize_to_macros_2_0(); @@ -165,7 +163,7 @@ impl<'a> Resolver<'a> { MacroRulesScope::Invocation(invoc_id) => { Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) } - MacroRulesScope::Empty => Scope::Module(module, None), + MacroRulesScope::Empty => Scope::Module(module), }, Scope::CrateRoot => match ns { TypeNS => { @@ -174,16 +172,10 @@ impl<'a> Resolver<'a> { } ValueNS | MacroNS => break, }, - Scope::Module(module, prev_lint_id) => { + Scope::Module(module) => { use_prelude = !module.no_implicit_prelude; - let derive_fallback_lint_id = match scope_set { - ScopeSet::Late(.., lint_id) => lint_id, - _ => None, - }; - match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { - Some((parent_module, lint_id)) => { - Scope::Module(parent_module, lint_id.or(prev_lint_id)) - } + match self.hygienic_lexical_parent(module, &mut ctxt) { + Some(parent_module) => Scope::Module(parent_module), None => { ctxt.adjust(ExpnId::root()); match ns { @@ -215,45 +207,13 @@ impl<'a> Resolver<'a> { &mut self, module: Module<'a>, ctxt: &mut SyntaxContext, - derive_fallback_lint_id: Option<NodeId>, - ) -> Option<(Module<'a>, Option<NodeId>)> { + ) -> Option<Module<'a>> { if !module.expansion.outer_expn_is_descendant_of(*ctxt) { - return Some((self.expn_def_scope(ctxt.remove_mark()), None)); + return Some(self.expn_def_scope(ctxt.remove_mark())); } if let ModuleKind::Block = module.kind { - return Some((module.parent.unwrap().nearest_item_scope(), None)); - } - - // We need to support the next case under a deprecation warning - // ``` - // struct MyStruct; - // ---- begin: this comes from a proc macro derive - // mod implementation_details { - // // Note that `MyStruct` is not in scope here. - // impl SomeTrait for MyStruct { ... } - // } - // ---- end - // ``` - // So we have to fall back to the module's parent during lexical resolution in this case. - if derive_fallback_lint_id.is_some() { - if let Some(parent) = module.parent { - // Inner module is inside the macro, parent module is outside of the macro. - if module.expansion != parent.expansion - && module.expansion.is_descendant_of(parent.expansion) - { - // The macro is a proc macro derive - if let Some(def_id) = module.expansion.expn_data().macro_def_id { - let ext = self.get_macro_by_def_id(def_id).ext; - if ext.builtin_name.is_none() - && ext.macro_kind() == MacroKind::Derive - && parent.expansion.outer_expn_is_descendant_of(*ctxt) - { - return Some((parent, derive_fallback_lint_id)); - } - } - } - } + return Some(module.parent.unwrap().nearest_item_scope()); } None @@ -510,7 +470,7 @@ impl<'a> Resolver<'a> { Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), } } - Scope::Module(module, derive_fallback_lint_id) => { + Scope::Module(module) => { let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; let binding = this.resolve_ident_in_module_unadjusted_ext( ModuleOrUniformRoot::Module(module), @@ -523,21 +483,6 @@ impl<'a> Resolver<'a> { ); match binding { Ok(binding) => { - if let Some(lint_id) = derive_fallback_lint_id { - this.lint_buffer.buffer_lint_with_diagnostic( - PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - lint_id, - orig_ident.span, - &format!( - "cannot find {} `{}` in this scope", - ns.descr(), - ident - ), - BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback( - orig_ident.span, - ), - ); - } let misc_flags = if ptr::eq(module, this.graph_root) { Flags::MISC_SUGGEST_CRATE } else if module.is_normal() { @@ -915,7 +860,11 @@ impl<'a> Resolver<'a> { } if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT { - if let NameBindingKind::Res(_, true) = binding.kind { + if let NameBindingKind::Import { + import: Import { kind: ImportKind::MacroExport, .. }, + .. + } = binding.kind + { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index f2cc50c199f..bdb852548b8 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -44,20 +44,36 @@ pub enum ImportKind<'a> { type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` nested: bool, + /// The ID of the `UseTree` that imported this `Import`. + /// + /// In the case where the `Import` was expanded from a "nested" use tree, + /// this id is the ID of the leaf tree. For example: + /// + /// ```ignore (pacify the merciless tidy) + /// use foo::bar::{a, b} + /// ``` + /// + /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree` + /// for `a` in this field. + id: NodeId, /// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement /// (eg. implicit struct constructors) additional_ids: (NodeId, NodeId), }, Glob { is_prelude: bool, - max_vis: Cell<Option<ty::Visibility>>, // The visibility of the greatest re-export. - // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. + // The visibility of the greatest re-export. + // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. + max_vis: Cell<Option<ty::Visibility>>, + id: NodeId, }, ExternCrate { source: Option<Symbol>, target: Ident, + id: NodeId, }, MacroUse, + MacroExport, } /// Manually implement `Debug` for `ImportKind` because the `source/target_bindings` @@ -71,6 +87,7 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { ref target, ref type_ns_only, ref nested, + ref id, ref additional_ids, // Ignore the following to avoid an infinite loop while printing. source_bindings: _, @@ -81,19 +98,23 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { .field("target", target) .field("type_ns_only", type_ns_only) .field("nested", nested) + .field("id", id) .field("additional_ids", additional_ids) .finish_non_exhaustive(), - Glob { ref is_prelude, ref max_vis } => f + Glob { ref is_prelude, ref max_vis, ref id } => f .debug_struct("Glob") .field("is_prelude", is_prelude) .field("max_vis", max_vis) + .field("id", id) .finish(), - ExternCrate { ref source, ref target } => f + ExternCrate { ref source, ref target, ref id } => f .debug_struct("ExternCrate") .field("source", source) .field("target", target) + .field("id", id) .finish(), MacroUse => f.debug_struct("MacroUse").finish(), + MacroExport => f.debug_struct("MacroExport").finish(), } } } @@ -103,24 +124,15 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { pub(crate) struct Import<'a> { pub kind: ImportKind<'a>, - /// The ID of the `extern crate`, `UseTree` etc that imported this `Import`. - /// - /// In the case where the `Import` was expanded from a "nested" use tree, - /// this id is the ID of the leaf tree. For example: - /// - /// ```ignore (pacify the merciless tidy) + /// Node ID of the "root" use item -- this is always the same as `ImportKind`'s `id` + /// (if it exists) except in the case of "nested" use trees, in which case + /// it will be the ID of the root use tree. e.g., in the example + /// ```ignore (incomplete code) /// use foo::bar::{a, b} /// ``` - /// - /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree` - /// for `a` in this field. - pub id: NodeId, - - /// The `id` of the "root" use-kind -- this is always the same as - /// `id` except in the case of "nested" use trees, in which case - /// it will be the `id` of the root use tree. e.g., in the example - /// from `id`, this would be the ID of the `use foo::bar` - /// `UseTree` node. + /// this would be the ID of the `use foo::bar` `UseTree` node. + /// In case of imports without their own node ID it's the closest node that can be used, + /// for example, for reporting lints. pub root_id: NodeId, /// Span of the entire use statement. @@ -161,6 +173,15 @@ impl<'a> Import<'a> { pub(crate) fn expect_vis(&self) -> ty::Visibility { self.vis.get().expect("encountered cleared import visibility") } + + pub(crate) fn id(&self) -> Option<NodeId> { + match self.kind { + ImportKind::Single { id, .. } + | ImportKind::Glob { id, .. } + | ImportKind::ExternCrate { id, .. } => Some(id), + ImportKind::MacroUse | ImportKind::MacroExport => None, + } + } } /// Records information about the resolution of a name in a namespace of a module. @@ -368,7 +389,9 @@ impl<'a> Resolver<'a> { self.record_use(target, dummy_binding, false); } else if import.imported_module.get().is_none() { import.used.set(true); - self.used_imports.insert(import.id); + if let Some(id) = import.id() { + self.used_imports.insert(id); + } } } } @@ -718,47 +741,51 @@ impl<'a, 'b> ImportResolver<'a, 'b> { PathResult::Indeterminate => unreachable!(), }; - let (ident, target, source_bindings, target_bindings, type_ns_only) = match import.kind { - ImportKind::Single { - source, - target, - ref source_bindings, - ref target_bindings, - type_ns_only, - .. - } => (source, target, source_bindings, target_bindings, type_ns_only), - ImportKind::Glob { is_prelude, ref max_vis } => { - if import.module_path.len() <= 1 { - // HACK(eddyb) `lint_if_path_starts_with_module` needs at least - // 2 segments, so the `resolve_path` above won't trigger it. - let mut full_path = import.module_path.clone(); - full_path.push(Segment::from_ident(Ident::empty())); - self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None); - } + let (ident, target, source_bindings, target_bindings, type_ns_only, import_id) = + match import.kind { + ImportKind::Single { + source, + target, + ref source_bindings, + ref target_bindings, + type_ns_only, + id, + .. + } => (source, target, source_bindings, target_bindings, type_ns_only, id), + ImportKind::Glob { is_prelude, ref max_vis, id } => { + if import.module_path.len() <= 1 { + // HACK(eddyb) `lint_if_path_starts_with_module` needs at least + // 2 segments, so the `resolve_path` above won't trigger it. + let mut full_path = import.module_path.clone(); + full_path.push(Segment::from_ident(Ident::empty())); + self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None); + } - if let ModuleOrUniformRoot::Module(module) = module { - if ptr::eq(module, import.parent_scope.module) { - // Importing a module into itself is not allowed. - return Some(UnresolvedImportError { - span: import.span, - label: Some(String::from("cannot glob-import a module into itself")), - note: None, - suggestion: None, - candidate: None, - }); + if let ModuleOrUniformRoot::Module(module) = module { + if ptr::eq(module, import.parent_scope.module) { + // Importing a module into itself is not allowed. + return Some(UnresolvedImportError { + span: import.span, + label: Some(String::from( + "cannot glob-import a module into itself", + )), + note: None, + suggestion: None, + candidate: None, + }); + } } - } - if !is_prelude + if !is_prelude && let Some(max_vis) = max_vis.get() && !max_vis.is_at_least(import.expect_vis(), &*self.r) { let msg = "glob import doesn't reexport anything because no candidate is public enough"; - self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg); + self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg); } - return None; - } - _ => unreachable!(), - }; + return None; + } + _ => unreachable!(), + }; let mut all_ns_err = true; self.r.per_ns(|this, ns| { @@ -858,7 +885,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { match binding.kind { // Never suggest the name that has binding error // i.e., the name that cannot be previously resolved - NameBindingKind::Res(Res::Err, _) => None, + NameBindingKind::Res(Res::Err) => None, _ => Some(i.name), } } @@ -960,7 +987,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ); self.r.lint_buffer.buffer_lint( PUB_USE_OF_PRIVATE_EXTERN_CRATE, - import.id, + import_id, import.span, &msg, ); @@ -989,7 +1016,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut err = struct_span_err!(self.r.session, import.span, E0364, "{error_msg}"); match binding.kind { - NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id), _) + NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id)) // exclude decl_macro if self.r.get_macro_by_def_id(def_id).macro_rules => { @@ -1029,7 +1056,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // purposes it's good enough to just favor one over the other. self.r.per_ns(|this, ns| { if let Ok(binding) = source_bindings[ns].get() { - this.import_res_map.entry(import.id).or_default()[ns] = Some(binding.res()); + this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res()); } }); @@ -1047,6 +1074,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> { target_bindings: &PerNS<Cell<Option<&'b NameBinding<'b>>>>, target: Ident, ) { + // This function is only called for single imports. + let ImportKind::Single { id, .. } = import.kind else { unreachable!() }; + // Skip if the import was produced by a macro. if import.parent_scope.expansion != LocalExpnId::ROOT { return; @@ -1094,7 +1124,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { redundant_spans.dedup(); self.r.lint_buffer.buffer_lint_with_diagnostic( UNUSED_IMPORTS, - import.id, + id, import.span, &format!("the item `{}` is imported redundantly", ident), BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident), @@ -1103,6 +1133,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } fn resolve_glob_import(&mut self, import: &'b Import<'b>) { + // This function is only called for glob imports. + let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() }; + let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else { self.r.session.span_err(import.span, "cannot glob-import all possible crates"); return; @@ -1113,7 +1146,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { return; } else if ptr::eq(module, import.parent_scope.module) { return; - } else if let ImportKind::Glob { is_prelude: true, .. } = import.kind { + } else if is_prelude { self.r.prelude = Some(module); return; } @@ -1145,7 +1178,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } // Record the destination of this import - self.r.record_partial_res(import.id, PartialRes::new(module.res().unwrap())); + self.r.record_partial_res(id, PartialRes::new(module.res().unwrap())); } // Miscellaneous post-processing, including recording re-exports, @@ -1204,5 +1237,6 @@ fn import_kind_to_string(import_kind: &ImportKind<'_>) -> String { ImportKind::Glob { .. } => "*".to_string(), ImportKind::ExternCrate { .. } => "<extern crate>".to_string(), ImportKind::MacroUse => "#[macro_use]".to_string(), + ImportKind::MacroExport => "#[macro_export]".to_string(), } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 00eb768ad18..6d2ee25df32 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -32,7 +32,7 @@ use smallvec::{smallvec, SmallVec}; use rustc_span::source_map::{respan, Spanned}; use std::assert_matches::debug_assert_matches; use std::collections::{hash_map::Entry, BTreeSet}; -use std::mem::{replace, take}; +use std::mem::{replace, swap, take}; mod diagnostics; @@ -3369,11 +3369,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let (mut err, candidates) = this.smart_resolve_report_errors(path, path_span, PathSource::Type, None); - if candidates.is_empty() { - err.cancel(); - return Some(parent_err); - } - // There are two different error messages user might receive at // this point: // - E0412 cannot find type `{}` in this scope @@ -3383,37 +3378,62 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // latter one - for paths in expression-position. // // Thus (since we're in expression-position at this point), not to - // confuse the user, we want to keep the *message* from E0432 (so + // confuse the user, we want to keep the *message* from E0433 (so // `parent_err`), but we want *hints* from E0412 (so `err`). // // And that's what happens below - we're just mixing both messages // into a single one. let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node); + // overwrite all properties with the parent's error message err.message = take(&mut parent_err.message); err.code = take(&mut parent_err.code); + swap(&mut err.span, &mut parent_err.span); err.children = take(&mut parent_err.children); + err.sort_span = parent_err.sort_span; + err.is_lint = parent_err.is_lint; + + // merge the parent's suggestions with the typo suggestions + fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) { + match res1 { + Ok(vec1) => match res2 { + Ok(mut vec2) => vec1.append(&mut vec2), + Err(e) => *res1 = Err(e), + }, + Err(_) => (), + }; + } + append_result(&mut err.suggestions, parent_err.suggestions.clone()); parent_err.cancel(); let def_id = this.parent_scope.module.nearest_parent_mod(); if this.should_report_errs() { - this.r.use_injections.push(UseError { - err, - candidates, - def_id, - instead: false, - suggestion: None, - path: path.into(), - is_call: source.is_call(), - }); + if candidates.is_empty() { + // When there is no suggested imports, we can just emit the error + // and suggestions immediately. Note that we bypass the usually error + // reporting routine (ie via `self.r.report_error`) because we need + // to post-process the `ResolutionError` above. + err.emit(); + } else { + // If there are suggested imports, the error reporting is delayed + this.r.use_injections.push(UseError { + err, + candidates, + def_id, + instead: false, + suggestion: None, + path: path.into(), + is_call: source.is_call(), + }); + } } else { err.cancel(); } // We don't return `Some(parent_err)` here, because the error will - // be already printed as part of the `use` injections + // be already printed either immediately or as part of the `use` injections None }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 11b70a38da5..ee1c97d5ad2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -104,9 +104,7 @@ enum Scope<'a> { DeriveHelpersCompat, MacroRules(MacroRulesScopeRef<'a>), CrateRoot, - // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` - // lint if it should be reported. - Module(Module<'a>, Option<NodeId>), + Module(Module<'a>), MacroUsePrelude, BuiltinAttrs, ExternPrelude, @@ -646,7 +644,7 @@ impl<'a> ToNameBinding<'a> for &'a NameBinding<'a> { #[derive(Clone, Debug)] enum NameBindingKind<'a> { - Res(Res, /* is_macro_export */ bool), + Res(Res), Module(Module<'a>), Import { binding: &'a NameBinding<'a>, import: &'a Import<'a>, used: Cell<bool> }, } @@ -745,7 +743,7 @@ impl<'a> NameBinding<'a> { fn res(&self) -> Res { match self.kind { - NameBindingKind::Res(res, _) => res, + NameBindingKind::Res(res) => res, NameBindingKind::Module(module) => module.res().unwrap(), NameBindingKind::Import { binding, .. } => binding.res(), } @@ -762,10 +760,10 @@ impl<'a> NameBinding<'a> { fn is_possibly_imported_variant(&self) -> bool { match self.kind { NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(), - NameBindingKind::Res( - Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _), + NameBindingKind::Res(Res::Def( + DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _, - ) => true, + )) => true, NameBindingKind::Res(..) | NameBindingKind::Module(..) => false, } } @@ -788,6 +786,13 @@ impl<'a> NameBinding<'a> { matches!(self.kind, NameBindingKind::Import { .. }) } + /// The binding introduced by `#[macro_export] macro_rules` is a public import, but it might + /// not be perceived as such by users, so treat it as a non-import in some diagnostics. + fn is_import_user_facing(&self) -> bool { + matches!(self.kind, NameBindingKind::Import { import, .. } + if !matches!(import.kind, ImportKind::MacroExport)) + } + fn is_glob_import(&self) -> bool { match self.kind { NameBindingKind::Import { import, .. } => import.is_glob(), @@ -1283,7 +1288,7 @@ impl<'a> Resolver<'a> { arenas, dummy_binding: arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Res(Res::Err, false), + kind: NameBindingKind::Res(Res::Err), ambiguity: None, expansion: LocalExpnId::ROOT, span: DUMMY_SP, @@ -1551,7 +1556,7 @@ impl<'a> Resolver<'a> { self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| { match scope { - Scope::Module(module, _) => { + Scope::Module(module) => { this.traits_in_module(module, assoc_item, &mut found_traits); } Scope::StdLibPrelude => { @@ -1613,10 +1618,12 @@ impl<'a> Resolver<'a> { ) -> SmallVec<[LocalDefId; 1]> { let mut import_ids = smallvec![]; while let NameBindingKind::Import { import, binding, .. } = kind { - let id = self.local_def_id(import.id); - self.maybe_unused_trait_imports.insert(id); + if let Some(node_id) = import.id() { + let def_id = self.local_def_id(node_id); + self.maybe_unused_trait_imports.insert(def_id); + import_ids.push(def_id); + } self.add_to_glob_map(&import, trait_name); - import_ids.push(id); kind = &binding.kind; } import_ids @@ -1683,7 +1690,9 @@ impl<'a> Resolver<'a> { } used.set(true); import.used.set(true); - self.used_imports.insert(import.id); + if let Some(id) = import.id() { + self.used_imports.insert(id); + } self.add_to_glob_map(&import, ident); self.record_use(ident, binding, false); } @@ -1691,8 +1700,8 @@ impl<'a> Resolver<'a> { #[inline] fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) { - if import.is_glob() { - let def_id = self.local_def_id(import.id); + if let ImportKind::Glob { id, .. } = import.kind { + let def_id = self.local_def_id(id); self.glob_map.entry(def_id).or_default().insert(ident.name); } } @@ -1994,11 +2003,7 @@ impl<'a> Resolver<'a> { // Items that go to reexport table encoded to metadata and visible through it to other crates. fn is_reexport(&self, binding: &NameBinding<'a>) -> Option<def::Res<!>> { - // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules` - // into the crate root to actual `NameBindingKind::Import`. - if binding.is_import() - || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true)) - { + if binding.is_import() { let res = binding.res().expect_non_local(); // Ambiguous imports are treated as errors at this point and are // not exposed to other crates (see #36837 for more details). diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f2ee52262ad..856ff3d4150 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -794,6 +794,7 @@ impl UnstableOptions { report_delayed_bugs: self.report_delayed_bugs, macro_backtrace: self.macro_backtrace, deduplicate_diagnostics: self.deduplicate_diagnostics, + track_diagnostics: self.track_diagnostics, } } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 3f234a47a3d..e93c4138e61 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1587,6 +1587,8 @@ options! { "choose the TLS model to use (`rustc --print tls-models` for details)"), trace_macros: bool = (false, parse_bool, [UNTRACKED], "for every macro invocation, print its name and arguments (default: no)"), + track_diagnostics: bool = (false, parse_bool, [UNTRACKED], + "tracks where in rustc a diagnostic was emitted"), // Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved // alongside query results and changes to translation options can affect diagnostics - so // translation options should be tracked. diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index a199947ebed..f9f4f2979c4 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -97,6 +97,7 @@ pub fn feature_err<'a>( /// /// This variant allows you to control whether it is a library or language feature. /// Almost always, you want to use this for a language feature. If so, prefer `feature_err`. +#[track_caller] pub fn feature_err_issue<'a>( sess: &'a ParseSess, feature: Symbol, @@ -332,6 +333,7 @@ impl ParseSess { self.proc_macro_quoted_spans.lock().clone() } + #[track_caller] pub fn create_err<'a>( &'a self, err: impl IntoDiagnostic<'a>, @@ -339,10 +341,12 @@ impl ParseSess { err.into_diagnostic(&self.span_diagnostic) } + #[track_caller] pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed { self.create_err(err).emit() } + #[track_caller] pub fn create_warning<'a>( &'a self, warning: impl IntoDiagnostic<'a, ()>, @@ -350,6 +354,7 @@ impl ParseSess { warning.into_diagnostic(&self.span_diagnostic) } + #[track_caller] pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { self.create_warning(warning).emit() } @@ -377,6 +382,7 @@ impl ParseSess { } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_err( &self, msg: impl Into<DiagnosticMessage>, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 100c66f6364..6d3cda684a6 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -286,6 +286,7 @@ impl Session { } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_warn<S: Into<MultiSpan>>( &self, sp: S, @@ -294,6 +295,7 @@ impl Session { self.diagnostic().struct_span_warn(sp, msg) } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>( &self, sp: S, @@ -303,6 +305,7 @@ impl Session { self.diagnostic().struct_span_warn_with_expectation(sp, msg, id) } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_warn_with_code<S: Into<MultiSpan>>( &self, sp: S, @@ -312,10 +315,12 @@ impl Session { self.diagnostic().struct_span_warn_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn(msg) } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_warn_with_expectation( &self, msg: impl Into<DiagnosticMessage>, @@ -324,6 +329,7 @@ impl Session { self.diagnostic().struct_warn_with_expectation(msg, id) } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_allow<S: Into<MultiSpan>>( &self, sp: S, @@ -332,10 +338,12 @@ impl Session { self.diagnostic().struct_span_allow(sp, msg) } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_allow(msg) } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_expect( &self, msg: impl Into<DiagnosticMessage>, @@ -344,6 +352,7 @@ impl Session { self.diagnostic().struct_expect(msg, id) } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_err<S: Into<MultiSpan>>( &self, sp: S, @@ -352,6 +361,7 @@ impl Session { self.diagnostic().struct_span_err(sp, msg) } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_err_with_code<S: Into<MultiSpan>>( &self, sp: S, @@ -362,12 +372,14 @@ impl Session { } // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_err( &self, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { self.parse_sess.struct_err(msg) } + #[track_caller] #[rustc_lint_diagnostics] pub fn struct_err_with_code( &self, @@ -377,6 +389,7 @@ impl Session { self.diagnostic().struct_err_with_code(msg, code) } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_warn_with_code( &self, msg: impl Into<DiagnosticMessage>, @@ -385,6 +398,7 @@ impl Session { self.diagnostic().struct_warn_with_code(msg, code) } #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_fatal<S: Into<MultiSpan>>( &self, sp: S, @@ -407,6 +421,7 @@ impl Session { } #[rustc_lint_diagnostics] + #[track_caller] pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! { self.diagnostic().span_fatal(sp, msg) } @@ -424,6 +439,7 @@ impl Session { self.diagnostic().fatal(msg).raise() } #[rustc_lint_diagnostics] + #[track_caller] pub fn span_err_or_warn<S: Into<MultiSpan>>( &self, is_warning: bool, @@ -437,6 +453,7 @@ impl Session { } } #[rustc_lint_diagnostics] + #[track_caller] pub fn span_err<S: Into<MultiSpan>>( &self, sp: S, @@ -457,12 +474,14 @@ impl Session { pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed { self.diagnostic().err(msg) } + #[track_caller] pub fn create_err<'a>( &'a self, err: impl IntoDiagnostic<'a>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { self.parse_sess.create_err(err) } + #[track_caller] pub fn create_feature_err<'a>( &'a self, err: impl IntoDiagnostic<'a>, @@ -475,33 +494,40 @@ impl Session { add_feature_diagnostics(&mut err, &self.parse_sess, feature); err } + #[track_caller] pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed { self.parse_sess.emit_err(err) } + #[track_caller] pub fn create_warning<'a>( &'a self, err: impl IntoDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()> { self.parse_sess.create_warning(err) } + #[track_caller] pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { self.parse_sess.emit_warning(warning) } + #[track_caller] pub fn create_note<'a>( &'a self, note: impl IntoDiagnostic<'a, Noted>, ) -> DiagnosticBuilder<'a, Noted> { self.parse_sess.create_note(note) } + #[track_caller] pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted { self.parse_sess.emit_note(note) } + #[track_caller] pub fn create_fatal<'a>( &'a self, fatal: impl IntoDiagnostic<'a, !>, ) -> DiagnosticBuilder<'a, !> { self.parse_sess.create_fatal(fatal) } + #[track_caller] pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! { self.parse_sess.emit_fatal(fatal) } @@ -541,6 +567,7 @@ impl Session { } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] + #[track_caller] pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { self.diagnostic().span_warn(sp, msg) } @@ -587,6 +614,8 @@ impl Session { pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) { self.diagnostic().note_without_error(msg) } + + #[track_caller] pub fn span_note_without_error<S: Into<MultiSpan>>( &self, sp: S, @@ -1213,6 +1242,7 @@ fn default_emitter( fallback_bundle: LazyFallbackBundle, ) -> Box<dyn Emitter + sync::Send> { let macro_backtrace = sopts.unstable_opts.macro_backtrace; + let track_diagnostics = sopts.unstable_opts.track_diagnostics; match sopts.error_format { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); @@ -1236,6 +1266,7 @@ fn default_emitter( sopts.unstable_opts.teach, sopts.diagnostic_width, macro_backtrace, + track_diagnostics, ); Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } @@ -1250,6 +1281,7 @@ fn default_emitter( json_rendered, sopts.diagnostic_width, macro_backtrace, + track_diagnostics, ) .ui_testing(sopts.unstable_opts.ui_testing), ), @@ -1552,11 +1584,18 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler false, None, false, + false, )) } - config::ErrorOutputType::Json { pretty, json_rendered } => { - Box::new(JsonEmitter::basic(pretty, json_rendered, None, fallback_bundle, None, false)) - } + config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic( + pretty, + json_rendered, + None, + fallback_bundle, + None, + false, + false, + )), }; rustc_errors::Handler::with_emitter(true, None, emitter) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7e565df7601..cccc4897ecc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -694,6 +694,7 @@ symbols! { export_name, expr, extended_key_value_attributes, + extended_varargs_abi_support, extern_absolute_paths, extern_crate_item_prelude, extern_crate_self, diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index ce45fa13970..cb2a0c04c6a 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -40,6 +40,28 @@ pub enum Abi { RustCold, } +impl Abi { + pub fn supports_varargs(self) -> bool { + // * C and Cdecl obviously support varargs. + // * C can be based on SysV64 or Win64, so they must support varargs. + // * EfiApi is based on Win64 or C, so it also supports it. + // + // * Stdcall does not, because it would be impossible for the callee to clean + // up the arguments. (callee doesn't know how many arguments are there) + // * Same for Fastcall, Vectorcall and Thiscall. + // * System can become Stdcall, so is also a no-no. + // * Other calling conventions are related to hardware or the compiler itself. + match self { + Self::C { .. } + | Self::Cdecl { .. } + | Self::Win64 { .. } + | Self::SysV64 { .. } + | Self::EfiApi => true, + _ => false, + } + } +} + #[derive(Copy, Clone)] pub struct AbiData { abi: Abi, diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psx.rs b/compiler/rustc_target/src/spec/mipsel_sony_psx.rs new file mode 100644 index 00000000000..12a66efdd46 --- /dev/null +++ b/compiler/rustc_target/src/spec/mipsel_sony_psx.rs @@ -0,0 +1,37 @@ +use crate::spec::{cvs, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "mipsel-sony-psx".into(), + pointer_width: 32, + data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), + arch: "mips".into(), + + options: TargetOptions { + os: "none".into(), + env: "psx".into(), + vendor: "sony".into(), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + cpu: "mips1".into(), + executables: true, + linker: Some("rust-lld".into()), + relocation_model: RelocModel::Static, + exe_suffix: ".exe".into(), + + // PSX doesn't natively support floats. + features: "+soft-float".into(), + + // This should be 16 bits, but LLVM incorrectly tries emitting MIPS-II SYNC instructions + // for atomic loads and stores. This crashes rustc so we have to disable the Atomic* API + // until this is fixed upstream. See https://reviews.llvm.org/D122427#3420144 for more + // info. + max_atomic_width: Some(0), + + // PSX does not support trap-on-condition instructions. + llvm_args: cvs!["-mno-check-zero-division"], + llvm_abiname: "o32".into(), + panic_strategy: PanicStrategy::Abort, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 8909cf33af9..72b088d663b 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1222,6 +1222,7 @@ supported_targets! { ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf), ("mipsel-sony-psp", mipsel_sony_psp), + ("mipsel-sony-psx", mipsel_sony_psx), ("mipsel-unknown-none", mipsel_unknown_none), ("thumbv4t-none-eabi", thumbv4t_none_eabi), ("armv4t-none-eabi", armv4t_none_eabi), diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 7f870582444..23c3715860e 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -67,6 +67,7 @@ pub struct NegativePositiveConflict<'a> { } impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> { + #[track_caller] fn into_diagnostic( self, handler: &Handler, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index a335f8e06bc..96ac4e9c129 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -1,5 +1,5 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::{self, TraitEngine, TraitEngineExt}; +use crate::traits::{self, ObligationCtxt}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; @@ -142,7 +142,7 @@ pub trait InferCtxtBuilderExt<'tcx> { fn enter_canonical_trait_query<K, R>( &mut self, canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>, + operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>, ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>> where K: TypeFoldable<'tcx>, @@ -170,17 +170,17 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> { fn enter_canonical_trait_query<K, R>( &mut self, canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>, + operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>, ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>> where K: TypeFoldable<'tcx>, R: Debug + TypeFoldable<'tcx>, Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>, { - let (ref infcx, key, canonical_inference_vars) = + let (infcx, key, canonical_inference_vars) = self.build_with_canonical(DUMMY_SP, canonical_key); - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); - let value = operation(infcx, &mut *fulfill_cx, key)?; - infcx.make_canonicalized_query_response(canonical_inference_vars, value, &mut *fulfill_cx) + let ocx = ObligationCtxt::new(&infcx); + let value = operation(&ocx, key)?; + ocx.make_canonicalized_query_response(canonical_inference_vars, value) } } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index e0c8deec91a..21516c93efb 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -1,14 +1,21 @@ use std::cell::RefCell; +use std::fmt::Debug; use super::TraitEngine; use super::{ChalkFulfillmentContext, FulfillmentContext}; use crate::infer::InferCtxtExt; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_infer::infer::at::ToTrace; +use rustc_infer::infer::canonical::{ + Canonical, CanonicalVarValues, CanonicalizedQueryResponse, QueryResponse, +}; use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::traits::query::Fallible; use rustc_infer::traits::{ FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, }; +use rustc_middle::arena::ArenaAllocatable; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::ToPredicate; use rustc_middle::ty::TypeFoldable; @@ -105,12 +112,12 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { self.register_infer_ok_obligations(infer_ok) } - pub fn equate_types( + pub fn eq<T: ToTrace<'tcx>>( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - expected: Ty<'tcx>, - actual: Ty<'tcx>, + expected: T, + actual: T, ) -> Result<(), TypeError<'tcx>> { match self.infcx.at(cause, param_env).eq(expected, actual) { Ok(InferOk { obligations, value: () }) => { @@ -121,6 +128,22 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { } } + pub fn sup<T: ToTrace<'tcx>>( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'tcx>> { + match self.infcx.at(cause, param_env).sup(expected, actual) { + Ok(InferOk { obligations, value: () }) => { + self.register_obligations(obligations); + Ok(()) + } + Err(e) => Err(e), + } + } + pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> { self.engine.borrow_mut().select_all_or_error(self.infcx) } @@ -154,4 +177,20 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { } implied_bounds } + + pub fn make_canonicalized_query_response<T>( + &self, + inference_vars: CanonicalVarValues<'tcx>, + answer: T, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>> + where + T: Debug + TypeFoldable<'tcx>, + Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, + { + self.infcx.make_canonicalized_query_response( + inference_vars, + answer, + &mut **self.engine.borrow_mut(), + ) + } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 1217d264a9c..dacce5cd2f6 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -974,7 +974,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // useful for less general traits. if peeled && !self.tcx.trait_is_auto(def_id) - && !self.tcx.lang_items().items().contains(&Some(def_id)) + && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id) { let trait_ref = trait_pred.to_poly_trait_ref(); let impl_candidates = @@ -1898,7 +1898,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let def_id = trait_ref.def_id(); if impl_candidates.is_empty() { if self.tcx.trait_is_auto(def_id) - || self.tcx.lang_items().items().contains(&Some(def_id)) + || self.tcx.lang_items().iter().any(|(_, id)| id == def_id) || self.tcx.get_diagnostic_name(def_id).is_some() { // Mentioning implementers of `Copy`, `Debug` and friends is not useful. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 8c41d9d240c..d7606d88803 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1019,7 +1019,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut never_suggest_borrow: Vec<_> = [LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized] .iter() - .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok()) + .filter_map(|lang_item| self.tcx.lang_items().get(*lang_item)) .collect(); if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) { diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 7d36b9558d5..82f6111f6f9 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -28,9 +28,9 @@ fn implied_outlives_bounds<'tcx>( &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>, NoSolution, > { - tcx.infer_ctxt().enter_canonical_trait_query(&goal, |infcx, _fulfill_cx, key| { + tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { let (param_env, ty) = key.into_parts(); - compute_implied_outlives_bounds(&infcx, param_env, ty) + compute_implied_outlives_bounds(&ocx.infcx, param_env, ty) }) } diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 0da28737f69..0ffa92f1ad5 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -3,6 +3,7 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![feature(let_chains)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 98bb42c9afd..e805eb42821 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -1,6 +1,5 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_trait_selection::infer::InferCtxtBuilderExt; @@ -23,8 +22,8 @@ fn normalize_projection_ty<'tcx>( tcx.sess.perf_stats.normalize_projection_ty.fetch_add(1, Ordering::Relaxed); tcx.infer_ctxt().enter_canonical_trait_query( &goal, - |infcx, fulfill_cx, ParamEnvAnd { param_env, value: goal }| { - let selcx = &mut SelectionContext::new(infcx); + |ocx, ParamEnvAnd { param_env, value: goal }| { + let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = vec![]; let answer = traits::normalize_projection_type( @@ -35,7 +34,7 @@ fn normalize_projection_ty<'tcx>( 0, &mut obligations, ); - fulfill_cx.register_predicate_obligations(infcx, obligations); + ocx.register_obligations(obligations); // FIXME(associated_const_equality): All users of normalize_projection_ty expected // a type, but there is the possibility it could've been a const now. Maybe change // it to a Term later? diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index bca7458ed33..98cb3f21555 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -2,17 +2,14 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; -use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{ObligationCauseCode, TraitEngineExt as _}; +use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; +use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{ - self, EarlyBinder, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance, -}; -use rustc_middle::ty::{GenericArg, UserSelfTy, UserSubsts}; -use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate}; +use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ParamEnvAnd, Predicate, ToPredicate}; +use rustc_middle::ty::{UserSelfTy, UserSubsts}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::normalize::AtExt; use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType; use rustc_trait_selection::traits::query::type_op::eq::Eq; @@ -20,7 +17,7 @@ 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::query::type_op::subtype::Subtype; use rustc_trait_selection::traits::query::{Fallible, NoSolution}; -use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine}; +use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt}; use std::fmt; use std::iter::zip; @@ -42,17 +39,16 @@ fn type_op_ascribe_user_type<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { - tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { - type_op_ascribe_user_type_with_span(infcx, fulfill_cx, key, None) + tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| { + type_op_ascribe_user_type_with_span(ocx, key, None) }) } /// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors, /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. -pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>( - infcx: &'a InferCtxt<'tcx>, - fulfill_cx: &'a mut dyn TraitEngine<'tcx>, +pub fn type_op_ascribe_user_type_with_span<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, span: Option<Span>, ) -> Result<(), NoSolution> { @@ -61,68 +57,50 @@ pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>( "type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}", mir_ty, def_id, user_substs ); - - let mut cx = AscribeUserTypeCx { infcx, param_env, span: span.unwrap_or(DUMMY_SP), fulfill_cx }; + let cx = AscribeUserTypeCx { ocx, param_env, span: span.unwrap_or(DUMMY_SP) }; cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?; Ok(()) } struct AscribeUserTypeCx<'me, 'tcx> { - infcx: &'me InferCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + ocx: &'me ObligationCtxt<'me, 'tcx>, + param_env: ty::ParamEnv<'tcx>, span: Span, - fulfill_cx: &'me mut dyn TraitEngine<'tcx>, } impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { - fn normalize<T>(&mut self, value: T) -> T + fn normalize<T>(&self, value: T) -> T where T: TypeFoldable<'tcx>, { self.normalize_with_cause(value, ObligationCause::misc(self.span, hir::CRATE_HIR_ID)) } - fn normalize_with_cause<T>(&mut self, value: T, cause: ObligationCause<'tcx>) -> T + fn normalize_with_cause<T>(&self, value: T, cause: ObligationCause<'tcx>) -> T where T: TypeFoldable<'tcx>, { - self.infcx - .partially_normalize_associated_types_in(cause, self.param_env, value) - .into_value_registering_obligations(self.infcx, self.fulfill_cx) + self.ocx.normalize(cause, self.param_env, value) } - fn relate<T>(&mut self, a: T, variance: Variance, b: T) -> Result<(), NoSolution> + fn eq<T>(&self, a: T, b: T) -> Result<(), NoSolution> where T: ToTrace<'tcx>, { - self.infcx - .at(&ObligationCause::dummy_with_span(self.span), self.param_env) - .relate(a, variance, b)? - .into_value_registering_obligations(self.infcx, self.fulfill_cx); - Ok(()) + Ok(self.ocx.eq(&ObligationCause::dummy_with_span(self.span), self.param_env, a, b)?) } - fn prove_predicate(&mut self, predicate: Predicate<'tcx>, cause: ObligationCause<'tcx>) { - self.fulfill_cx.register_predicate_obligation( - self.infcx, - Obligation::new(cause, self.param_env, predicate), - ); + fn prove_predicate(&self, predicate: Predicate<'tcx>, cause: ObligationCause<'tcx>) { + self.ocx.register_obligation(Obligation::new(cause, self.param_env, predicate)); } fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn subst<T>(&self, value: T, substs: &[GenericArg<'tcx>]) -> T - where - T: TypeFoldable<'tcx>, - { - EarlyBinder(value).subst(self.tcx(), substs) + self.ocx.infcx.tcx } #[instrument(level = "debug", skip(self))] fn relate_mir_and_user_ty( - &mut self, + &self, mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>, @@ -130,20 +108,18 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { let UserSubsts { user_self_ty, substs } = user_substs; let tcx = self.tcx(); - let ty = tcx.type_of(def_id); - let ty = self.subst(ty, substs); + let ty = tcx.bound_type_of(def_id).subst(tcx, substs); let ty = self.normalize(ty); debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); - self.relate(mir_ty, Variance::Invariant, ty)?; + self.eq(mir_ty, ty)?; // Prove the predicates coming along with `def_id`. // // Also, normalize the `instantiated_predicates` // because otherwise we wind up with duplicate "type // outlives" error messages. - let instantiated_predicates = - self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs); + let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); let cause = ObligationCause::dummy_with_span(self.span); @@ -163,15 +139,14 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { } if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { - let impl_self_ty = self.tcx().type_of(impl_def_id); - let impl_self_ty = self.subst(impl_self_ty, &substs); + let impl_self_ty = tcx.bound_type_of(impl_def_id).subst(tcx, substs); let impl_self_ty = self.normalize(impl_self_ty); - self.relate(self_ty, Variance::Invariant, impl_self_ty)?; + self.eq(self_ty, impl_self_ty)?; self.prove_predicate( ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())) - .to_predicate(self.tcx()), + .to_predicate(tcx), cause.clone(), ); } @@ -188,7 +163,7 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { // type were ill-formed but did not appear in `ty`, // which...could happen with normalization... self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(tcx), cause, ); Ok(()) @@ -199,19 +174,14 @@ fn type_op_eq<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { - tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { + tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| { let (param_env, Eq { a, b }) = key.into_parts(); - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(a, b)? - .into_value_registering_obligations(infcx, fulfill_cx); - Ok(()) + Ok(ocx.eq(&ObligationCause::dummy(), param_env, a, b)?) }) } fn type_op_normalize<'tcx, T>( - infcx: &InferCtxt<'tcx>, - fulfill_cx: &mut dyn TraitEngine<'tcx>, + ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Normalize<T>>, ) -> Fallible<T> where @@ -219,8 +189,8 @@ where { let (param_env, Normalize { value }) = key.into_parts(); let Normalized { value, obligations } = - infcx.at(&ObligationCause::dummy(), param_env).normalize(value)?; - fulfill_cx.register_predicate_obligations(infcx, obligations); + ocx.infcx.at(&ObligationCause::dummy(), param_env).normalize(value)?; + ocx.register_obligations(obligations); Ok(value) } @@ -256,13 +226,9 @@ fn type_op_subtype<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Subtype<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { - tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { + tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| { let (param_env, Subtype { sub, sup }) = key.into_parts(); - infcx - .at(&ObligationCause::dummy(), param_env) - .sup(sup, sub)? - .into_value_registering_obligations(infcx, fulfill_cx); - Ok(()) + Ok(ocx.sup(&ObligationCause::dummy(), param_env, sup, sub)?) }) } @@ -274,8 +240,8 @@ fn type_op_prove_predicate<'tcx>( // impl-trait/issue-99642.rs tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_canonical_trait_query( &canonicalized, - |infcx, fulfill_cx, key| { - type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy()); + |ocx, key| { + type_op_prove_predicate_with_cause(ocx, key, ObligationCause::dummy()); Ok(()) }, ) @@ -284,12 +250,11 @@ fn type_op_prove_predicate<'tcx>( /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors, /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. -pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>( - infcx: &'a InferCtxt<'tcx>, - fulfill_cx: &'a mut dyn TraitEngine<'tcx>, +pub fn type_op_prove_predicate_with_cause<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>, cause: ObligationCause<'tcx>, ) { let (param_env, ProvePredicate { predicate }) = key.into_parts(); - fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate)); + ocx.register_obligation(Obligation::new(cause, param_env, predicate)); } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index acd4fa63d78..2bc6bc1fc23 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -284,7 +284,8 @@ pub(crate) mod rustc { } ty::Array(ty, len) => { - let len = len.try_eval_usize(tcx, ParamEnv::reveal_all()).unwrap(); + let len = + len.try_eval_usize(tcx, ParamEnv::reveal_all()).ok_or(Err::Unspecified)?; let elt = Tree::from_ty(*ty, tcx)?; Ok(std::iter::repeat(elt) .take(len as usize) |
