From 6192690b92d32d0d8511e1dd33b7cd35a52d6209 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 5 Sep 2023 15:14:53 +0200 Subject: [PATCH 01/26] Add clippy like expr_or_init fn to rustc LateContext --- compiler/rustc_lint/src/context.rs | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 7a336a8f6947..460d54739a2e 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1315,6 +1315,54 @@ impl<'tcx> LateContext<'tcx> { tcx.try_normalize_erasing_regions(self.param_env, proj).ok() }) } + + /// If the given expression is a local binding, find the initializer expression. + /// If that initializer expression is another local or **outside** (`const`/`static`) + /// binding, find its initializer again. + /// + /// This process repeats as long as possible (but usually no more than once). + /// Type-check adjustments are not taken in account in this function. + /// + /// Examples: + /// ``` + /// const ABC: i32 = 1; + /// // ^ output + /// let def = ABC; + /// dbg!(def); + /// // ^^^ input + /// + /// // or... + /// let abc = 1; + /// let def = abc + 2; + /// // ^^^^^^^ output + /// dbg!(def); + /// // ^^^ input + /// ``` + pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> { + expr = expr.peel_blocks(); + + while let hir::ExprKind::Path(ref qpath) = expr.kind + && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) { + Res::Local(hir_id) => self.tcx.hir().find_parent(hir_id), + Res::Def(_, def_id) => self.tcx.hir().get_if_local(def_id), + _ => None, + } + && let Some(init) = match parent_node { + hir::Node::Expr(expr) => Some(expr), + hir::Node::Local(hir::Local { init, .. }) => *init, + hir::Node::Item(item) => match item.kind { + hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => { + Some(self.tcx.hir().body(body_id).value) + } + _ => None + } + _ => None + } + { + expr = init.peel_blocks(); + } + expr + } } impl<'tcx> abi::HasDataLayout for LateContext<'tcx> { From c599761140ed1e3824a10d556395f178617e076a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Sun, 17 Sep 2023 20:13:05 +0200 Subject: [PATCH 02/26] rustc_hir_analysis: add a helper to check function the signature mismatches This function is now used to check `#[panic_handler]`, `start` lang item, `main`, `#[start]` and intrinsic functions. The diagnosis produced are now closer to the ones produced by trait/impl method signature mismatch. --- .../rustc_hir_analysis/src/check/entry.rs | 54 ++-- .../rustc_hir_analysis/src/check/intrinsic.rs | 13 +- compiler/rustc_hir_analysis/src/check/mod.rs | 91 ++++++- compiler/rustc_hir_analysis/src/lib.rs | 26 +- compiler/rustc_hir_typeck/messages.ftl | 10 - compiler/rustc_hir_typeck/src/check.rs | 245 ++++++------------ compiler/rustc_hir_typeck/src/errors.rs | 33 --- compiler/rustc_infer/messages.ftl | 6 + compiler/rustc_infer/src/errors/mod.rs | 8 + .../src/infer/error_reporting/mod.rs | 6 + compiler/rustc_middle/src/traits/mod.rs | 3 + .../src/traits/error_reporting/suggestions.rs | 1 + .../issue-111879-1.stderr | 4 +- tests/ui/borrowck/issue-92157.rs | 2 +- tests/ui/borrowck/issue-92157.stderr | 9 +- .../auxiliary/bad_main_functions.rs | 2 + ...orted_main_from_extern_crate_wrong_type.rs | 6 + ...d_main_from_extern_crate_wrong_type.stderr | 12 + tests/ui/error-codes/E0308.stderr | 8 +- tests/ui/extern/extern-main-fn.stderr | 4 +- tests/ui/fn/bad-main.stderr | 4 +- tests/ui/issues/issue-9575.stderr | 4 +- .../start_lang_item_args.argc.stderr | 8 +- .../start_lang_item_args.argv.stderr | 8 +- ...start_lang_item_args.argv_inner_ptr.stderr | 11 +- .../start_lang_item_args.main_args.stderr | 13 +- .../start_lang_item_args.main_ret.stderr | 13 +- .../start_lang_item_args.main_ty.stderr | 8 +- ...art_lang_item_args.missing_all_args.stderr | 9 +- .../start_lang_item_args.missing_ret.stderr | 8 +- ..._lang_item_args.missing_sigpipe_arg.stderr | 9 +- tests/ui/lang-items/start_lang_item_args.rs | 24 +- .../start_lang_item_args.sigpipe.stderr | 8 +- .../start_lang_item_args.start_ret.stderr | 8 +- .../start_lang_item_args.too_many_args.stderr | 9 +- tests/ui/main-wrong-type.stderr | 4 +- .../panic-handler-bad-signature-1.rs | 7 +- .../panic-handler-bad-signature-1.stderr | 18 +- .../panic-handler-bad-signature-2.rs | 5 +- .../panic-handler-bad-signature-2.stderr | 18 +- .../panic-handler-bad-signature-3.rs | 2 +- .../panic-handler-bad-signature-3.stderr | 8 +- .../panic-handler-bad-signature-5.rs | 13 + .../panic-handler-bad-signature-5.stderr | 18 ++ tests/ui/range/issue-54505-no-std.rs | 6 +- tests/ui/range/issue-54505-no-std.stderr | 14 +- tests/ui/resolve/bad-expr-path.stderr | 4 +- tests/ui/resolve/bad-expr-path2.stderr | 4 +- 48 files changed, 423 insertions(+), 385 deletions(-) create mode 100644 tests/ui/entry-point/auxiliary/bad_main_functions.rs create mode 100644 tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs create mode 100644 tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.stderr create mode 100644 tests/ui/panic-handler/panic-handler-bad-signature-5.rs create mode 100644 tests/ui/panic-handler/panic-handler-bad-signature-5.stderr diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index fcaefe0261b0..27af10af8e6f 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -11,8 +11,8 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use std::ops::Not; +use super::check_function_signature; use crate::errors; -use crate::require_same_types; pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) { match tcx.entry_fn(()) { @@ -162,33 +162,33 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { error = true; } // now we can take the return type of the given main function - expected_return_type = main_fnsig.output(); + expected_return_type = norm_return_ty; } else { // standard () main return type - expected_return_type = ty::Binder::dummy(Ty::new_unit(tcx)); + expected_return_type = tcx.types.unit; } if error { return; } - let se_ty = Ty::new_fn_ptr( - tcx, - expected_return_type.map_bound(|expected_return_type| { - tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust) - }), - ); + let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig( + [], + expected_return_type, + false, + hir::Unsafety::Normal, + Abi::Rust, + )); - require_same_types( + check_function_signature( tcx, - &ObligationCause::new( + ObligationCause::new( main_span, main_diagnostics_def_id, ObligationCauseCode::MainFunctionType, ), - param_env, - se_ty, - Ty::new_fn_ptr(tcx, main_fnsig), + main_def_id, + expected_sig, ); } @@ -247,27 +247,23 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { } } - let se_ty = Ty::new_fn_ptr( - tcx, - ty::Binder::dummy(tcx.mk_fn_sig( - [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))], - tcx.types.isize, - false, - hir::Unsafety::Normal, - Abi::Rust, - )), - ); + let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig( + [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))], + tcx.types.isize, + false, + hir::Unsafety::Normal, + Abi::Rust, + )); - require_same_types( + check_function_signature( tcx, - &ObligationCause::new( + ObligationCause::new( start_span, start_def_id, ObligationCauseCode::StartFunctionType, ), - ty::ParamEnv::empty(), // start should not have any where bounds. - se_ty, - Ty::new_fn_ptr(tcx, tcx.fn_sig(start_def_id).instantiate_identity()), + start_def_id.into(), + expected_sig, ); } _ => { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index f89e2e5c25bf..444103ffe8f3 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -1,11 +1,11 @@ //! Type-checking for the rust-intrinsic and platform-intrinsic //! intrinsics that the compiler exposes. +use crate::check::check_function_signature; use crate::errors::{ UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction, WrongNumberOfGenericArgumentsToIntrinsic, }; -use crate::require_same_types; use hir::def_id::DefId; use rustc_errors::{struct_span_err, DiagnosticMessage}; @@ -53,15 +53,12 @@ fn equate_intrinsic_type<'tcx>( && gen_count_ok(own_counts.types, n_tps, "type") && gen_count_ok(own_counts.consts, 0, "const") { - let fty = Ty::new_fn_ptr(tcx, sig); let it_def_id = it.owner_id.def_id; - let cause = ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType); - require_same_types( + check_function_signature( tcx, - &cause, - ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env? - Ty::new_fn_ptr(tcx, tcx.fn_sig(it.owner_id).instantiate_identity()), - fty, + ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType), + it_def_id.into(), + sig, ); } } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index d83316613666..b9ce4c079227 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -73,23 +73,31 @@ pub mod wfcheck; pub use check::check_abi; +use std::num::NonZeroU32; + use check::check_mod_item_types; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; +use rustc_infer::infer::error_reporting::ObligationCauseExt as _; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::{self, TyCtxtInferExt as _}; +use rustc_infer::traits::ObligationCause; use rustc_middle::query::Providers; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_session::parse::feature_err; use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{self, BytePos, Span, Symbol}; +use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; -use std::num::NonZeroU32; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; +use rustc_trait_selection::traits::ObligationCtxt; use crate::errors; use crate::require_c_abi_if_c_variadic; @@ -546,3 +554,82 @@ fn bad_non_zero_sized_fields<'tcx>( pub fn potentially_plural_count(count: usize, word: &str) -> String { format!("{} {}{}", count, word, pluralize!(count)) } + +pub fn check_function_signature<'tcx>( + tcx: TyCtxt<'tcx>, + mut cause: ObligationCause<'tcx>, + fn_id: DefId, + expected_sig: ty::PolyFnSig<'tcx>, +) { + let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID); + + let param_env = ty::ParamEnv::empty(); + + let infcx = &tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(infcx); + + let unnormalized_actual_sig = infcx.instantiate_binder_with_fresh_vars( + cause.span, + infer::HigherRankedType, + tcx.fn_sig(fn_id).instantiate_identity(), + ); + + let norm_cause = ObligationCause::misc(cause.span, local_id); + let actual_sig = ocx.normalize(&norm_cause, param_env, unnormalized_actual_sig); + + let expected_sig = tcx.liberate_late_bound_regions(fn_id, expected_sig); + + match ocx.eq(&cause, param_env, expected_sig, actual_sig) { + Ok(()) => { + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors); + return; + } + } + Err(err) => { + let err_ctxt = infcx.err_ctxt(); + if fn_id.is_local() { + cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id); + } + let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]); + let mut diag = tcx.sess.create_err(failure_code); + err_ctxt.note_type_err( + &mut diag, + &cause, + None, + Some(infer::ValuePairs::Sigs(ExpectedFound { + expected: expected_sig, + found: actual_sig, + })), + err, + false, + false, + ); + diag.emit(); + return; + } + } + + let outlives_env = OutlivesEnvironment::new(param_env); + let _ = ocx.resolve_regions_and_report_errors(local_id, &outlives_env); + + fn extract_span_for_error_reporting<'tcx>( + tcx: TyCtxt<'tcx>, + err: TypeError<'_>, + cause: &ObligationCause<'tcx>, + fn_id: LocalDefId, + ) -> rustc_span::Span { + let mut args = { + let node = tcx.hir().expect_owner(fn_id); + let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node)); + decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span())) + }; + + match err { + TypeError::ArgumentMutability(i) + | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(), + _ => cause.span(), + } + } +} diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index ef788935efba..03963925d3db 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -99,7 +99,6 @@ use rustc_errors::ErrorGuaranteed; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; -use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::middle; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -107,8 +106,7 @@ use rustc_middle::util; use rustc_session::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 _; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt}; +use rustc_trait_selection::traits; use astconv::{AstConv, OnlySelfBounds}; use bounds::Bounds; @@ -151,28 +149,6 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi tcx.sess.emit_err(errors::VariadicFunctionCompatibleConvention { span, conventions }); } -fn require_same_types<'tcx>( - tcx: TyCtxt<'tcx>, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - expected: Ty<'tcx>, - actual: Ty<'tcx>, -) { - let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); - match ocx.eq(cause, param_env, expected, actual) { - Ok(()) => { - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors); - } - } - Err(err) => { - infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit(); - } - } -} - pub fn provide(providers: &mut Providers) { collect::provide(providers); coherence::provide(providers); diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 921a5f5154a1..9950a226333e 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -83,16 +83,6 @@ hir_typeck_int_to_fat_label_nightly = consider casting this expression to `*cons hir_typeck_invalid_callee = expected function, found {$ty} -hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` -hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item -hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count} - -hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect - .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` - -hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect - .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` - hir_typeck_lossy_provenance_int2ptr = strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}` .suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 1fc1e5aca2b3..041cc1abd54e 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -1,7 +1,6 @@ +use std::cell::RefCell; + use crate::coercion::CoerceMany; -use crate::errors::{ - LangStartIncorrectNumberArgs, LangStartIncorrectParam, LangStartIncorrectRetTy, -}; use crate::gather_locals::GatherLocalsVisitor; use crate::FnCtxt; use crate::GeneratorTypes; @@ -9,14 +8,15 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir_analysis::check::fn_maybe_err; +use rustc_hir_analysis::check::{check_function_signature, fn_maybe_err}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::RegionVariableOrigin; use rustc_middle::ty::{self, Binder, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; -use std::cell::RefCell; +use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; /// Helper used for fns and closures. Does the grungy work of checking a function /// body and returns the function context used for that purpose, since in the case of a fn item @@ -166,52 +166,17 @@ pub(super) fn check_fn<'a, 'tcx>( if let Some(panic_impl_did) = tcx.lang_items().panic_impl() && panic_impl_did == fn_def_id.to_def_id() { - check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty); + check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig); } if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == fn_def_id.to_def_id() { - check_lang_start_fn(tcx, fn_sig, decl, fn_def_id); + check_lang_start_fn(tcx, fn_sig, fn_def_id); } gen_ty } -fn check_panic_info_fn( - tcx: TyCtxt<'_>, - fn_id: LocalDefId, - fn_sig: ty::FnSig<'_>, - decl: &hir::FnDecl<'_>, - declared_ret_ty: Ty<'_>, -) { - let Some(panic_info_did) = tcx.lang_items().panic_info() else { - tcx.sess.err("language item required, but not found: `panic_info`"); - 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_panic_info = match *inputs[0].kind() { - ty::Ref(region, ty, mutbl) => match *ty.kind() { - ty::Adt(ref adt, _) => { - adt.did() == panic_info_did && mutbl.is_not() && !region.is_static() - } - _ => false, - }, - _ => false, - }; - - if !arg_is_panic_info { - tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); - } - +fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) { let DefKind::Fn = tcx.def_kind(fn_id) else { let span = tcx.def_span(fn_id); tcx.sess.span_err(span, "should be a function"); @@ -227,125 +192,87 @@ fn check_panic_info_fn( let span = tcx.def_span(fn_id); tcx.sess.span_err(span, "should have no const parameters"); } + + let Some(panic_info_did) = tcx.lang_items().panic_info() else { + tcx.sess.err("language item required, but not found: `panic_info`"); + return; + }; + + // build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` + let panic_info_ty = tcx.type_of(panic_info_did).instantiate( + tcx, + &[ty::GenericArg::from(ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon(None) }, + ))], + ); + let panic_info_ref_ty = Ty::new_imm_ref( + tcx, + ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }, + ), + panic_info_ty, + ); + + let bounds = tcx.mk_bound_variable_kinds(&[ + ty::BoundVariableKind::Region(ty::BrAnon(None)), + ty::BoundVariableKind::Region(ty::BrAnon(None)), + ]); + let expected_sig = ty::Binder::bind_with_vars( + tcx.mk_fn_sig([panic_info_ref_ty], tcx.types.never, false, fn_sig.unsafety, Abi::Rust), + bounds, + ); + + check_function_signature( + tcx, + ObligationCause::new( + tcx.def_span(fn_id), + fn_id, + ObligationCauseCode::LangFunctionType(sym::panic_impl), + ), + fn_id.into(), + expected_sig, + ); } -fn check_lang_start_fn<'tcx>( - tcx: TyCtxt<'tcx>, - fn_sig: ty::FnSig<'tcx>, - decl: &'tcx hir::FnDecl<'tcx>, - def_id: LocalDefId, -) { - let inputs = fn_sig.inputs(); +fn check_lang_start_fn<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: ty::FnSig<'tcx>, def_id: LocalDefId) { + // build type `fn(main: fn() -> T, argc: isize, argv: *const *const u8, sigpipe: u8)` - let arg_count = inputs.len(); - if arg_count != 4 { - tcx.sess.emit_err(LangStartIncorrectNumberArgs { - params_span: tcx.def_span(def_id), - found_param_count: arg_count, - }); - } + // make a Ty for the generic on the fn for diagnostics + // FIXME: make the lang item generic checks check for the right generic *kind* + // for example `start`'s generic should be a type parameter + let generics = tcx.generics_of(def_id); + let fn_generic = generics.param_at(0, tcx); + let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name); + let main_fn_ty = Ty::new_fn_ptr( + tcx, + Binder::dummy(tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust)), + ); - // only check args if they should exist by checking the count - // note: this does not handle args being shifted or their order swapped very nicely - // but it's a lang item, users shouldn't frequently encounter this + let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig( + [ + main_fn_ty, + tcx.types.isize, + Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8)), + tcx.types.u8, + ], + tcx.types.isize, + false, + fn_sig.unsafety, + Abi::Rust, + )); - // first arg is `main: fn() -> T` - if let Some(&main_arg) = inputs.get(0) { - // make a Ty for the generic on the fn for diagnostics - // FIXME: make the lang item generic checks check for the right generic *kind* - // for example `start`'s generic should be a type parameter - let generics = tcx.generics_of(def_id); - let fn_generic = generics.param_at(0, tcx); - let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name); - let expected_fn_sig = - tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust); - let expected_ty = Ty::new_fn_ptr(tcx, Binder::dummy(expected_fn_sig)); - - // we emit the same error to suggest changing the arg no matter what's wrong with the arg - let emit_main_fn_arg_err = || { - tcx.sess.emit_err(LangStartIncorrectParam { - param_span: decl.inputs[0].span, - param_num: 1, - expected_ty: expected_ty, - found_ty: main_arg, - }); - }; - - if let ty::FnPtr(main_fn_sig) = main_arg.kind() { - let main_fn_inputs = main_fn_sig.inputs(); - if main_fn_inputs.iter().count() != 0 { - emit_main_fn_arg_err(); - } - - let output = main_fn_sig.output(); - output.map_bound(|ret_ty| { - // if the output ty is a generic, it's probably the right one - if !matches!(ret_ty.kind(), ty::Param(_)) { - emit_main_fn_arg_err(); - } - }); - } else { - emit_main_fn_arg_err(); - } - } - - // second arg is isize - if let Some(&argc_arg) = inputs.get(1) { - if argc_arg != tcx.types.isize { - tcx.sess.emit_err(LangStartIncorrectParam { - param_span: decl.inputs[1].span, - param_num: 2, - expected_ty: tcx.types.isize, - found_ty: argc_arg, - }); - } - } - - // third arg is `*const *const u8` - if let Some(&argv_arg) = inputs.get(2) { - let mut argv_is_okay = false; - if let ty::RawPtr(outer_ptr) = argv_arg.kind() { - if outer_ptr.mutbl.is_not() { - if let ty::RawPtr(inner_ptr) = outer_ptr.ty.kind() { - if inner_ptr.mutbl.is_not() && inner_ptr.ty == tcx.types.u8 { - argv_is_okay = true; - } - } - } - } - - if !argv_is_okay { - let inner_ptr_ty = - Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 }); - let expected_ty = - Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty }); - tcx.sess.emit_err(LangStartIncorrectParam { - param_span: decl.inputs[2].span, - param_num: 3, - expected_ty, - found_ty: argv_arg, - }); - } - } - - // fourth arg is `sigpipe: u8` - if let Some(&sigpipe_arg) = inputs.get(3) { - if sigpipe_arg != tcx.types.u8 { - tcx.sess.emit_err(LangStartIncorrectParam { - param_span: decl.inputs[3].span, - param_num: 4, - expected_ty: tcx.types.u8, - found_ty: sigpipe_arg, - }); - } - } - - // output type is isize - if fn_sig.output() != tcx.types.isize { - tcx.sess.emit_err(LangStartIncorrectRetTy { - ret_span: decl.output.span(), - expected_ty: tcx.types.isize, - found_ty: fn_sig.output(), - }); - } + check_function_signature( + tcx, + ObligationCause::new( + tcx.def_span(def_id), + def_id, + ObligationCauseCode::LangFunctionType(sym::start), + ), + def_id.into(), + expected_sig, + ); } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 7152585d4408..1526988fbd92 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -236,39 +236,6 @@ impl AddToDiagnostic for TypeMismatchFruTypo { } } -#[derive(Diagnostic)] -#[diag(hir_typeck_lang_start_incorrect_number_params)] -#[note(hir_typeck_lang_start_incorrect_number_params_note_expected_count)] -#[note(hir_typeck_lang_start_expected_sig_note)] -pub struct LangStartIncorrectNumberArgs { - #[primary_span] - pub params_span: Span, - pub found_param_count: usize, -} - -#[derive(Diagnostic)] -#[diag(hir_typeck_lang_start_incorrect_param)] -pub struct LangStartIncorrectParam<'tcx> { - #[primary_span] - #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")] - pub param_span: Span, - - pub param_num: usize, - pub expected_ty: Ty<'tcx>, - pub found_ty: Ty<'tcx>, -} - -#[derive(Diagnostic)] -#[diag(hir_typeck_lang_start_incorrect_ret_ty)] -pub struct LangStartIncorrectRetTy<'tcx> { - #[primary_span] - #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")] - pub ret_span: Span, - - pub expected_ty: Ty<'tcx>, - pub found_ty: Ty<'tcx>, -} - #[derive(LintDiagnostic)] #[diag(hir_typeck_lossy_provenance_int2ptr)] #[help] diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 4d0e77063672..46558997f723 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -198,6 +198,10 @@ infer_nothing = {""} infer_oc_cant_coerce = cannot coerce intrinsics to function pointers infer_oc_closure_selfref = closure/generator type that references itself infer_oc_const_compat = const not compatible with trait +infer_oc_fn_lang_correct_type = {$lang_item_name -> + [panic_impl] `#[panic_handler]` + *[lang_item_name] lang item `{$lang_item_name}` + } function has wrong type infer_oc_fn_main_correct_type = `main` function has wrong type infer_oc_fn_start_correct_type = `#[start]` function has wrong type infer_oc_generic = mismatched types @@ -337,6 +341,7 @@ infer_subtype = ...so that the {$requirement -> [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type [fn_start_correct_type] `#[start]` function has the correct type + [fn_lang_correct_type] lang item function has the correct type [intrinsic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type *[other] types are compatible @@ -350,6 +355,7 @@ infer_subtype_2 = ...so that {$requirement -> [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type [fn_start_correct_type] `#[start]` function has the correct type + [fn_lang_correct_type] lang item function has the correct type [intrinsic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type *[other] types are compatible diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index a7e045e1e894..38910e45eccc 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1463,6 +1463,14 @@ pub enum ObligationCauseFailureCode { #[subdiagnostic] subdiags: Vec, }, + #[diag(infer_oc_fn_lang_correct_type, code = "E0308")] + FnLangCorrectType { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + lang_item_name: Symbol, + }, #[diag(infer_oc_intrinsic_correct_type, code = "E0308")] IntrinsicCorrectType { #[primary_span] diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 6dba5d2945db..2ca5b7d657dd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2927,6 +2927,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { | IfExpression { .. } | LetElse | StartFunctionType + | LangFunctionType(_) | IntrinsicType | MethodReceiver => Error0308, @@ -2971,6 +2972,9 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags }, MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span }, StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }, + &LangFunctionType(lang_item_name) => { + ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name } + } IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags }, MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags }, @@ -3006,6 +3010,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { IfExpressionWithNoElse => "`if` missing an `else` returns `()`", MainFunctionType => "`main` function has the correct type", StartFunctionType => "`#[start]` function has the correct type", + LangFunctionType(_) => "lang item function has the correct type", IntrinsicType => "intrinsic has the correct type", MethodReceiver => "method receiver has the correct type", _ => "types are compatible", @@ -3028,6 +3033,7 @@ impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> { IfExpressionWithNoElse => "no_else", MainFunctionType => "fn_main_correct_type", StartFunctionType => "fn_start_correct_type", + LangFunctionType(_) => "fn_lang_correct_type", IntrinsicType => "intrinsic_correct_type", MethodReceiver => "method_correct_type", _ => "other", diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 1340e674568f..eef193a657de 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -378,6 +378,9 @@ pub enum ObligationCauseCode<'tcx> { /// `start` has wrong type StartFunctionType, + /// language function has wrong type + LangFunctionType(Symbol), + /// Intrinsic has wrong type IntrinsicType, 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 a08ebe5a9ea8..64d1308b83f9 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2711,6 +2711,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::IfExpressionWithNoElse | ObligationCauseCode::MainFunctionType | ObligationCauseCode::StartFunctionType + | ObligationCauseCode::LangFunctionType(_) | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression diff --git a/tests/ui/associated-inherent-types/issue-111879-1.stderr b/tests/ui/associated-inherent-types/issue-111879-1.stderr index 689b45e09aaa..bf35f2bb5b53 100644 --- a/tests/ui/associated-inherent-types/issue-111879-1.stderr +++ b/tests/ui/associated-inherent-types/issue-111879-1.stderr @@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type LL | fn main(_: for<'a> fn(Foo::Assoc)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn()` - found fn pointer `fn(for<'a> fn(Foo::Assoc))` + = note: expected signature `fn()` + found signature `fn(for<'a> fn(&'a ()))` error: aborting due to previous error diff --git a/tests/ui/borrowck/issue-92157.rs b/tests/ui/borrowck/issue-92157.rs index 6ee2320a603a..3a6f8908b219 100644 --- a/tests/ui/borrowck/issue-92157.rs +++ b/tests/ui/borrowck/issue-92157.rs @@ -9,7 +9,7 @@ extern {} #[lang = "start"] fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - //~^ ERROR: incorrect number of parameters for the `start` lang item + //~^ ERROR lang item `start` function has wrong type [E0308] 40+2 } diff --git a/tests/ui/borrowck/issue-92157.stderr b/tests/ui/borrowck/issue-92157.stderr index a4010d73d057..a46b1288911d 100644 --- a/tests/ui/borrowck/issue-92157.stderr +++ b/tests/ui/borrowck/issue-92157.stderr @@ -1,11 +1,12 @@ -error: incorrect number of parameters for the `start` lang item +error[E0308]: lang item `start` function has wrong type --> $DIR/issue-92157.rs:11:1 | LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: the `start` lang item should have four parameters, but found 3 - = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _` + found signature `fn(fn() -> T, isize, *const *const u8) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/entry-point/auxiliary/bad_main_functions.rs b/tests/ui/entry-point/auxiliary/bad_main_functions.rs new file mode 100644 index 000000000000..4649be99e6f2 --- /dev/null +++ b/tests/ui/entry-point/auxiliary/bad_main_functions.rs @@ -0,0 +1,2 @@ +pub fn boilerplate(x: u8) {} +//~^ ERROR: `main` function has wrong type [E0580] diff --git a/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs new file mode 100644 index 000000000000..0a115dd3b081 --- /dev/null +++ b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.rs @@ -0,0 +1,6 @@ +// aux-build:bad_main_functions.rs + +#![feature(imported_main)] + +extern crate bad_main_functions; +pub use bad_main_functions::boilerplate as main; diff --git a/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.stderr b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.stderr new file mode 100644 index 000000000000..3c68933101c8 --- /dev/null +++ b/tests/ui/entry-point/imported_main_from_extern_crate_wrong_type.stderr @@ -0,0 +1,12 @@ +error[E0580]: `main` function has wrong type + --> $DIR/auxiliary/bad_main_functions.rs:1:1 + | +LL | pub fn boilerplate(x: u8) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters + | + = note: expected signature `fn()` + found signature `fn(u8)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0580`. diff --git a/tests/ui/error-codes/E0308.stderr b/tests/ui/error-codes/E0308.stderr index 187b775f92dc..141abed6032e 100644 --- a/tests/ui/error-codes/E0308.stderr +++ b/tests/ui/error-codes/E0308.stderr @@ -1,11 +1,11 @@ error[E0308]: intrinsic has wrong type - --> $DIR/E0308.rs:6:5 + --> $DIR/E0308.rs:6:20 | LL | fn size_of(); - | ^^^^^^^^^^^^^^^^ expected `()`, found `usize` + | ^ expected `usize`, found `()` | - = note: expected fn pointer `extern "rust-intrinsic" fn()` - found fn pointer `extern "rust-intrinsic" fn() -> usize` + = note: expected signature `extern "rust-intrinsic" fn() -> usize` + found signature `extern "rust-intrinsic" fn()` error: aborting due to previous error diff --git a/tests/ui/extern/extern-main-fn.stderr b/tests/ui/extern/extern-main-fn.stderr index 136c95753824..846102670a83 100644 --- a/tests/ui/extern/extern-main-fn.stderr +++ b/tests/ui/extern/extern-main-fn.stderr @@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type LL | extern "C" fn main() {} | ^^^^^^^^^^^^^^^^^^^^ expected "Rust" fn, found "C" fn | - = note: expected fn pointer `fn()` - found fn pointer `extern "C" fn()` + = note: expected signature `fn()` + found signature `extern "C" fn()` error: aborting due to previous error diff --git a/tests/ui/fn/bad-main.stderr b/tests/ui/fn/bad-main.stderr index 675b66d05783..65140a0794f8 100644 --- a/tests/ui/fn/bad-main.stderr +++ b/tests/ui/fn/bad-main.stderr @@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type LL | fn main(x: isize) { } | ^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn()` - found fn pointer `fn(isize)` + = note: expected signature `fn()` + found signature `fn(isize)` error: aborting due to previous error diff --git a/tests/ui/issues/issue-9575.stderr b/tests/ui/issues/issue-9575.stderr index 5b8ce84a0716..e49eac3babf8 100644 --- a/tests/ui/issues/issue-9575.stderr +++ b/tests/ui/issues/issue-9575.stderr @@ -4,8 +4,8 @@ error[E0308]: `#[start]` function has wrong type LL | fn start(argc: isize, argv: *const *const u8, crate_map: *const u8) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn(isize, *const *const u8) -> _` - found fn pointer `fn(isize, *const *const u8, *const u8) -> _` + = note: expected signature `fn(isize, *const *const u8) -> _` + found signature `fn(isize, *const *const u8, *const u8) -> _` error: aborting due to previous error diff --git a/tests/ui/lang-items/start_lang_item_args.argc.stderr b/tests/ui/lang-items/start_lang_item_args.argc.stderr index 65c99a93c751..66d4397a2935 100644 --- a/tests/ui/lang-items/start_lang_item_args.argc.stderr +++ b/tests/ui/lang-items/start_lang_item_args.argc.stderr @@ -1,8 +1,12 @@ -error: parameter 2 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:75:38 | LL | fn start(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ^^ help: change the type from `i8` to `isize` + | ^^ expected `isize`, found `i8` + | + = note: expected signature `fn(fn() -> _, isize, _, _) -> _` + found signature `fn(fn() -> _, i8, _, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.argv.stderr b/tests/ui/lang-items/start_lang_item_args.argv.stderr index f0947a9b3e93..53d776cd846a 100644 --- a/tests/ui/lang-items/start_lang_item_args.argv.stderr +++ b/tests/ui/lang-items/start_lang_item_args.argv.stderr @@ -1,8 +1,12 @@ -error: parameter 3 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:89:52 | LL | fn start(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize { - | ^^ help: change the type from `u8` to `*const *const u8` + | ^^ expected `*const *const u8`, found `u8` + | + = note: expected signature `fn(fn() -> _, _, *const *const u8, _) -> _` + found signature `fn(fn() -> _, _, u8, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr index 08efd5088f99..7d002e090b5a 100644 --- a/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr +++ b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr @@ -1,13 +1,12 @@ -error: parameter 3 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:82:52 | LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize { - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ expected `u8`, found `usize` | -help: change the type from `*const *const usize` to `*const *const u8` - | -LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ~~~~~~~~~~~~~~~~ + = note: expected signature `fn(fn() -> _, _, *const *const u8, _) -> _` + found signature `fn(fn() -> _, _, *const *const usize, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.main_args.stderr b/tests/ui/lang-items/start_lang_item_args.main_args.stderr index c20a744661d4..91994b9d7429 100644 --- a/tests/ui/lang-items/start_lang_item_args.main_args.stderr +++ b/tests/ui/lang-items/start_lang_item_args.main_args.stderr @@ -1,13 +1,12 @@ -error: parameter 1 of the `start` lang item is incorrect - --> $DIR/start_lang_item_args.rs:61:20 +error[E0308]: lang item `start` function has wrong type + --> $DIR/start_lang_item_args.rs:61:1 | LL | fn start(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | -help: change the type from `fn(i32) -> T` to `fn() -> T` - | -LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ~~~~~~~~~ + = note: expected signature `fn(fn() -> _, _, _, _) -> _` + found signature `fn(fn(i32) -> _, _, _, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.main_ret.stderr b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr index 8f967252f49b..4582b69850cf 100644 --- a/tests/ui/lang-items/start_lang_item_args.main_ret.stderr +++ b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr @@ -1,13 +1,14 @@ -error: parameter 1 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:68:20 | LL | fn start(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ^^^^^^^^^^^ + | - ^^^^^^^^^^^ expected type parameter `T`, found `u16` + | | + | this type parameter | -help: change the type from `fn() -> u16` to `fn() -> T` - | -LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ~~~~~~~~~ + = note: expected signature `fn(fn() -> T, _, _, _) -> _` + found signature `fn(fn() -> u16, _, _, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.main_ty.stderr b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr index deb37b868ea8..87940d05e785 100644 --- a/tests/ui/lang-items/start_lang_item_args.main_ty.stderr +++ b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr @@ -1,8 +1,12 @@ -error: parameter 1 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:54:20 | LL | fn start(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - | ^^^ help: change the type from `u64` to `fn() -> T` + | ^^^ expected fn pointer, found `u64` + | + = note: expected signature `fn(fn() -> T, _, _, _) -> _` + found signature `fn(u64, _, _, _) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr index 004c2a67f62f..5363871e2022 100644 --- a/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr +++ b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr @@ -1,11 +1,12 @@ -error: incorrect number of parameters for the `start` lang item +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:15:1 | LL | fn start() -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: the `start` lang item should have four parameters, but found 0 - = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _` + found signature `fn() -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr index 1d8285b59000..2bb29f911a12 100644 --- a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr +++ b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr @@ -1,8 +1,12 @@ -error: the return type of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:29:84 | LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {} - | ^ help: change the type from `()` to `isize` + | ^ expected `isize`, found `()` + | + = note: expected signature `fn(fn() -> _, _, _, _) -> isize` + found signature `fn(fn() -> _, _, _, _)` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr index e545a750f24a..f873f7614bdc 100644 --- a/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr +++ b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr @@ -1,11 +1,12 @@ -error: incorrect number of parameters for the `start` lang item +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:22:1 | LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: the `start` lang item should have four parameters, but found 3 - = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _` + found signature `fn(fn() -> T, isize, *const *const u8) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.rs b/tests/ui/lang-items/start_lang_item_args.rs index 0dbfba39cb60..4a0302bcb152 100644 --- a/tests/ui/lang-items/start_lang_item_args.rs +++ b/tests/ui/lang-items/start_lang_item_args.rs @@ -13,33 +13,33 @@ pub trait Sized {} #[cfg(missing_all_args)] #[lang = "start"] fn start() -> isize { - //[missing_all_args]~^ ERROR incorrect number of parameters + //[missing_all_args]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(missing_sigpipe_arg)] #[lang = "start"] fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - //[missing_sigpipe_arg]~^ ERROR incorrect number of parameters + //[missing_sigpipe_arg]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(missing_ret)] #[lang = "start"] fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {} -//[missing_ret]~^ ERROR the return type of the `start` lang item is incorrect +//[missing_ret]~^ ERROR lang item `start` function has wrong type [E0308] #[cfg(start_ret)] #[lang = "start"] fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 { - //[start_ret]~^ ERROR the return type of the `start` lang item is incorrect + //[start_ret]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(too_many_args)] #[lang = "start"] fn start( - //[too_many_args]~^ ERROR incorrect number of parameters + //[too_many_args]~^ ERROR lang item `start` function has wrong type [E0308] _main: fn() -> T, _argc: isize, _argv: *const *const u8, @@ -52,49 +52,49 @@ fn start( #[cfg(main_ty)] #[lang = "start"] fn start(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - //[main_ty]~^ ERROR parameter 1 of the `start` lang item is incorrect + //[main_ty]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(main_args)] #[lang = "start"] fn start(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - //[main_args]~^ ERROR parameter 1 of the `start` lang item is incorrect + //[main_args]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(main_ret)] #[lang = "start"] fn start(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { - //[main_ret]~^ ERROR parameter 1 of the `start` lang item is incorrect + //[main_ret]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(argc)] #[lang = "start"] fn start(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize { - //[argc]~^ ERROR parameter 2 of the `start` lang item is incorrect + //[argc]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(argv_inner_ptr)] #[lang = "start"] fn start(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize { - //[argv_inner_ptr]~^ ERROR parameter 3 of the `start` lang item is incorrect + //[argv_inner_ptr]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(argv)] #[lang = "start"] fn start(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize { - //[argv]~^ ERROR parameter 3 of the `start` lang item is incorrect + //[argv]~^ ERROR lang item `start` function has wrong type [E0308] 100 } #[cfg(sigpipe)] #[lang = "start"] fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize { - //[sigpipe]~^ ERROR parameter 4 of the `start` lang item is incorrect + //[sigpipe]~^ ERROR lang item `start` function has wrong type [E0308] 100 } diff --git a/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr index b20ae3128013..280d423bd7e1 100644 --- a/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr +++ b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr @@ -1,8 +1,12 @@ -error: parameter 4 of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:96:80 | LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize { - | ^^^ help: change the type from `i64` to `u8` + | ^^^ expected `u8`, found `i64` + | + = note: expected signature `fn(fn() -> _, _, _, u8) -> _` + found signature `fn(fn() -> _, _, _, i64) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.start_ret.stderr b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr index 935d5f3c8b42..4e4f8a5cdb39 100644 --- a/tests/ui/lang-items/start_lang_item_args.start_ret.stderr +++ b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr @@ -1,8 +1,12 @@ -error: the return type of the `start` lang item is incorrect +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:34:87 | LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 { - | ^^ help: change the type from `u8` to `isize` + | ^^ expected `isize`, found `u8` + | + = note: expected signature `fn(fn() -> _, _, _, _) -> isize` + found signature `fn(fn() -> _, _, _, _) -> u8` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr index 30a7ed18a3d2..085d4b1f238e 100644 --- a/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr +++ b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr @@ -1,4 +1,4 @@ -error: incorrect number of parameters for the `start` lang item +error[E0308]: lang item `start` function has wrong type --> $DIR/start_lang_item_args.rs:41:1 | LL | / fn start( @@ -8,10 +8,11 @@ LL | | _argc: isize, ... | LL | | _extra_arg: (), LL | | ) -> isize { - | |__________^ + | |__________^ incorrect number of function parameters | - = note: the `start` lang item should have four parameters, but found 5 - = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _` + found signature `fn(fn() -> T, isize, *const *const u8, u8, ()) -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/main-wrong-type.stderr b/tests/ui/main-wrong-type.stderr index 43efaf884e3a..1e5f368758e6 100644 --- a/tests/ui/main-wrong-type.stderr +++ b/tests/ui/main-wrong-type.stderr @@ -4,8 +4,8 @@ error[E0580]: `main` function has wrong type LL | fn main(foo: S) { | ^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn()` - found fn pointer `fn(S)` + = note: expected signature `fn()` + found signature `fn(S)` error: aborting due to previous error diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-1.rs b/tests/ui/panic-handler/panic-handler-bad-signature-1.rs index 775961d3fd74..ae27db7a8352 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-1.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.rs @@ -6,8 +6,5 @@ use core::panic::PanicInfo; #[panic_handler] -fn panic( - info: PanicInfo, //~ ERROR argument should be `&PanicInfo` -) -> () //~ ERROR return type should be `!` -{ -} +fn panic(info: PanicInfo) -> () {} +//~^ `#[panic_handler]` function has wrong type [E0308] diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr index 8b044f7669c7..d12bfbf269eb 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr @@ -1,14 +1,12 @@ -error: return type should be `!` - --> $DIR/panic-handler-bad-signature-1.rs:11:6 +error[E0308]: `#[panic_handler]` function has wrong type + --> $DIR/panic-handler-bad-signature-1.rs:9:16 | -LL | ) -> () - | ^^ - -error: argument should be `&PanicInfo` - --> $DIR/panic-handler-bad-signature-1.rs:10:11 +LL | fn panic(info: PanicInfo) -> () {} + | ^^^^^^^^^ expected `&PanicInfo<'_>`, found `PanicInfo<'_>` | -LL | info: PanicInfo, - | ^^^^^^^^^ + = note: expected signature `fn(&PanicInfo<'_>) -> !` + found signature `fn(PanicInfo<'_>)` -error: aborting due to 2 previous errors +error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-2.rs b/tests/ui/panic-handler/panic-handler-bad-signature-2.rs index 727934000589..3c3f1513f6fe 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-2.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-2.rs @@ -6,9 +6,8 @@ use core::panic::PanicInfo; #[panic_handler] -fn panic( - info: &'static PanicInfo, //~ ERROR argument should be `&PanicInfo` -) -> ! +fn panic(info: &'static PanicInfo) -> ! +//~^ #[panic_handler]` function has wrong type [E0308] { loop {} } diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr index 5ab6934202e9..37c737d974db 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr @@ -1,8 +1,18 @@ -error: argument should be `&PanicInfo` - --> $DIR/panic-handler-bad-signature-2.rs:10:11 +error[E0308]: `#[panic_handler]` function has wrong type + --> $DIR/panic-handler-bad-signature-2.rs:9:1 | -LL | info: &'static PanicInfo, - | ^^^^^^^^^^^^^^^^^^ +LL | fn panic(info: &'static PanicInfo) -> ! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected signature `fn(&PanicInfo<'_>) -> _` + found signature `fn(&'static PanicInfo<'_>) -> _` +note: the anonymous lifetime as defined here... + --> $DIR/panic-handler-bad-signature-2.rs:9:1 + | +LL | fn panic(info: &'static PanicInfo) -> ! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...does not necessarily outlive the static lifetime error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-3.rs b/tests/ui/panic-handler/panic-handler-bad-signature-3.rs index ab9c9d7f4177..9e17e32fbb4c 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-3.rs +++ b/tests/ui/panic-handler/panic-handler-bad-signature-3.rs @@ -6,6 +6,6 @@ use core::panic::PanicInfo; #[panic_handler] -fn panic() -> ! { //~ ERROR function should have one argument +fn panic() -> ! { //~ #[panic_handler]` function has wrong type [E0308] loop {} } diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr index 0a70181fdace..8365f5769ebe 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-3.stderr @@ -1,8 +1,12 @@ -error: function should have one argument +error[E0308]: `#[panic_handler]` function has wrong type --> $DIR/panic-handler-bad-signature-3.rs:9:1 | LL | fn panic() -> ! { - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ incorrect number of function parameters + | + = note: expected signature `fn(&PanicInfo<'_>) -> _` + found signature `fn() -> _` error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-5.rs b/tests/ui/panic-handler/panic-handler-bad-signature-5.rs new file mode 100644 index 000000000000..97307d1b2a46 --- /dev/null +++ b/tests/ui/panic-handler/panic-handler-bad-signature-5.rs @@ -0,0 +1,13 @@ +// compile-flags:-C panic=abort + +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_handler] +fn panic(info: &PanicInfo<'static>) -> ! +//~^ #[panic_handler]` function has wrong type [E0308] +{ + loop {} +} diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr new file mode 100644 index 000000000000..2745c05834ca --- /dev/null +++ b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr @@ -0,0 +1,18 @@ +error[E0308]: `#[panic_handler]` function has wrong type + --> $DIR/panic-handler-bad-signature-5.rs:9:1 + | +LL | fn panic(info: &PanicInfo<'static>) -> ! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected signature `fn(&PanicInfo<'_>) -> _` + found signature `fn(&PanicInfo<'static>) -> _` +note: the anonymous lifetime as defined here... + --> $DIR/panic-handler-bad-signature-5.rs:9:1 + | +LL | fn panic(info: &PanicInfo<'static>) -> ! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...does not necessarily outlive the static lifetime + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/range/issue-54505-no-std.rs b/tests/ui/range/issue-54505-no-std.rs index db455fada3bd..a15956853729 100644 --- a/tests/ui/range/issue-54505-no-std.rs +++ b/tests/ui/range/issue-54505-no-std.rs @@ -17,9 +17,9 @@ extern "C" fn eh_personality() {} static EH_CATCH_TYPEINFO: u8 = 0; #[panic_handler] -fn panic_handler() {} -//~^ ERROR return type should be `!` -//~| ERROR function should have one argument +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + unimplemented!(); +} // take a reference to any built-in range fn take_range(_r: &impl RangeBounds) {} diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr index 13563d1940cb..1694d514f425 100644 --- a/tests/ui/range/issue-54505-no-std.stderr +++ b/tests/ui/range/issue-54505-no-std.stderr @@ -1,15 +1,3 @@ -error: return type should be `!` - --> $DIR/issue-54505-no-std.rs:20:20 - | -LL | fn panic_handler() {} - | ^ - -error: function should have one argument - --> $DIR/issue-54505-no-std.rs:20:1 - | -LL | fn panic_handler() {} - | ^^^^^^^^^^^^^^^^^^ - error[E0308]: mismatched types --> $DIR/issue-54505-no-std.rs:29:16 | @@ -130,6 +118,6 @@ help: consider borrowing here LL | take_range(&(..=42)); | ++ + -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/resolve/bad-expr-path.stderr b/tests/ui/resolve/bad-expr-path.stderr index 411130913c8f..0392c1fa2399 100644 --- a/tests/ui/resolve/bad-expr-path.stderr +++ b/tests/ui/resolve/bad-expr-path.stderr @@ -16,8 +16,8 @@ error[E0580]: `main` function has wrong type LL | fn main(arguments: Vec) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn()` - found fn pointer `fn(Vec)` + = note: expected signature `fn()` + found signature `fn(Vec)` error[E0425]: cannot find function `log` in this scope --> $DIR/bad-expr-path.rs:4:5 diff --git a/tests/ui/resolve/bad-expr-path2.stderr b/tests/ui/resolve/bad-expr-path2.stderr index af3ca99c5102..9238b1f7023e 100644 --- a/tests/ui/resolve/bad-expr-path2.stderr +++ b/tests/ui/resolve/bad-expr-path2.stderr @@ -16,8 +16,8 @@ error[E0580]: `main` function has wrong type LL | fn main(arguments: Vec) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected fn pointer `fn()` - found fn pointer `fn(Vec)` + = note: expected signature `fn()` + found signature `fn(Vec)` error[E0425]: cannot find function `log` in this scope --> $DIR/bad-expr-path2.rs:6:5 From 85d61b01aea90d9201c35c4bd61a508c72807c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Tue, 19 Sep 2023 21:15:58 +0200 Subject: [PATCH 03/26] wrap fn sig binders in fn ptr --- compiler/rustc_hir_analysis/src/check/mod.rs | 17 +++++++---------- .../panic-handler-bad-signature-2.stderr | 12 +++--------- .../panic-handler-bad-signature-5.stderr | 12 +++--------- 3 files changed, 13 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index b9ce4c079227..0cf3cee66b56 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -568,18 +568,15 @@ pub fn check_function_signature<'tcx>( let infcx = &tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new(infcx); - let unnormalized_actual_sig = infcx.instantiate_binder_with_fresh_vars( - cause.span, - infer::HigherRankedType, - tcx.fn_sig(fn_id).instantiate_identity(), - ); + let actual_sig = tcx.fn_sig(fn_id).instantiate_identity(); let norm_cause = ObligationCause::misc(cause.span, local_id); - let actual_sig = ocx.normalize(&norm_cause, param_env, unnormalized_actual_sig); + let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig); - let expected_sig = tcx.liberate_late_bound_regions(fn_id, expected_sig); + let expected_ty = Ty::new_fn_ptr(tcx, expected_sig); + let actual_ty = Ty::new_fn_ptr(tcx, actual_sig); - match ocx.eq(&cause, param_env, expected_sig, actual_sig) { + match ocx.eq(&cause, param_env, expected_ty, actual_ty) { Ok(()) => { let errors = ocx.select_all_or_error(); if !errors.is_empty() { @@ -599,8 +596,8 @@ pub fn check_function_signature<'tcx>( &cause, None, Some(infer::ValuePairs::Sigs(ExpectedFound { - expected: expected_sig, - found: actual_sig, + expected: tcx.liberate_late_bound_regions(fn_id, expected_sig), + found: tcx.liberate_late_bound_regions(fn_id, actual_sig), })), err, false, diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr index 37c737d974db..06e32d5fb84a 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-2.stderr @@ -2,16 +2,10 @@ error[E0308]: `#[panic_handler]` function has wrong type --> $DIR/panic-handler-bad-signature-2.rs:9:1 | LL | fn panic(info: &'static PanicInfo) -> ! - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected signature `fn(&PanicInfo<'_>) -> _` - found signature `fn(&'static PanicInfo<'_>) -> _` -note: the anonymous lifetime as defined here... - --> $DIR/panic-handler-bad-signature-2.rs:9:1 - | -LL | fn panic(info: &'static PanicInfo) -> ! - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...does not necessarily outlive the static lifetime + = note: expected fn pointer `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _` + found fn pointer `for<'a> fn(&'static PanicInfo<'a>) -> _` error: aborting due to previous error diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr index 2745c05834ca..22b8d5ca8115 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-5.stderr @@ -2,16 +2,10 @@ error[E0308]: `#[panic_handler]` function has wrong type --> $DIR/panic-handler-bad-signature-5.rs:9:1 | LL | fn panic(info: &PanicInfo<'static>) -> ! - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected signature `fn(&PanicInfo<'_>) -> _` - found signature `fn(&PanicInfo<'static>) -> _` -note: the anonymous lifetime as defined here... - --> $DIR/panic-handler-bad-signature-5.rs:9:1 - | -LL | fn panic(info: &PanicInfo<'static>) -> ! - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...does not necessarily outlive the static lifetime + = note: expected fn pointer `for<'a, 'b> fn(&'a PanicInfo<'b>) -> _` + found fn pointer `for<'a> fn(&'a PanicInfo<'static>) -> _` error: aborting due to previous error From a2374e65aafd47fa68a3954fa2a3116c519aa7e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Sep 2023 17:44:31 +0200 Subject: [PATCH 04/26] the Const::eval_bits methods don't need to be given the Ty --- .../src/debuginfo/type_names.rs | 4 ++-- .../src/transform/promote_consts.rs | 2 +- compiler/rustc_middle/src/mir/consts.rs | 17 ++++++----------- compiler/rustc_middle/src/ty/consts.rs | 17 ++++++----------- .../src/build/custom/parse/instruction.rs | 4 ++-- .../rustc_mir_build/src/build/matches/mod.rs | 4 ++-- .../rustc_mir_build/src/build/matches/test.rs | 5 +---- .../src/thir/pattern/deconstruct_pat.rs | 6 +++--- .../rustc_mir_build/src/thir/pattern/mod.rs | 12 ++++++------ compiler/rustc_mir_transform/src/const_goto.rs | 4 ++-- .../src/simplify_branches.rs | 2 +- .../src/typeid/typeid_itanium_cxx_abi.rs | 4 ++-- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- 13 files changed, 35 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index e21148a4de14..a2190293c0b2 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -660,12 +660,12 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S } _ => match ct.ty().kind() { ty::Int(ity) => { - let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty()); + let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; write!(output, "{val}") } ty::Uint(_) => { - let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty()); + let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); write!(output, "{val}") } ty::Bool => { diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index d79c65f1d1fe..d346fd721609 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -554,7 +554,7 @@ impl<'tcx> Validator<'_, 'tcx> { // Integer division: the RHS must be a non-zero const. let const_val = match rhs { Operand::Constant(c) => { - c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty) + c.literal.try_eval_bits(self.tcx, self.param_env) } _ => None, }; diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 9e86eb214c12..cbe84bf840ab 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -323,23 +323,18 @@ impl<'tcx> ConstantKind<'tcx> { } #[inline] - pub fn try_eval_bits( - &self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - ) -> Option { + pub fn try_eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option { let int = self.try_eval_scalar_int(tcx, param_env)?; - assert_eq!(self.ty(), ty); - let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; + let size = + tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size; int.to_bits(size).ok() } /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. #[inline] - pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 { - self.try_eval_bits(tcx, param_env, ty) - .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self)) + pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 { + self.try_eval_bits(tcx, param_env) + .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self)) } #[inline] diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index ba871d6478bf..2518f0cf2e9c 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -339,24 +339,19 @@ impl<'tcx> Const<'tcx> { /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it /// contains const generic parameters or pointers). - pub fn try_eval_bits( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ty: Ty<'tcx>, - ) -> Option { + pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option { let int = self.try_eval_scalar_int(tcx, param_env)?; - assert_eq!(self.ty(), ty); - let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; + let size = + tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size; // if `ty` does not depend on generic parameters, use an empty param_env int.to_bits(size).ok() } #[inline] /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. - pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 { - self.try_eval_bits(tcx, param_env, ty) - .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self)) + pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 { + self.try_eval_bits(tcx, param_env) + .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self)) } #[inline] diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 0eff2df13662..05f135b01f4a 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -100,7 +100,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { expected: "constant pattern".to_string(), }); }; - values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty)); + values.push(value.eval_bits(self.tcx, self.param_env)); targets.push(self.parse_block(arm.body)?); } @@ -301,7 +301,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { | ExprKind::NonHirLiteral { .. } | ExprKind::ConstBlock { .. } => Ok({ let value = as_constant_inner(expr, |_| None, self.tcx); - value.literal.eval_bits(self.tcx, self.param_env, value.ty()) + value.literal.eval_bits(self.tcx, self.param_env) }), ) } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 7e81c8b50c2d..1a5d8c63f93e 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1622,9 +1622,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // may want to add cases based on the candidates that are // available match test.kind { - TestKind::SwitchInt { switch_ty, ref mut options } => { + TestKind::SwitchInt { switch_ty: _, ref mut options } => { for candidate in candidates.iter() { - if !self.add_cases_to_switch(&match_place, candidate, switch_ty, options) { + if !self.add_cases_to_switch(&match_place, candidate, options) { break; } } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 484e8490919d..0fdc0a82da56 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -85,7 +85,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, test_place: &PlaceBuilder<'tcx>, candidate: &Candidate<'pat, 'tcx>, - switch_ty: Ty<'tcx>, options: &mut FxIndexMap, u128>, ) -> bool { let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place) @@ -95,9 +94,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match match_pair.pattern.kind { PatKind::Constant { value } => { - options - .entry(value) - .or_insert_with(|| value.eval_bits(self.tcx, self.param_env, switch_ty)); + options.entry(value).or_insert_with(|| value.eval_bits(self.tcx, self.param_env)); true } PatKind::Variant { .. } => { diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index bee1c4e4614f..ee7ac91b148b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -146,7 +146,7 @@ impl IntRange { valtree.unwrap_leaf().to_bits(target_size).ok() }, // This is a more general form of the previous case. - _ => value.try_eval_bits(tcx, param_env, ty), + _ => value.try_eval_bits(tcx, param_env), }?; let val = val ^ bias; @@ -1379,8 +1379,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let ty = lo.ty(); ctor = if let Some(int_range) = IntRange::from_range( cx.tcx, - lo.eval_bits(cx.tcx, cx.param_env, lo.ty()), - hi.eval_bits(cx.tcx, cx.param_env, hi.ty()), + lo.eval_bits(cx.tcx, cx.param_env), + hi.eval_bits(cx.tcx, cx.param_env), ty, &end, ) { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3d9e634c8493..8f3e1359700b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -131,7 +131,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr && let rustc_ast::ast::LitKind::Int(val, _) = lit.node { - if lo.eval_bits(self.tcx, self.param_env, ty) != val { + if lo.eval_bits(self.tcx, self.param_env) != val { lower_overflow = true; self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); } @@ -139,7 +139,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr && let rustc_ast::ast::LitKind::Int(val, _) = lit.node { - if hi.eval_bits(self.tcx, self.param_env, ty) != val { + if hi.eval_bits(self.tcx, self.param_env) != val { higher_overflow = true; self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); } @@ -162,7 +162,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr && let rustc_ast::ast::LitKind::Int(val, _) = lit.node { - if lo.eval_bits(self.tcx, self.param_env, ty) != val { + if lo.eval_bits(self.tcx, self.param_env) != val { lower_overflow = true; self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); } @@ -170,7 +170,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr && let rustc_ast::ast::LitKind::Int(val, _) = lit.node { - if hi.eval_bits(self.tcx, self.param_env, ty) != val { + if hi.eval_bits(self.tcx, self.param_env) != val { higher_overflow = true; self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); } @@ -865,8 +865,8 @@ pub(crate) fn compare_const_vals<'tcx>( }, } - let a = a.eval_bits(tcx, param_env, ty); - let b = b.eval_bits(tcx, param_env, ty); + let a = a.eval_bits(tcx, param_env); + let b = b.eval_bits(tcx, param_env); use rustc_apfloat::Float; match *ty.kind() { diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index e175f22d7a94..cd3ea9509efd 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -96,10 +96,10 @@ impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> { let (discr, targets) = target_bb_terminator.kind.as_switch()?; if discr.place() == Some(*place) { let switch_ty = place.ty(self.body.local_decls(), self.tcx).ty; + debug_assert_eq!(switch_ty, _const.ty()); // We now know that the Switch matches on the const place, and it is statementless // Now find which value in the Switch matches the const value. - let const_value = - _const.literal.try_eval_bits(self.tcx, self.param_env, switch_ty)?; + let const_value = _const.literal.try_eval_bits(self.tcx, self.param_env)?; let target_to_use_in_goto = targets.target_for_value(const_value); self.optimizations.push(OptimizationToApply { bb_with_goto: location.block, diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 1ff488169864..495f66417666 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -23,7 +23,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition { TerminatorKind::SwitchInt { discr: Operand::Constant(ref c), ref targets, .. } => { - let constant = c.literal.try_eval_bits(tcx, param_env, c.ty()); + let constant = c.literal.try_eval_bits(tcx, param_env); if let Some(constant) = constant { let target = targets.target_for_value(constant); TerminatorKind::Goto { target } diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 77457c8daaa1..d1f2c1b27fd1 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -118,7 +118,7 @@ fn encode_const<'tcx>( // bool value false is encoded as 0 and true as 1. match c.ty().kind() { ty::Int(ity) => { - let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty()); + let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all()); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; if val < 0 { s.push('n'); @@ -126,7 +126,7 @@ fn encode_const<'tcx>( let _ = write!(s, "{val}"); } ty::Uint(_) => { - let val = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty()); + let val = c.eval_bits(tcx, ty::ParamEnv::reveal_all()); let _ = write!(s, "{val}"); } ty::Bool => { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 2550570af65b..e9a7d0be4b49 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -594,7 +594,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => { self = ty.print(self)?; - let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ty); + let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all()); // Negative integer values are mangled using `n` as a "sign prefix". if let ty::Int(ity) = ty.kind() { From 0d07b4c2ce5bd677735dc8d2265395d52041636f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 20 Sep 2023 18:59:12 +0200 Subject: [PATCH 05/26] Call panic_display directly in const_panic_fmt. --- library/core/src/panicking.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 281f8c1e1663..1f4c7c376bda 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -234,7 +234,8 @@ fn panic_in_cleanup() -> ! { #[rustc_const_unstable(feature = "core_panic", issue = "none")] pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if let Some(msg) = fmt.as_str() { - panic_str(msg); + // The panic_display function is hooked by conost eval. + panic_display(&msg); } else { // SAFETY: This is only evaluated at compile time, which reliably // handles this UB (in case this branch turns out to be reachable From da08a3f40c38b233a57aa0b9aca6c875ab383240 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Sep 2023 21:49:30 +0200 Subject: [PATCH 06/26] interpret: more consistently use ImmTy in operators and casts --- .../src/const_eval/machine.rs | 4 +- .../rustc_const_eval/src/interpret/cast.rs | 52 ++++---- .../src/interpret/discriminant.rs | 13 +- .../src/interpret/intrinsics.rs | 14 +- .../rustc_const_eval/src/interpret/machine.rs | 6 +- .../rustc_const_eval/src/interpret/operand.rs | 8 +- .../src/interpret/operator.rs | 126 +++++++++--------- .../rustc_const_eval/src/interpret/step.rs | 2 +- .../src/interpret/terminator.rs | 14 +- .../rustc_mir_transform/src/const_prop.rs | 2 +- .../src/const_prop_lint.rs | 4 +- .../src/dataflow_const_prop.rs | 14 +- src/tools/miri/src/concurrency/data_race.rs | 8 +- src/tools/miri/src/helpers.rs | 15 ++- src/tools/miri/src/machine.rs | 2 +- src/tools/miri/src/operator.rs | 14 +- src/tools/miri/src/shims/intrinsics/mod.rs | 7 +- src/tools/miri/src/shims/intrinsics/simd.rs | 26 ++-- src/tools/miri/src/shims/x86/mod.rs | 4 +- src/tools/miri/src/shims/x86/sse.rs | 6 +- src/tools/miri/src/shims/x86/sse2.rs | 48 +++---- 21 files changed, 200 insertions(+), 189 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index f16aea6f34b7..14b9894aad5c 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -3,7 +3,7 @@ use rustc_hir::{LangItem, CRATE_HIR_ID}; use rustc_middle::mir; use rustc_middle::mir::interpret::PointerArithmetic; use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::INVALID_ALIGNMENT; use std::borrow::Borrow; use std::hash::Hash; @@ -596,7 +596,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _bin_op: mir::BinOp, _left: &ImmTy<'tcx>, _right: &ImmTy<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> { throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time"); } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 4c826239eca4..3f1b7e668e35 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -34,31 +34,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { CastKind::PointerExposeAddress => { let src = self.read_immediate(src)?; let res = self.pointer_expose_address_cast(&src, cast_ty)?; - self.write_immediate(res, dest)?; + self.write_immediate(*res, dest)?; } CastKind::PointerFromExposedAddress => { let src = self.read_immediate(src)?; let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?; - self.write_immediate(res, dest)?; + self.write_immediate(*res, dest)?; } CastKind::IntToInt | CastKind::IntToFloat => { let src = self.read_immediate(src)?; let res = self.int_to_int_or_float(&src, cast_ty)?; - self.write_immediate(res, dest)?; + self.write_immediate(*res, dest)?; } CastKind::FloatToFloat | CastKind::FloatToInt => { let src = self.read_immediate(src)?; let res = self.float_to_float_or_int(&src, cast_ty)?; - self.write_immediate(res, dest)?; + self.write_immediate(*res, dest)?; } CastKind::FnPtrToPtr | CastKind::PtrToPtr => { let src = self.read_immediate(src)?; let res = self.ptr_to_ptr(&src, cast_ty)?; - self.write_immediate(res, dest)?; + self.write_immediate(*res, dest)?; } CastKind::PointerCoercion( @@ -165,11 +165,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool()); assert!(cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char()); - Ok(self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?.into()) + let layout = self.layout_of(cast_ty)?; + Ok(ImmTy::from_scalar( + self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?, + layout, + )) } /// Handles 'FloatToFloat' and 'FloatToInt' casts. @@ -177,21 +181,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { use rustc_type_ir::sty::TyKind::*; - match src.layout.ty.kind() { + let layout = self.layout_of(cast_ty)?; + let val = match src.layout.ty.kind() { // Floating point - Float(FloatTy::F32) => { - return Ok(self.cast_from_float(src.to_scalar().to_f32()?, cast_ty).into()); - } - Float(FloatTy::F64) => { - return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into()); - } + Float(FloatTy::F32) => self.cast_from_float(src.to_scalar().to_f32()?, cast_ty), + Float(FloatTy::F64) => self.cast_from_float(src.to_scalar().to_f64()?, cast_ty), _ => { bug!("Can't cast 'Float' type into {:?}", cast_ty); } - } + }; + Ok(ImmTy::from_scalar(val, layout)) } /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts. @@ -199,21 +201,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_any_ptr()); assert!(cast_ty.is_unsafe_ptr()); // Handle casting any ptr to raw ptr (might be a fat ptr). let dest_layout = self.layout_of(cast_ty)?; if dest_layout.size == src.layout.size { // Thin or fat pointer that just hast the ptr kind of target type changed. - return Ok(**src); + return Ok(ImmTy::from_immediate(**src, dest_layout)); } else { // Casting the metadata away from a fat ptr. assert_eq!(src.layout.size, 2 * self.pointer_size()); assert_eq!(dest_layout.size, self.pointer_size()); assert!(src.layout.ty.is_unsafe_ptr()); return match **src { - Immediate::ScalarPair(data, _) => Ok(data.into()), + Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, dest_layout)), Immediate::Scalar(..) => span_bug!( self.cur_span(), "{:?} input to a fat-to-thin cast ({:?} -> {:?})", @@ -230,7 +232,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_)); assert!(cast_ty.is_integral()); @@ -240,14 +242,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(ptr) => M::expose_ptr(self, ptr)?, Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP. }; - Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) + let layout = self.layout_of(cast_ty)?; + Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_ty)?, layout)) } pub fn pointer_from_exposed_address_cast( &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_integral()); assert_matches!(cast_ty.kind(), ty::RawPtr(_)); @@ -258,12 +261,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Then turn address into pointer. let ptr = M::ptr_from_addr_cast(&self, addr)?; - Ok(Scalar::from_maybe_pointer(ptr, self).into()) + let layout = self.layout_of(cast_ty)?; + Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), layout)) } /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input /// type (basically everything with a scalar layout) to int/float/char types. - pub fn cast_from_int_like( + fn cast_from_int_like( &self, scalar: Scalar, // input value (there is no ScalarTy so we separate data+layout) src_layout: TyAndLayout<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 440ee06e7fe7..f177edd2b412 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -76,7 +76,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); let variant_index_relative_val = ImmTy::from_uint(variant_index_relative, tag_layout); - let tag_val = self.binary_op( + let tag_val = self.wrapping_binary_op( mir::BinOp::Add, &variant_index_relative_val, &niche_start_val, @@ -153,19 +153,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Figure out which discriminant and variant this corresponds to. let index = match *tag_encoding { TagEncoding::Direct => { - let scalar = tag_val.to_scalar(); // Generate a specific error if `tag_val` is not an integer. // (`tag_bits` itself is only used for error messages below.) - let tag_bits = scalar + let tag_bits = tag_val + .to_scalar() .try_to_int() .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))? .assert_bits(tag_layout.size); // Cast bits from tag layout to discriminant layout. // After the checks we did above, this cannot fail, as // discriminants are int-like. - let discr_val = - self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap(); - let discr_bits = discr_val.assert_bits(discr_layout.size); + let discr_val = self.int_to_int_or_float(&tag_val, discr_layout.ty).unwrap(); + let discr_bits = discr_val.to_scalar().assert_bits(discr_layout.size); // Convert discriminant to variant index, and catch invalid discriminants. let index = match *ty.kind() { ty::Adt(adt, _) => { @@ -208,7 +207,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let tag_val = ImmTy::from_uint(tag_bits, tag_layout); let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); let variant_index_relative_val = - self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?; + self.wrapping_binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?; let variant_index_relative = variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size); // Check if this is in the range that indicates an actual discriminant. diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index f08f1437918f..d6a147520957 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -307,7 +307,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let dist = { // Addresses are unsigned, so this is a `usize` computation. We have to do the // overflow check separately anyway. - let (val, overflowed, _ty) = { + let (val, overflowed) = { let a_offset = ImmTy::from_uint(a_offset, usize_layout); let b_offset = ImmTy::from_uint(b_offset, usize_layout); self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)? @@ -324,7 +324,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The signed form of the intrinsic allows this. If we interpret the // difference as isize, we'll get the proper signed difference. If that // seems *positive*, they were more than isize::MAX apart. - let dist = val.to_target_isize(self)?; + let dist = val.to_scalar().to_target_isize(self)?; if dist >= 0 { throw_ub_custom!( fluent::const_eval_offset_from_underflow, @@ -334,7 +334,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { dist } else { // b >= a - let dist = val.to_target_isize(self)?; + let dist = val.to_scalar().to_target_isize(self)?; // If converting to isize produced a *negative* result, we had an overflow // because they were more than isize::MAX apart. if dist < 0 { @@ -504,9 +504,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`. // First, check x % y != 0 (or if that computation overflows). - let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?; + let (res, overflow) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?; assert!(!overflow); // All overflow is UB, so this should never return on overflow. - if res.assert_bits(a.layout.size) != 0 { + if res.to_scalar().assert_bits(a.layout.size) != 0 { throw_ub_custom!( fluent::const_eval_exact_div_has_remainder, a = format!("{a}"), @@ -524,7 +524,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { r: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Scalar> { assert!(matches!(mir_op, BinOp::Add | BinOp::Sub)); - let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?; + let (val, overflowed) = self.overflowing_binary_op(mir_op, l, r)?; Ok(if overflowed { let size = l.layout.size; let num_bits = size.bits(); @@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } } else { - val + val.to_scalar() }) } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index c9fd21024184..aaa674a598f8 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -9,7 +9,7 @@ use std::hash::Hash; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::DefId; use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi as CallAbi; @@ -18,7 +18,7 @@ use crate::const_eval::CheckAlignment; use super::{ AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx, - InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance, Scalar, + InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance, }; /// Data returned by Machine::stack_pop, @@ -238,7 +238,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { bin_op: mir::BinOp, left: &ImmTy<'tcx, Self::Provenance>, right: &ImmTy<'tcx, Self::Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; + ) -> InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)>; /// Called before writing the specified `local` of the `frame`. /// Since writing a ZST is not actually accessing memory or locals, this is never invoked diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 788b50d7c4af..18ede5ac91e1 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -8,7 +8,7 @@ use either::{Either, Left, Right}; use rustc_hir::def::Namespace; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; -use rustc_middle::ty::{ConstInt, Ty}; +use rustc_middle::ty::{ConstInt, Ty, TyCtxt}; use rustc_middle::{mir, ty}; use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size}; @@ -188,6 +188,12 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { Self::from_scalar(Scalar::from_int(i, layout.size), layout) } + #[inline] + pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self { + let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(tcx.types.bool)).unwrap(); + Self::from_scalar(Scalar::from_bool(b), layout) + } + #[inline] pub fn to_const_int(self) -> ConstInt { assert!(self.layout.ty.is_integral()); diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index eb0645780673..22813ef66f60 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -1,7 +1,7 @@ use rustc_apfloat::Float; use rustc_middle::mir; use rustc_middle::mir::interpret::{InterpResult, Scalar}; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_span::symbol::sym; use rustc_target::abi::Abi; @@ -20,9 +20,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { right: &ImmTy<'tcx, M::Provenance>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?; + let (val, overflowed) = self.overflowing_binary_op(op, &left, &right)?; debug_assert_eq!( - Ty::new_tup(self.tcx.tcx, &[ty, self.tcx.types.bool]), + Ty::new_tup(self.tcx.tcx, &[val.layout.ty, self.tcx.types.bool]), dest.layout.ty, "type mismatch for result of {op:?}", ); @@ -30,7 +30,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Abi::ScalarPair(..) = dest.layout.abi { // We can use the optimized path and avoid `place_field` (which might do // `force_allocation`). - let pair = Immediate::ScalarPair(val, Scalar::from_bool(overflowed)); + let pair = Immediate::ScalarPair(val.to_scalar(), Scalar::from_bool(overflowed)); self.write_immediate(pair, dest)?; } else { assert!(self.tcx.sess.opts.unstable_opts.randomize_layout); @@ -38,7 +38,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // do a component-wise write here. This code path is slower than the above because // `place_field` will have to `force_allocate` locals here. let val_field = self.project_field(dest, 0)?; - self.write_scalar(val, &val_field)?; + self.write_scalar(val.to_scalar(), &val_field)?; let overflowed_field = self.project_field(dest, 1)?; self.write_scalar(Scalar::from_bool(overflowed), &overflowed_field)?; } @@ -54,9 +54,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { right: &ImmTy<'tcx, M::Provenance>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?; - assert_eq!(ty, dest.layout.ty, "type mismatch for result of {op:?}"); - self.write_scalar(val, dest) + let val = self.wrapping_binary_op(op, left, right)?; + assert_eq!(val.layout.ty, dest.layout.ty, "type mismatch for result of {op:?}"); + self.write_immediate(*val, dest) } } @@ -66,7 +66,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, l: char, r: char, - ) -> (Scalar, bool, Ty<'tcx>) { + ) -> (ImmTy<'tcx, M::Provenance>, bool) { use rustc_middle::mir::BinOp::*; let res = match bin_op { @@ -78,7 +78,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ge => l >= r, _ => span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op), }; - (Scalar::from_bool(res), false, self.tcx.types.bool) + (ImmTy::from_bool(res, *self.tcx), false) } fn binary_bool_op( @@ -86,7 +86,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, l: bool, r: bool, - ) -> (Scalar, bool, Ty<'tcx>) { + ) -> (ImmTy<'tcx, M::Provenance>, bool) { use rustc_middle::mir::BinOp::*; let res = match bin_op { @@ -101,33 +101,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { BitXor => l ^ r, _ => span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op), }; - (Scalar::from_bool(res), false, self.tcx.types.bool) + (ImmTy::from_bool(res, *self.tcx), false) } fn binary_float_op>>( &self, bin_op: mir::BinOp, - ty: Ty<'tcx>, + layout: TyAndLayout<'tcx>, l: F, r: F, - ) -> (Scalar, bool, Ty<'tcx>) { + ) -> (ImmTy<'tcx, M::Provenance>, bool) { use rustc_middle::mir::BinOp::*; - let (val, ty) = match bin_op { - Eq => (Scalar::from_bool(l == r), self.tcx.types.bool), - Ne => (Scalar::from_bool(l != r), self.tcx.types.bool), - Lt => (Scalar::from_bool(l < r), self.tcx.types.bool), - Le => (Scalar::from_bool(l <= r), self.tcx.types.bool), - Gt => (Scalar::from_bool(l > r), self.tcx.types.bool), - Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool), - Add => ((l + r).value.into(), ty), - Sub => ((l - r).value.into(), ty), - Mul => ((l * r).value.into(), ty), - Div => ((l / r).value.into(), ty), - Rem => ((l % r).value.into(), ty), + let val = match bin_op { + Eq => ImmTy::from_bool(l == r, *self.tcx), + Ne => ImmTy::from_bool(l != r, *self.tcx), + Lt => ImmTy::from_bool(l < r, *self.tcx), + Le => ImmTy::from_bool(l <= r, *self.tcx), + Gt => ImmTy::from_bool(l > r, *self.tcx), + Ge => ImmTy::from_bool(l >= r, *self.tcx), + Add => ImmTy::from_scalar((l + r).value.into(), layout), + Sub => ImmTy::from_scalar((l - r).value.into(), layout), + Mul => ImmTy::from_scalar((l * r).value.into(), layout), + Div => ImmTy::from_scalar((l / r).value.into(), layout), + Rem => ImmTy::from_scalar((l % r).value.into(), layout), _ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op), }; - (val, false, ty) + (val, false) } fn binary_int_op( @@ -138,7 +138,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { left_layout: TyAndLayout<'tcx>, r: u128, right_layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { use rustc_middle::mir::BinOp::*; let throw_ub_on_overflow = match bin_op { @@ -200,7 +200,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ); } - return Ok((Scalar::from_uint(truncated, left_layout.size), overflow, left_layout.ty)); + return Ok((ImmTy::from_uint(truncated, left_layout), overflow)); } // For the remaining ops, the types must be the same on both sides @@ -230,7 +230,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Some(op) = op { let l = self.sign_extend(l, left_layout) as i128; let r = self.sign_extend(r, right_layout) as i128; - return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool)); + return Ok((ImmTy::from_bool(op(&l, &r), *self.tcx), false)); } let op: Option (i128, bool)> = match bin_op { Div if r == 0 => throw_ub!(DivisionByZero), @@ -267,22 +267,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if overflow && let Some(intrinsic_name) = throw_ub_on_overflow { throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name); } - return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty)); + return Ok((ImmTy::from_uint(truncated, left_layout), overflow)); } } - let (val, ty) = match bin_op { - Eq => (Scalar::from_bool(l == r), self.tcx.types.bool), - Ne => (Scalar::from_bool(l != r), self.tcx.types.bool), + let val = match bin_op { + Eq => ImmTy::from_bool(l == r, *self.tcx), + Ne => ImmTy::from_bool(l != r, *self.tcx), - Lt => (Scalar::from_bool(l < r), self.tcx.types.bool), - Le => (Scalar::from_bool(l <= r), self.tcx.types.bool), - Gt => (Scalar::from_bool(l > r), self.tcx.types.bool), - Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool), + Lt => ImmTy::from_bool(l < r, *self.tcx), + Le => ImmTy::from_bool(l <= r, *self.tcx), + Gt => ImmTy::from_bool(l > r, *self.tcx), + Ge => ImmTy::from_bool(l >= r, *self.tcx), - BitOr => (Scalar::from_uint(l | r, size), left_layout.ty), - BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty), - BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty), + BitOr => ImmTy::from_uint(l | r, left_layout), + BitAnd => ImmTy::from_uint(l & r, left_layout), + BitXor => ImmTy::from_uint(l ^ r, left_layout), Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Rem | Div => { assert!(!left_layout.abi.is_signed()); @@ -304,7 +304,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if overflow && let Some(intrinsic_name) = throw_ub_on_overflow { throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name); } - return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty)); + return Ok((ImmTy::from_uint(truncated, left_layout), overflow)); } _ => span_bug!( @@ -317,7 +317,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ), }; - Ok((val, false, ty)) + Ok((val, false)) } fn binary_ptr_op( @@ -325,7 +325,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bin_op: mir::BinOp, left: &ImmTy<'tcx, M::Provenance>, right: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { use rustc_middle::mir::BinOp::*; match bin_op { @@ -336,7 +336,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?; - Ok((Scalar::from_maybe_pointer(offset_ptr, self), false, left.layout.ty)) + Ok(( + ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout), + false, + )) } // Fall back to machine hook so Miri can support more pointer ops. @@ -344,14 +347,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - /// Returns the result of the specified operation, whether it overflowed, and - /// the result type. + /// Returns the result of the specified operation, and whether it overflowed. pub fn overflowing_binary_op( &self, bin_op: mir::BinOp, left: &ImmTy<'tcx, M::Provenance>, right: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { trace!( "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, @@ -376,15 +378,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } ty::Float(fty) => { assert_eq!(left.layout.ty, right.layout.ty); - let ty = left.layout.ty; + let layout = left.layout; let left = left.to_scalar(); let right = right.to_scalar(); Ok(match fty { FloatTy::F32 => { - self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?) + self.binary_float_op(bin_op, layout, left.to_f32()?, right.to_f32()?) } FloatTy::F64 => { - self.binary_float_op(bin_op, ty, left.to_f64()?, right.to_f64()?) + self.binary_float_op(bin_op, layout, left.to_f64()?, right.to_f64()?) } }) } @@ -423,16 +425,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - /// Typed version of `overflowing_binary_op`, returning an `ImmTy`. Also ignores overflows. #[inline] - pub fn binary_op( + pub fn wrapping_binary_op( &self, bin_op: mir::BinOp, left: &ImmTy<'tcx, M::Provenance>, right: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?; - Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) + let (val, _overflow) = self.overflowing_binary_op(bin_op, left, right)?; + Ok(val) } /// Returns the result of the specified operation, whether it overflowed, and @@ -441,7 +442,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, un_op: mir::UnOp, val: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { use rustc_middle::mir::UnOp::*; let layout = val.layout; @@ -455,7 +456,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Not => !val, _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op), }; - Ok((Scalar::from_bool(res), false, self.tcx.types.bool)) + Ok((ImmTy::from_bool(res, *self.tcx), false)) } ty::Float(fty) => { let res = match (un_op, fty) { @@ -463,7 +464,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op), }; - Ok((res, false, layout.ty)) + Ok((ImmTy::from_scalar(res, layout), false)) } _ => { assert!(layout.ty.is_integral()); @@ -482,17 +483,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (truncated, overflow || self.sign_extend(truncated, layout) != res) } }; - Ok((Scalar::from_uint(res, layout.size), overflow, layout.ty)) + Ok((ImmTy::from_uint(res, layout), overflow)) } } } - pub fn unary_op( + #[inline] + pub fn wrapping_unary_op( &self, un_op: mir::UnOp, val: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?; - Ok(ImmTy::from_scalar(val, self.layout_of(ty)?)) + let (val, _overflow) = self.overflowing_unary_op(un_op, val)?; + Ok(val) } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index cf1f7ff75e1a..284e13407f7e 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -177,7 +177,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { UnaryOp(un_op, ref operand) => { // The operand always has the same type as the result. let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?; - let val = self.unary_op(un_op, &val)?; + let val = self.wrapping_unary_op(un_op, &val)?; assert_eq!(val.layout, dest.layout, "layout mismatch for result of {un_op:?}"); self.write_immediate(*val, &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index e15499bc68d0..8a62a816c961 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -98,14 +98,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { for (const_int, target) in targets.iter() { // Compare using MIR BinOp::Eq, to also support pointer values. // (Avoiding `self.binary_op` as that does some redundant layout computation.) - let res = self - .overflowing_binary_op( - mir::BinOp::Eq, - &discr, - &ImmTy::from_uint(const_int, discr.layout), - )? - .0; - if res.to_bool()? { + let res = self.wrapping_binary_op( + mir::BinOp::Eq, + &discr, + &ImmTy::from_uint(const_int, discr.layout), + )?; + if res.to_scalar().to_bool()? { target_block = target; break; } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index c6aac2ca2133..b44d86e658f6 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -210,7 +210,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _bin_op: BinOp, _left: &ImmTy<'tcx>, _right: &ImmTy<'tcx>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> { // We can't do this because aliasing of memory can differ between const eval and llvm throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index fb33b3b49d30..8bf2ccc63c75 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -322,7 +322,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn check_unary_op(&mut self, op: UnOp, arg: &Operand<'tcx>, location: Location) -> Option<()> { if let (val, true) = self.use_ecx(location, |this| { let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?; - let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?; + let (_res, overflow) = this.ecx.overflowing_unary_op(op, &val)?; Ok((val, overflow)) })? { // `AssertKind` only has an `OverflowNeg` variant, so make sure that is @@ -390,7 +390,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if let (Some(l), Some(r)) = (l, r) { // The remaining operators are handled through `overflowing_binary_op`. if self.use_ecx(location, |this| { - let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?; + let (_res, overflow) = this.ecx.overflowing_binary_op(op, &l, &r)?; Ok(overflow) })? { let source_info = self.body().source_info(location); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index cf827c988942..d3e85dc8e0ae 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -238,7 +238,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { FlatSet::Elem(op) => self .ecx .int_to_int_or_float(&op, *ty) - .map_or(FlatSet::Top, |result| self.wrap_immediate(result)), + .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, } @@ -248,7 +248,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { FlatSet::Elem(op) => self .ecx .float_to_float_or_int(&op, *ty) - .map_or(FlatSet::Top, |result| self.wrap_immediate(result)), + .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, } @@ -268,7 +268,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) { FlatSet::Elem(value) => self .ecx - .unary_op(*op, &value) + .wrapping_unary_op(*op, &value) .map_or(FlatSet::Top, |val| self.wrap_immediate(*val)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, @@ -439,7 +439,9 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // Both sides are known, do the actual computation. (FlatSet::Elem(left), FlatSet::Elem(right)) => { match self.ecx.overflowing_binary_op(op, &left, &right) { - Ok((val, overflow, _)) => (FlatSet::Elem(val), FlatSet::Elem(overflow)), + Ok((val, overflow)) => { + (FlatSet::Elem(val.to_scalar()), FlatSet::Elem(overflow)) + } _ => (FlatSet::Top, FlatSet::Top), } } @@ -783,8 +785,8 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm _bin_op: BinOp, _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, - ) -> interpret::InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - throw_unsup!(Unsupported("".into())) + ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> { + crate::const_prop::throw_machine_stop_str!("can't do pointer arithmetic"); } fn expose_ptr( diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 073b8b6a6613..24b9fa0776fb 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -516,8 +516,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; // Atomics wrap around on overflow. - let val = this.binary_op(op, &old, rhs)?; - let val = if neg { this.unary_op(mir::UnOp::Not, &val)? } else { val }; + let val = this.wrapping_binary_op(op, &old, rhs)?; + let val = if neg { this.wrapping_unary_op(mir::UnOp::Not, &val)? } else { val }; this.allow_data_races_mut(|this| this.write_immediate(*val, place))?; this.validate_atomic_rmw(place, atomic)?; @@ -561,7 +561,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; - let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?; + let lt = this.wrapping_binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?; let new_val = if min { if lt { &old } else { &rhs } @@ -605,7 +605,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { // Read as immediate for the sake of `binary_op()` let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; // `binary_op` will bail if either of them is not a scalar. - let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?; + let eq = this.wrapping_binary_op(mir::BinOp::Eq, &old, expect_old)?; // If the operation would succeed, but is "weak", fail some portion // of the time, based on `success_rate`. let success_rate = 1.0 - this.machine.cmpxchg_weak_failure_rate; diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index b05087134a0b..d5b658969e3d 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1015,13 +1015,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { f: F, dest_ty: Ty<'tcx>, round: rustc_apfloat::Round, - ) -> Option> + ) -> Option> where F: rustc_apfloat::Float + Into>, { let this = self.eval_context_ref(); - match dest_ty.kind() { + let val = match dest_ty.kind() { // Unsigned ty::Uint(t) => { let size = Integer::from_uint_ty(this, *t).size(); @@ -1033,11 +1033,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) { // Floating point value is NaN (flagged with INVALID_OP) or outside the range // of values of the integer type (flagged with OVERFLOW or UNDERFLOW). - None + return None } else { // Floating point value can be represented by the integer type after rounding. // The INEXACT flag is ignored on purpose to allow rounding. - Some(Scalar::from_uint(res.value, size)) + Scalar::from_uint(res.value, size) } } // Signed @@ -1051,11 +1051,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) { // Floating point value is NaN (flagged with INVALID_OP) or outside the range // of values of the integer type (flagged with OVERFLOW or UNDERFLOW). - None + return None } else { // Floating point value can be represented by the integer type after rounding. // The INEXACT flag is ignored on purpose to allow rounding. - Some(Scalar::from_int(res.value, size)) + Scalar::from_int(res.value, size) } } // Nothing else @@ -1064,7 +1064,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.cur_span(), "attempted float-to-int conversion with non-int output type {dest_ty:?}" ), - } + }; + Some(ImmTy::from_scalar(val, this.layout_of(dest_ty).unwrap())) } /// Returns an integer type that is twice wide as `ty` diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index ce7f47b5b4fe..f1c50794ca8d 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -998,7 +998,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { bin_op: mir::BinOp, left: &ImmTy<'tcx, Provenance>, right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)> { ecx.binary_ptr_op(bin_op, left, right) } diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 368aa2bacdc8..27fe7374ea5d 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -1,6 +1,6 @@ use log::trace; -use rustc_middle::{mir, ty::Ty}; +use rustc_middle::mir; use rustc_target::abi::Size; use crate::*; @@ -11,7 +11,7 @@ pub trait EvalContextExt<'tcx> { bin_op: mir::BinOp, left: &ImmTy<'tcx, Provenance>, right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; + ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)>; } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { @@ -20,7 +20,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { bin_op: mir::BinOp, left: &ImmTy<'tcx, Provenance>, right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)> { use rustc_middle::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); @@ -50,7 +50,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { Ge => left >= right, _ => bug!(), }; - (Scalar::from_bool(res), false, self.tcx.types.bool) + (ImmTy::from_bool(res, *self.tcx), false) } // Some more operations are possible with atomics. @@ -65,12 +65,12 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { right.to_scalar().to_target_usize(self)?, self.machine.layouts.usize, ); - let (result, overflowing, _ty) = + let (result, overflowing) = self.overflowing_binary_op(bin_op, &left, &right)?; // Construct a new pointer with the provenance of `ptr` (the LHS). let result_ptr = - Pointer::new(ptr.provenance, Size::from_bytes(result.to_target_usize(self)?)); - (Scalar::from_maybe_pointer(result_ptr, self), overflowing, left.layout.ty) + Pointer::new(ptr.provenance, Size::from_bytes(result.to_scalar().to_target_usize(self)?)); + (ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, self), left.layout), overflowing) } _ => span_bug!(self.cur_span(), "Invalid operator on pointers: {:?}", bin_op), diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index ef9d07104481..224ef97a1e12 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -89,10 +89,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let [left, right] = check_arg_count(args)?; let left = this.read_immediate(left)?; let right = this.read_immediate(right)?; - let (val, _overflowed, _ty) = - this.overflowing_binary_op(mir::BinOp::Eq, &left, &right)?; + let val = this.wrapping_binary_op(mir::BinOp::Eq, &left, &right)?; // We're type punning a bool as an u8 here. - this.write_scalar(val, dest)?; + this.write_scalar(val.to_scalar(), dest)?; } "const_allocate" => { // For now, for compatibility with the run-time implementation of this, we just return null. @@ -396,7 +395,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ), }; - this.write_scalar(res, dest)?; + this.write_immediate(*res, dest)?; } // Other diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index 626ead378e7b..98b21f768b1f 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -60,7 +60,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let op = this.read_immediate(&this.project_index(&op, i)?)?; let dest = this.project_index(&dest, i)?; let val = match which { - Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar(), + Op::MirOp(mir_op) => this.wrapping_unary_op(mir_op, &op)?.to_scalar(), Op::Abs => { // Works for f32 and f64. let ty::Float(float_ty) = op.layout.ty.kind() else { @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest = this.project_index(&dest, i)?; let val = match which { Op::MirOp(mir_op) => { - let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; + let (val, overflowed) = this.overflowing_binary_op(mir_op, &left, &right)?; if matches!(mir_op, BinOp::Shl | BinOp::Shr) { // Shifts have extra UB as SIMD operations that the MIR binop does not have. // See . @@ -188,13 +188,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { // Special handling for boolean-returning operations - assert_eq!(ty, this.tcx.types.bool); - let val = val.to_bool().unwrap(); + assert_eq!(val.layout.ty, this.tcx.types.bool); + let val = val.to_scalar().to_bool().unwrap(); bool_to_simd_element(val, dest.layout.size) } else { - assert_ne!(ty, this.tcx.types.bool); - assert_eq!(ty, dest.layout.ty); - val + assert_ne!(val.layout.ty, this.tcx.types.bool); + assert_eq!(val.layout.ty, dest.layout.ty); + val.to_scalar() } } Op::SaturatingOp(mir_op) => { @@ -304,18 +304,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let op = this.read_immediate(&this.project_index(&op, i)?)?; res = match which { Op::MirOp(mir_op) => { - this.binary_op(mir_op, &res, &op)? + this.wrapping_binary_op(mir_op, &res, &op)? } Op::MirOpBool(mir_op) => { let op = imm_from_bool(simd_element_to_bool(op)?); - this.binary_op(mir_op, &res, &op)? + this.wrapping_binary_op(mir_op, &res, &op)? } Op::Max => { if matches!(res.layout.ty.kind(), ty::Float(_)) { ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout) } else { // Just boring integers, so NaNs to worry about - if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar().to_bool()? { + if this.wrapping_binary_op(BinOp::Ge, &res, &op)?.to_scalar().to_bool()? { res } else { op @@ -327,7 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout) } else { // Just boring integers, so NaNs to worry about - if this.binary_op(BinOp::Le, &res, &op)?.to_scalar().to_bool()? { + if this.wrapping_binary_op(BinOp::Le, &res, &op)?.to_scalar().to_bool()? { res } else { op @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let mut res = init; for i in 0..op_len { let op = this.read_immediate(&this.project_index(&op, i)?)?; - res = this.binary_op(mir_op, &res, &op)?; + res = this.wrapping_binary_op(mir_op, &res, &op)?; } this.write_immediate(*res, dest)?; } @@ -487,7 +487,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { to_ty = dest.layout.ty, ), }; - this.write_immediate(val, &dest)?; + this.write_immediate(*val, &dest)?; } } "shuffle" => { diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index ccc729aae1a2..cbdc500be789 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -80,8 +80,8 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>( ) -> InterpResult<'tcx, Scalar> { match which { FloatBinOp::Arith(which) => { - let (res, _overflow, _ty) = this.overflowing_binary_op(which, left, right)?; - Ok(res) + let res = this.wrapping_binary_op(which, left, right)?; + Ok(res.to_scalar()) } FloatBinOp::Cmp(which) => { let left = left.to_scalar().to_float::()?; diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index 30ad088206a1..17a39660edb5 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -175,10 +175,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE semantics. - Scalar::from_int(dest.layout.size.signed_int_min(), dest.layout.size) + ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); - this.write_scalar(res, dest)?; + this.write_immediate(*res, dest)?; } // Used to implement the _mm_cvtsi32_ss and _mm_cvtsi64_ss functions. // Converts `right` from i32/i64 to f32. Returns a SIMD vector with @@ -197,7 +197,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let right = this.read_immediate(right)?; let dest0 = this.project_index(&dest, 0)?; let res0 = this.int_to_int_or_float(&right, dest0.layout.ty)?; - this.write_immediate(res0, &dest0)?; + this.write_immediate(*res0, &dest0)?; for i in 1..dest_len { this.copy_op( diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index b68690a835c2..03b298a23ecf 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -62,30 +62,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let right = this.int_to_int_or_float(&right, twice_wide_ty)?; // Calculate left + right + 1 - let (added, _overflow, _ty) = this.overflowing_binary_op( + let added = this.wrapping_binary_op( mir::BinOp::Add, - &ImmTy::from_immediate(left, twice_wide_layout), - &ImmTy::from_immediate(right, twice_wide_layout), + &left, + &right, )?; - let (added, _overflow, _ty) = this.overflowing_binary_op( + let added = this.wrapping_binary_op( mir::BinOp::Add, - &ImmTy::from_scalar(added, twice_wide_layout), + &added, &ImmTy::from_uint(1u32, twice_wide_layout), )?; // Calculate (left + right + 1) / 2 - let (divided, _overflow, _ty) = this.overflowing_binary_op( + let divided = this.wrapping_binary_op( mir::BinOp::Div, - &ImmTy::from_scalar(added, twice_wide_layout), + &added, &ImmTy::from_uint(2u32, twice_wide_layout), )?; // Narrow back to the original type let res = this.int_to_int_or_float( - &ImmTy::from_scalar(divided, twice_wide_layout), + ÷d, dest.layout.ty, )?; - this.write_immediate(res, &dest)?; + this.write_immediate(*res, &dest)?; } } // Used to implement the _mm_mulhi_epi16 and _mm_mulhi_epu16 functions. @@ -112,24 +112,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let right = this.int_to_int_or_float(&right, twice_wide_ty)?; // Multiply - let (multiplied, _overflow, _ty) = this.overflowing_binary_op( + let multiplied = this.wrapping_binary_op( mir::BinOp::Mul, - &ImmTy::from_immediate(left, twice_wide_layout), - &ImmTy::from_immediate(right, twice_wide_layout), + &left, + &right, )?; // Keep the high half - let (high, _overflow, _ty) = this.overflowing_binary_op( + let high = this.wrapping_binary_op( mir::BinOp::Shr, - &ImmTy::from_scalar(multiplied, twice_wide_layout), + &multiplied, &ImmTy::from_uint(dest.layout.size.bits(), twice_wide_layout), )?; // Narrow back to the original type let res = this.int_to_int_or_float( - &ImmTy::from_scalar(high, twice_wide_layout), + &high, dest.layout.ty, )?; - this.write_immediate(res, &dest)?; + this.write_immediate(*res, &dest)?; } } // Used to implement the _mm_mul_epu32 function. @@ -394,9 +394,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE2 semantics. - Scalar::from_i32(i32::MIN) + ImmTy::from_int(i32::MIN, this.machine.layouts.i32) }); - this.write_scalar(res, &dest)?; + this.write_immediate(*res, &dest)?; } } // Used to implement the _mm_packs_epi16 function. @@ -649,7 +649,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest = this.project_index(&dest, i)?; let res = this.float_to_float_or_int(&op, dest.layout.ty)?; - this.write_immediate(res, &dest)?; + this.write_immediate(*res, &dest)?; } // For f32 -> f64, ignore the remaining // For f64 -> f32, fill the remaining with zeros @@ -687,9 +687,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE2 semantics. - Scalar::from_i32(i32::MIN) + ImmTy::from_int(i32::MIN, this.machine.layouts.i32) }); - this.write_scalar(res, &dest)?; + this.write_immediate(*res, &dest)?; } // Fill the remaining with zeros for i in op_len..dest_len { @@ -718,10 +718,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE semantics. - Scalar::from_int(dest.layout.size.signed_int_min(), dest.layout.size) + ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); - this.write_scalar(res, dest)?; + this.write_immediate(*res, dest)?; } // Used to implement the _mm_cvtsd_ss and _mm_cvtss_sd functions. // Converts the first f64/f32 from `right` to f32/f64 and copies @@ -742,7 +742,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // `float_to_float_or_int` here will convert from f64 to f32 (cvtsd2ss) or // from f32 to f64 (cvtss2sd). let res0 = this.float_to_float_or_int(&right0, dest0.layout.ty)?; - this.write_immediate(res0, &dest0)?; + this.write_immediate(*res0, &dest0)?; // Copy remianing from `left` for i in 1..dest_len { From bdbf545f4216bc316822610b7ab231d336ecec2b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Sep 2023 22:25:09 +0200 Subject: [PATCH 07/26] interpret: less debug-printing of types --- .../rustc_const_eval/src/interpret/cast.rs | 18 ++++++++-------- .../src/interpret/eval_context.rs | 6 +++--- .../rustc_const_eval/src/interpret/operand.rs | 8 ++----- .../src/interpret/operator.rs | 21 ++++++++----------- .../rustc_const_eval/src/interpret/place.rs | 6 +++--- .../src/interpret/terminator.rs | 9 +++----- 6 files changed, 29 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 3f1b7e668e35..e18d72a766ba 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -87,7 +87,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let fn_ptr = self.fn_ptr(FnVal::Instance(instance)); self.write_pointer(fn_ptr, dest)?; } - _ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty), + _ => span_bug!(self.cur_span(), "reify fn pointer on {}", src.layout.ty), } } @@ -98,7 +98,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // No change to value self.write_immediate(*src, dest)?; } - _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {:?}", cast_ty), + _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {}", cast_ty), } } @@ -119,7 +119,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let fn_ptr = self.fn_ptr(FnVal::Instance(instance)); self.write_pointer(fn_ptr, dest)?; } - _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty), + _ => span_bug!(self.cur_span(), "closure fn pointer on {}", src.layout.ty), } } @@ -190,7 +190,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Float(FloatTy::F32) => self.cast_from_float(src.to_scalar().to_f32()?, cast_ty), Float(FloatTy::F64) => self.cast_from_float(src.to_scalar().to_f64()?, cast_ty), _ => { - bug!("Can't cast 'Float' type into {:?}", cast_ty); + bug!("Can't cast 'Float' type into {}", cast_ty); } }; Ok(ImmTy::from_scalar(val, layout)) @@ -218,7 +218,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, dest_layout)), Immediate::Scalar(..) => span_bug!( self.cur_span(), - "{:?} input to a fat-to-thin cast ({:?} -> {:?})", + "{:?} input to a fat-to-thin cast ({} -> {})", *src, src.layout.ty, cast_ty @@ -302,7 +302,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Casts to bool are not permitted by rustc, no need to handle them here. - _ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty), + _ => span_bug!(self.cur_span(), "invalid int to {} cast", cast_ty), }) } @@ -335,7 +335,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // float -> f64 Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value), // That's it. - _ => span_bug!(self.cur_span(), "invalid float to {:?} cast", dest_ty), + _ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty), } } @@ -393,7 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { span_bug!( self.cur_span(), - "invalid pointer unsizing {:?} -> {:?}", + "invalid pointer unsizing {} -> {}", src.layout.ty, cast_ty ) @@ -407,7 +407,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { cast_ty: TyAndLayout<'tcx>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty); + trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty); match (&src.layout.ty.kind(), &cast_ty.ty.kind()) { (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. })) | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index cb14e165b5c4..5737123d94f4 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -416,7 +416,7 @@ pub(super) fn from_known_layout<'tcx>( if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) { span_bug!( tcx.span, - "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}", + "expected type differs from actual type.\nexpected: {}\nactual: {}", known_layout.ty, check_layout.ty, ); @@ -712,7 +712,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::Foreign(_) => Ok(None), - _ => span_bug!(self.cur_span(), "size_and_align_of::<{:?}> not supported", layout.ty), + _ => span_bug!(self.cur_span(), "size_and_align_of::<{}> not supported", layout.ty), } } #[inline] @@ -982,7 +982,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::Bound(..) | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("`is_very_trivially_sized` applied to unexpected type: {:?}", ty) + bug!("`is_very_trivially_sized` applied to unexpected type: {}", ty) } } } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 18ede5ac91e1..c351fa84d37f 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -514,11 +514,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Abi::Scalar(abi::Scalar::Initialized { .. }) | Abi::ScalarPair(abi::Scalar::Initialized { .. }, abi::Scalar::Initialized { .. }) ) { - span_bug!( - self.cur_span(), - "primitive read not possible for type: {:?}", - op.layout().ty - ); + span_bug!(self.cur_span(), "primitive read not possible for type: {}", op.layout().ty); } let imm = self.read_immediate_raw(op)?.right().unwrap(); if matches!(*imm, Immediate::Uninit) { @@ -669,7 +665,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )?)?, op.layout, ), - "eval_place of a MIR place with type {:?} produced an interpreter operand with type {:?}", + "eval_place of a MIR place with type {:?} produced an interpreter operand with type {}", mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, op.layout.ty, ); diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 22813ef66f60..b084864f3a73 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -207,12 +207,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if left_layout.ty != right_layout.ty { span_bug!( self.cur_span(), - "invalid asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})", - bin_op, - l, - left_layout.ty, - r, - right_layout.ty, + "invalid asymmetric binary op {bin_op:?}: {l:?} ({l_ty}), {r:?} ({r_ty})", + l_ty = left_layout.ty, + r_ty = right_layout.ty, ) } @@ -309,7 +306,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => span_bug!( self.cur_span(), - "invalid binary op {:?}: {:?}, {:?} (both {:?})", + "invalid binary op {:?}: {:?}, {:?} (both {})", bin_op, l, r, @@ -355,7 +352,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { right: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { trace!( - "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", + "Running binary op {:?}: {:?} ({}), {:?} ({})", bin_op, *left, left.layout.ty, @@ -394,7 +391,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // the RHS type can be different, e.g. for shifts -- but it has to be integral, too assert!( right.layout.ty.is_integral(), - "Unexpected types for BinOp: {:?} {:?} {:?}", + "Unexpected types for BinOp: {} {:?} {}", left.layout.ty, bin_op, right.layout.ty @@ -409,7 +406,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // (Even when both sides are pointers, their type might differ, see issue #91636) assert!( right.layout.ty.is_any_ptr() || right.layout.ty.is_integral(), - "Unexpected types for BinOp: {:?} {:?} {:?}", + "Unexpected types for BinOp: {} {:?} {}", left.layout.ty, bin_op, right.layout.ty @@ -419,7 +416,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } _ => span_bug!( self.cur_span(), - "Invalid MIR: bad LHS type for binop: {:?}", + "Invalid MIR: bad LHS type for binop: {}", left.layout.ty ), } @@ -447,7 +444,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = val.layout; let val = val.to_scalar(); - trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty); + trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty); match layout.ty.kind() { ty::Bool => { diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index fb9aa9d3abe6..503004cbbe1e 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -460,7 +460,7 @@ where trace!("deref to {} on {:?}", val.layout.ty, *val); if val.layout.ty.is_box() { - bug!("dereferencing {:?}", val.layout.ty); + bug!("dereferencing {}", val.layout.ty); } let mplace = self.ref_to_mplace(&val)?; @@ -582,7 +582,7 @@ where )?)?, place.layout, ), - "eval_place of a MIR place with type {:?} produced an interpreter place with type {:?}", + "eval_place of a MIR place with type {:?} produced an interpreter place with type {}", mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, place.layout.ty, ); @@ -835,7 +835,7 @@ where if !allow_transmute && !layout_compat { span_bug!( self.cur_span(), - "type mismatch when copying!\nsrc: {:?},\ndest: {:?}", + "type mismatch when copying!\nsrc: {},\ndest: {}", src.layout().ty, dest.layout().ty, ); diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 8a62a816c961..578dd6622aaf 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -149,7 +149,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } _ => span_bug!( terminator.source_info.span, - "invalid callee of type {:?}", + "invalid callee of type {}", func.layout.ty ), }; @@ -679,10 +679,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.storage_live(local)?; // Must be a tuple let ty::Tuple(fields) = ty.kind() else { - span_bug!( - self.cur_span(), - "non-tuple type for `spread_arg`: {ty:?}" - ) + span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}") }; for (i, field_ty) in fields.iter().enumerate() { let dest = dest.project_deeper( @@ -924,7 +921,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { target: mir::BasicBlock, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { - trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance); + trace!("drop_in_place: {:?},\n instance={:?}", place, instance); // We take the address of the object. This may well be unaligned, which is fine // for us here. However, unaligned accesses will probably make the actual drop // implementation fail -- a problem shared by rustc. From 23fd2860fa0aa521083019df952d762b43400212 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Sep 2023 22:28:46 +0200 Subject: [PATCH 08/26] stronger consistency check in ImmTy::from_immediate --- compiler/rustc_const_eval/src/interpret/operand.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index c351fa84d37f..62efa84f869a 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -159,7 +159,15 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline(always)] pub fn from_immediate(imm: Immediate, layout: TyAndLayout<'tcx>) -> Self { - debug_assert!(layout.is_sized(), "immediates must be sized"); + debug_assert!( + match (imm, layout.abi) { + (Immediate::Scalar(..), Abi::Scalar(..)) => true, + (Immediate::ScalarPair(..), Abi::ScalarPair(..)) => true, + (Immediate::Uninit, _) if layout.is_sized() => true, + _ => false, + }, + "immediate {imm:?} does not fit to layout {layout:?}", + ); ImmTy { imm, layout } } @@ -448,7 +456,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { alloc_range(Size::ZERO, size), /*read_provenance*/ matches!(s, abi::Pointer(_)), )?; - Some(ImmTy { imm: scalar.into(), layout: mplace.layout }) + Some(ImmTy::from_scalar(scalar, mplace.layout)) } Abi::ScalarPair( abi::Scalar::Initialized { value: a, .. }, @@ -468,7 +476,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { alloc_range(b_offset, b_size), /*read_provenance*/ matches!(b, abi::Pointer(_)), )?; - Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout }) + Some(ImmTy::from_immediate(Immediate::ScalarPair(a_val, b_val), mplace.layout)) } _ => { // Neither a scalar nor scalar pair. From 667bba46b0dc1ed5f481431c48c24b8326e099a1 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 20 Sep 2023 22:37:39 +0200 Subject: [PATCH 09/26] Fix typo. --- library/core/src/panicking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 1f4c7c376bda..e6cdffd96afb 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -234,7 +234,7 @@ fn panic_in_cleanup() -> ! { #[rustc_const_unstable(feature = "core_panic", issue = "none")] pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if let Some(msg) = fmt.as_str() { - // The panic_display function is hooked by conost eval. + // The panic_display function is hooked by const eval. panic_display(&msg); } else { // SAFETY: This is only evaluated at compile time, which reliably From 3dcc8fcab5eecf1cf9715ed78609994ec37c9863 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 20 Sep 2023 22:09:48 -0700 Subject: [PATCH 10/26] Delete obsolete --disable-per-crate-search rustdoc flag --- src/librustdoc/lib.rs | 7 ------- .../issue-88756-default-output/output-default.stdout | 3 --- tests/rustdoc/no-crate-filter.rs | 6 ------ 3 files changed, 16 deletions(-) delete mode 100644 tests/rustdoc/no-crate-filter.rs diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2f88f6dc6e0a..fc2acb6eaa35 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -503,13 +503,6 @@ fn opts() -> Vec { "PATH", ) }), - unstable("disable-per-crate-search", |o| { - o.optflagmulti( - "", - "disable-per-crate-search", - "disables generating the crate selector on the search box", - ) - }), unstable("persist-doctests", |o| { o.optopt( "", diff --git a/tests/run-make/issue-88756-default-output/output-default.stdout b/tests/run-make/issue-88756-default-output/output-default.stdout index f5981045b03d..38a3965f0c53 100644 --- a/tests/run-make/issue-88756-default-output/output-default.stdout +++ b/tests/run-make/issue-88756-default-output/output-default.stdout @@ -133,9 +133,6 @@ Options: Path string to force loading static files from in output pages. If not set, uses combinations of '../' to reach the documentation root. - --disable-per-crate-search - disables generating the crate selector on the search - box --persist-doctests PATH Directory to persist doctest executables into --show-coverage diff --git a/tests/rustdoc/no-crate-filter.rs b/tests/rustdoc/no-crate-filter.rs deleted file mode 100644 index b2f89906480d..000000000000 --- a/tests/rustdoc/no-crate-filter.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![crate_name = "foo"] - -// compile-flags: -Z unstable-options --disable-per-crate-search - -// @!has 'foo/struct.Foo.html' '//*[id="crate-search"]' '' -pub struct Foo; From 0eff07b748b82240cd9605c631268ba1c8c8e58f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Sep 2023 07:26:11 +0200 Subject: [PATCH 11/26] try to avoid some layout_of calls --- .../rustc_const_eval/src/interpret/cast.rs | 67 +++++++++---------- .../src/interpret/discriminant.rs | 2 +- .../src/dataflow_const_prop.rs | 10 ++- src/tools/miri/src/helpers.rs | 9 +-- src/tools/miri/src/shims/intrinsics/mod.rs | 4 +- src/tools/miri/src/shims/intrinsics/simd.rs | 16 ++--- src/tools/miri/src/shims/x86/sse.rs | 4 +- src/tools/miri/src/shims/x86/sse2.rs | 34 +++++----- 8 files changed, 75 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index e18d72a766ba..d6e4dcd2fd41 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -24,40 +24,43 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { cast_ty: Ty<'tcx>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { + // `cast_ty` will often be the same as `dest.ty`, but not always, since subtyping is still + // possible. + let cast_layout = + if cast_ty == dest.layout.ty { dest.layout } else { self.layout_of(cast_ty)? }; // FIXME: In which cases should we trigger UB when the source is uninit? match cast_kind { CastKind::PointerCoercion(PointerCoercion::Unsize) => { - let cast_ty = self.layout_of(cast_ty)?; - self.unsize_into(src, cast_ty, dest)?; + self.unsize_into(src, cast_layout, dest)?; } CastKind::PointerExposeAddress => { let src = self.read_immediate(src)?; - let res = self.pointer_expose_address_cast(&src, cast_ty)?; + let res = self.pointer_expose_address_cast(&src, cast_layout)?; self.write_immediate(*res, dest)?; } CastKind::PointerFromExposedAddress => { let src = self.read_immediate(src)?; - let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?; + let res = self.pointer_from_exposed_address_cast(&src, cast_layout)?; self.write_immediate(*res, dest)?; } CastKind::IntToInt | CastKind::IntToFloat => { let src = self.read_immediate(src)?; - let res = self.int_to_int_or_float(&src, cast_ty)?; + let res = self.int_to_int_or_float(&src, cast_layout)?; self.write_immediate(*res, dest)?; } CastKind::FloatToFloat | CastKind::FloatToInt => { let src = self.read_immediate(src)?; - let res = self.float_to_float_or_int(&src, cast_ty)?; + let res = self.float_to_float_or_int(&src, cast_layout)?; self.write_immediate(*res, dest)?; } CastKind::FnPtrToPtr | CastKind::PtrToPtr => { let src = self.read_immediate(src)?; - let res = self.ptr_to_ptr(&src, cast_ty)?; + let res = self.ptr_to_ptr(&src, cast_layout)?; self.write_immediate(*res, dest)?; } @@ -140,6 +143,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { CastKind::Transmute => { assert!(src.layout.is_sized()); assert!(dest.layout.is_sized()); + assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely... if src.layout.size != dest.layout.size { let src_bytes = src.layout.size.bytes(); let dest_bytes = dest.layout.size.bytes(); @@ -164,15 +168,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn int_to_int_or_float( &self, src: &ImmTy<'tcx, M::Provenance>, - cast_ty: Ty<'tcx>, + cast_to: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool()); - assert!(cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char()); + assert!(cast_to.ty.is_floating_point() || cast_to.ty.is_integral() || cast_to.ty.is_char()); - let layout = self.layout_of(cast_ty)?; Ok(ImmTy::from_scalar( - self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?, - layout, + self.cast_from_int_like(src.to_scalar(), src.layout, cast_to.ty)?, + cast_to, )) } @@ -180,48 +183,46 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn float_to_float_or_int( &self, src: &ImmTy<'tcx, M::Provenance>, - cast_ty: Ty<'tcx>, + cast_to: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { use rustc_type_ir::sty::TyKind::*; - let layout = self.layout_of(cast_ty)?; let val = match src.layout.ty.kind() { // Floating point - Float(FloatTy::F32) => self.cast_from_float(src.to_scalar().to_f32()?, cast_ty), - Float(FloatTy::F64) => self.cast_from_float(src.to_scalar().to_f64()?, cast_ty), + Float(FloatTy::F32) => self.cast_from_float(src.to_scalar().to_f32()?, cast_to.ty), + Float(FloatTy::F64) => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty), _ => { - bug!("Can't cast 'Float' type into {}", cast_ty); + bug!("Can't cast 'Float' type into {}", cast_to.ty); } }; - Ok(ImmTy::from_scalar(val, layout)) + Ok(ImmTy::from_scalar(val, cast_to)) } /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts. pub fn ptr_to_ptr( &self, src: &ImmTy<'tcx, M::Provenance>, - cast_ty: Ty<'tcx>, + cast_to: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_any_ptr()); - assert!(cast_ty.is_unsafe_ptr()); + assert!(cast_to.ty.is_unsafe_ptr()); // Handle casting any ptr to raw ptr (might be a fat ptr). - let dest_layout = self.layout_of(cast_ty)?; - if dest_layout.size == src.layout.size { + if cast_to.size == src.layout.size { // Thin or fat pointer that just hast the ptr kind of target type changed. - return Ok(ImmTy::from_immediate(**src, dest_layout)); + return Ok(ImmTy::from_immediate(**src, cast_to)); } else { // Casting the metadata away from a fat ptr. assert_eq!(src.layout.size, 2 * self.pointer_size()); - assert_eq!(dest_layout.size, self.pointer_size()); + assert_eq!(cast_to.size, self.pointer_size()); assert!(src.layout.ty.is_unsafe_ptr()); return match **src { - Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, dest_layout)), + Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, cast_to)), Immediate::Scalar(..) => span_bug!( self.cur_span(), "{:?} input to a fat-to-thin cast ({} -> {})", *src, src.layout.ty, - cast_ty + cast_to.ty ), Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; @@ -231,10 +232,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn pointer_expose_address_cast( &mut self, src: &ImmTy<'tcx, M::Provenance>, - cast_ty: Ty<'tcx>, + cast_to: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_)); - assert!(cast_ty.is_integral()); + assert!(cast_to.ty.is_integral()); let scalar = src.to_scalar(); let ptr = scalar.to_pointer(self)?; @@ -242,17 +243,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(ptr) => M::expose_ptr(self, ptr)?, Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP. }; - let layout = self.layout_of(cast_ty)?; - Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_ty)?, layout)) + Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to)) } pub fn pointer_from_exposed_address_cast( &self, src: &ImmTy<'tcx, M::Provenance>, - cast_ty: Ty<'tcx>, + cast_to: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_integral()); - assert_matches!(cast_ty.kind(), ty::RawPtr(_)); + assert_matches!(cast_to.ty.kind(), ty::RawPtr(_)); // First cast to usize. let scalar = src.to_scalar(); @@ -261,8 +261,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Then turn address into pointer. let ptr = M::ptr_from_addr_cast(&self, addr)?; - let layout = self.layout_of(cast_ty)?; - Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), layout)) + Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to)) } /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index f177edd2b412..49e01728ff4b 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -163,7 +163,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Cast bits from tag layout to discriminant layout. // After the checks we did above, this cannot fail, as // discriminants are int-like. - let discr_val = self.int_to_int_or_float(&tag_val, discr_layout.ty).unwrap(); + let discr_val = self.int_to_int_or_float(&tag_val, discr_layout).unwrap(); let discr_bits = discr_val.to_scalar().assert_bits(discr_layout.size); // Convert discriminant to variant index, and catch invalid discriminants. let index = match *ty.kind() { diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index d3e85dc8e0ae..5f12057113ab 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -234,20 +234,26 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } } Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => { + let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else { + return ValueOrPlace::Value(FlatSet::Top); + }; match self.eval_operand(operand, state) { FlatSet::Elem(op) => self .ecx - .int_to_int_or_float(&op, *ty) + .int_to_int_or_float(&op, layout) .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, } } Rvalue::Cast(CastKind::FloatToInt | CastKind::FloatToFloat, operand, ty) => { + let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else { + return ValueOrPlace::Value(FlatSet::Top); + }; match self.eval_operand(operand, state) { FlatSet::Elem(op) => self .ecx - .float_to_float_or_int(&op, *ty) + .float_to_float_or_int(&op, layout) .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index d5b658969e3d..537c767065d9 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1013,7 +1013,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn float_to_int_checked( &self, f: F, - dest_ty: Ty<'tcx>, + cast_to: TyAndLayout<'tcx>, round: rustc_apfloat::Round, ) -> Option> where @@ -1021,7 +1021,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { { let this = self.eval_context_ref(); - let val = match dest_ty.kind() { + let val = match cast_to.ty.kind() { // Unsigned ty::Uint(t) => { let size = Integer::from_uint_ty(this, *t).size(); @@ -1062,10 +1062,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { _ => span_bug!( this.cur_span(), - "attempted float-to-int conversion with non-int output type {dest_ty:?}" + "attempted float-to-int conversion with non-int output type {}", + cast_to.ty, ), }; - Some(ImmTy::from_scalar(val, this.layout_of(dest_ty).unwrap())) + Some(ImmTy::from_scalar(val, cast_to)) } /// Returns an integer type that is twice wide as `ty` diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index 224ef97a1e12..d54145dbdc7f 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -368,7 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ty::Float(FloatTy::F32) => { let f = val.to_scalar().to_f32()?; this - .float_to_int_checked(f, dest.layout.ty, Round::TowardZero) + .float_to_int_checked(f, dest.layout, Round::TowardZero) .ok_or_else(|| { err_ub_format!( "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`", @@ -379,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ty::Float(FloatTy::F64) => { let f = val.to_scalar().to_f64()?; this - .float_to_int_checked(f, dest.layout.ty, Round::TowardZero) + .float_to_int_checked(f, dest.layout, Round::TowardZero) .ok_or_else(|| { err_ub_format!( "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`", diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index 98b21f768b1f..49ba7e5556e6 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -441,17 +441,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Int-to-(int|float): always safe (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) if safe_cast || unsafe_cast => - this.int_to_int_or_float(&op, dest.layout.ty)?, + this.int_to_int_or_float(&op, dest.layout)?, // Float-to-float: always safe (ty::Float(_), ty::Float(_)) if safe_cast || unsafe_cast => - this.float_to_float_or_int(&op, dest.layout.ty)?, + this.float_to_float_or_int(&op, dest.layout)?, // Float-to-int in safe mode (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast => - this.float_to_float_or_int(&op, dest.layout.ty)?, + this.float_to_float_or_int(&op, dest.layout)?, // Float-to-int in unchecked mode (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if unsafe_cast => { let f = op.to_scalar().to_f32()?; - this.float_to_int_checked(f, dest.layout.ty, Round::TowardZero) + this.float_to_int_checked(f, dest.layout, Round::TowardZero) .ok_or_else(|| { err_ub_format!( "`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`", @@ -462,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if unsafe_cast => { let f = op.to_scalar().to_f64()?; - this.float_to_int_checked(f, dest.layout.ty, Round::TowardZero) + this.float_to_int_checked(f, dest.layout, Round::TowardZero) .ok_or_else(|| { err_ub_format!( "`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`", @@ -473,12 +473,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } // Ptr-to-ptr cast (ty::RawPtr(..), ty::RawPtr(..)) if ptr_cast => - this.ptr_to_ptr(&op, dest.layout.ty)?, + this.ptr_to_ptr(&op, dest.layout)?, // Ptr/Int casts (ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) if expose_cast => - this.pointer_expose_address_cast(&op, dest.layout.ty)?, + this.pointer_expose_address_cast(&op, dest.layout)?, (ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast => - this.pointer_from_exposed_address_cast(&op, dest.layout.ty)?, + this.pointer_from_exposed_address_cast(&op, dest.layout)?, // Error otherwise _ => throw_unsup_format!( diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index 17a39660edb5..b6b994b45ac8 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -173,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { _ => unreachable!(), }; - let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { + let res = this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE semantics. ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); @@ -196,7 +196,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let right = this.read_immediate(right)?; let dest0 = this.project_index(&dest, 0)?; - let res0 = this.int_to_int_or_float(&right, dest0.layout.ty)?; + let res0 = this.int_to_int_or_float(&right, dest0.layout)?; this.write_immediate(*res0, &dest0)?; for i in 1..dest_len { diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 03b298a23ecf..7e10d1d3726e 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -56,10 +56,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest = this.project_index(&dest, i)?; // Widen the operands to avoid overflow - let twice_wide_ty = this.get_twice_wide_int_ty(left.layout.ty); - let twice_wide_layout = this.layout_of(twice_wide_ty)?; - let left = this.int_to_int_or_float(&left, twice_wide_ty)?; - let right = this.int_to_int_or_float(&right, twice_wide_ty)?; + let twice_wide = this.layout_of(this.get_twice_wide_int_ty(left.layout.ty))?; + let left = this.int_to_int_or_float(&left, twice_wide)?; + let right = this.int_to_int_or_float(&right, twice_wide)?; // Calculate left + right + 1 let added = this.wrapping_binary_op( @@ -70,20 +69,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let added = this.wrapping_binary_op( mir::BinOp::Add, &added, - &ImmTy::from_uint(1u32, twice_wide_layout), + &ImmTy::from_uint(1u32, twice_wide), )?; // Calculate (left + right + 1) / 2 let divided = this.wrapping_binary_op( mir::BinOp::Div, &added, - &ImmTy::from_uint(2u32, twice_wide_layout), + &ImmTy::from_uint(2u32, twice_wide), )?; // Narrow back to the original type let res = this.int_to_int_or_float( ÷d, - dest.layout.ty, + dest.layout, )?; this.write_immediate(*res, &dest)?; } @@ -106,10 +105,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest = this.project_index(&dest, i)?; // Widen the operands to avoid overflow - let twice_wide_ty = this.get_twice_wide_int_ty(left.layout.ty); - let twice_wide_layout = this.layout_of(twice_wide_ty)?; - let left = this.int_to_int_or_float(&left, twice_wide_ty)?; - let right = this.int_to_int_or_float(&right, twice_wide_ty)?; + let twice_wide = this.layout_of(this.get_twice_wide_int_ty(left.layout.ty))?; + let left = this.int_to_int_or_float(&left, twice_wide)?; + let right = this.int_to_int_or_float(&right, twice_wide)?; // Multiply let multiplied = this.wrapping_binary_op( @@ -121,13 +119,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let high = this.wrapping_binary_op( mir::BinOp::Shr, &multiplied, - &ImmTy::from_uint(dest.layout.size.bits(), twice_wide_layout), + &ImmTy::from_uint(dest.layout.size.bits(), twice_wide), )?; // Narrow back to the original type let res = this.int_to_int_or_float( &high, - dest.layout.ty, + dest.layout, )?; this.write_immediate(*res, &dest)?; } @@ -392,7 +390,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest = this.project_index(&dest, i)?; let res = - this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { + this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE2 semantics. ImmTy::from_int(i32::MIN, this.machine.layouts.i32) }); @@ -648,7 +646,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let op = this.read_immediate(&this.project_index(&op, i)?)?; let dest = this.project_index(&dest, i)?; - let res = this.float_to_float_or_int(&op, dest.layout.ty)?; + let res = this.float_to_float_or_int(&op, dest.layout)?; this.write_immediate(*res, &dest)?; } // For f32 -> f64, ignore the remaining @@ -685,7 +683,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest = this.project_index(&dest, i)?; let res = - this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { + this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE2 semantics. ImmTy::from_int(i32::MIN, this.machine.layouts.i32) }); @@ -716,7 +714,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { _ => unreachable!(), }; - let res = this.float_to_int_checked(op, dest.layout.ty, rnd).unwrap_or_else(|| { + let res = this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| { // Fallback to minimum acording to SSE semantics. ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); @@ -741,7 +739,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let dest0 = this.project_index(&dest, 0)?; // `float_to_float_or_int` here will convert from f64 to f32 (cvtsd2ss) or // from f32 to f64 (cvtss2sd). - let res0 = this.float_to_float_or_int(&right0, dest0.layout.ty)?; + let res0 = this.float_to_float_or_int(&right0, dest0.layout)?; this.write_immediate(*res0, &dest0)?; // Copy remianing from `left` From c94410c1458f9ea55e51fc9af478d94a82ec90a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Sep 2023 20:51:14 +0200 Subject: [PATCH 12/26] rename mir::Constant -> mir::ConstOperand, mir::ConstKind -> mir::Const --- .../rustc_borrowck/src/diagnostics/mod.rs | 6 +- compiler/rustc_borrowck/src/renumber.rs | 9 +- compiler/rustc_borrowck/src/type_check/mod.rs | 28 +++--- .../rustc_codegen_cranelift/src/constant.rs | 6 +- .../rustc_codegen_cranelift/src/inline_asm.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 4 +- .../rustc_codegen_ssa/src/mir/constant.rs | 20 ++--- .../src/interpret/eval_context.rs | 2 +- .../rustc_const_eval/src/interpret/operand.rs | 2 +- .../src/transform/check_consts/qualifs.rs | 12 +-- .../src/transform/promote_consts.rs | 16 ++-- compiler/rustc_middle/src/mir/consts.rs | 90 ++++--------------- compiler/rustc_middle/src/mir/mod.rs | 8 +- compiler/rustc_middle/src/mir/pretty.rs | 55 +++++++++--- compiler/rustc_middle/src/mir/statement.rs | 36 ++++++-- compiler/rustc_middle/src/mir/syntax.rs | 34 +++---- compiler/rustc_middle/src/mir/tcx.rs | 2 +- compiler/rustc_middle/src/mir/visit.rs | 16 ++-- compiler/rustc_middle/src/query/erase.rs | 7 +- compiler/rustc_middle/src/query/keys.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/thir.rs | 10 +-- compiler/rustc_middle/src/thir/visit.rs | 6 +- .../rustc_middle/src/util/find_self_call.rs | 4 +- compiler/rustc_mir_build/src/build/cfg.rs | 6 +- .../src/build/custom/parse/instruction.rs | 8 +- .../src/build/expr/as_constant.rs | 54 +++++------ .../src/build/expr/as_rvalue.rs | 10 +-- .../rustc_mir_build/src/build/expr/into.rs | 24 +++-- .../rustc_mir_build/src/build/matches/mod.rs | 4 +- .../rustc_mir_build/src/build/matches/test.rs | 24 +++-- compiler/rustc_mir_build/src/build/misc.rs | 14 ++- compiler/rustc_mir_build/src/thir/cx/expr.rs | 14 +-- .../src/thir/pattern/const_to_pat.rs | 22 ++--- .../src/thir/pattern/deconstruct_pat.rs | 12 +-- .../rustc_mir_build/src/thir/pattern/mod.rs | 34 +++---- .../rustc_mir_dataflow/src/elaborate_drops.rs | 4 +- compiler/rustc_mir_dataflow/src/rustc_peek.rs | 2 +- .../rustc_mir_dataflow/src/value_analysis.rs | 4 +- .../src/check_alignment.rs | 14 +-- .../rustc_mir_transform/src/check_unsafety.rs | 6 +- .../src/const_debuginfo.rs | 4 +- .../rustc_mir_transform/src/const_goto.rs | 2 +- .../rustc_mir_transform/src/const_prop.rs | 8 +- .../src/const_prop_lint.rs | 6 +- .../src/dataflow_const_prop.rs | 22 ++--- .../src/deduplicate_blocks.rs | 8 +- .../src/elaborate_drops.rs | 4 +- compiler/rustc_mir_transform/src/generator.rs | 4 +- compiler/rustc_mir_transform/src/inline.rs | 8 +- .../rustc_mir_transform/src/instsimplify.rs | 6 +- .../rustc_mir_transform/src/large_enums.rs | 4 +- compiler/rustc_mir_transform/src/lib.rs | 10 +-- .../src/lower_intrinsics.rs | 4 +- .../rustc_mir_transform/src/match_branches.rs | 12 +-- .../src/normalize_array_len.rs | 4 +- .../rustc_mir_transform/src/remove_zsts.rs | 6 +- .../src/required_consts.rs | 18 ++-- .../rustc_mir_transform/src/reveal_all.rs | 6 +- compiler/rustc_mir_transform/src/shim.rs | 8 +- .../src/simplify_branches.rs | 4 +- .../src/simplify_comparison_integral.rs | 4 +- compiler/rustc_monomorphize/src/collector.rs | 12 +-- .../rustc_monomorphize/src/polymorphize.rs | 16 ++-- compiler/rustc_smir/src/rustc_smir/mod.rs | 14 +-- src/librustdoc/clean/utils.rs | 8 +- .../clippy/clippy_lints/src/enum_clike.rs | 2 +- .../src/matches/overlapping_arms.rs | 4 +- src/tools/clippy/clippy_utils/src/consts.rs | 20 ++--- src/tools/clippy/clippy_utils/src/lib.rs | 6 +- ...ans.outer.PreCodegen.after.panic-abort.mir | 4 +- ...ns.outer.PreCodegen.after.panic-unwind.mir | 4 +- 72 files changed, 430 insertions(+), 449 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 099e07e88414..f70263e9dcf0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -13,7 +13,7 @@ use rustc_index::IndexSlice; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ - AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, + AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; @@ -101,12 +101,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let terminator = self.body[location.block].terminator(); debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator); if let TerminatorKind::Call { - func: Operand::Constant(box Constant { literal, .. }), + func: Operand::Constant(box ConstOperand { const_, .. }), args, .. } = &terminator.kind { - if let ty::FnDef(id, _) = *literal.ty().kind() { + if let ty::FnDef(id, _) = *const_.ty().kind() { debug!("add_moved_or_invoked_closure_note: id={:?}", id); if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() { let closure = match args.first() { diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 4c69ea843c72..4c7c4982050e 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -4,8 +4,7 @@ use crate::BorrowckInferCtxt; use rustc_index::IndexSlice; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::visit::{MutVisitor, TyContext}; -use rustc_middle::mir::Constant; -use rustc_middle::mir::{Body, Location, Promoted}; +use rustc_middle::mir::{Body, ConstOperand, Location, Promoted}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::{Span, Symbol}; @@ -117,9 +116,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) { - let literal = constant.literal; - constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(location)); + fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { + let const_ = constant.const_; + constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location)); debug!("constant: {:#?}", constant); } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 0f661421cdcf..60e6dcaf0b88 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -302,11 +302,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { self.sanitize_place(place, location, context); } - fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { debug!(?constant, ?location, "visit_constant"); self.super_constant(constant, location); - let ty = self.sanitize_type(constant, constant.literal.ty()); + let ty = self.sanitize_type(constant, constant.const_.ty()); self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { let live_region_vid = @@ -328,7 +328,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( - constant.literal.ty(), + constant.const_.ty(), ty::Variance::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, locations, @@ -340,20 +340,20 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { constant, "bad constant user type {:?} vs {:?}: {:?}", annotation, - constant.literal.ty(), + constant.const_.ty(), terr, ); } } else { let tcx = self.tcx(); - let maybe_uneval = match constant.literal { - ConstantKind::Ty(ct) => match ct.kind() { + let maybe_uneval = match constant.const_ { + Const::Ty(ct) => match ct.kind() { ty::ConstKind::Unevaluated(_) => { - bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct) + bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct) } _ => None, }, - ConstantKind::Unevaluated(uv, _) => Some(uv), + Const::Unevaluated(uv, _) => Some(uv), _ => None, }; @@ -384,7 +384,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { check_err(self, promoted_body, ty, promoted_ty); } else { self.cx.ascribe_user_type( - constant.literal.ty(), + constant.const_.ty(), UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }), locations.span(&self.cx.body), ); @@ -392,7 +392,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); let normalized_ty = self.cx.normalize(unnormalized_ty, locations); - let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty; + let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty; if let Err(terr) = self.cx.eq_types( literal_ty, @@ -404,7 +404,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } } - if let ty::FnDef(def_id, args) = *constant.literal.ty().kind() { + if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args); self.cx.normalize_and_prove_instantiated_predicates( def_id, @@ -1801,9 +1801,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!(?op, ?location, "check_operand"); if let Operand::Constant(constant) = op { - let maybe_uneval = match constant.literal { - ConstantKind::Val(..) | ConstantKind::Ty(_) => None, - ConstantKind::Unevaluated(uv, _) => Some(uv), + let maybe_uneval = match constant.const_ { + Const::Val(..) | Const::Ty(_) => None, + Const::Unevaluated(uv, _) => Some(uv), }; if let Some(uv) = maybe_uneval { diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 02468684ba05..59932db0fa6f 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -64,9 +64,9 @@ pub(crate) fn codegen_tls_ref<'tcx>( pub(crate) fn eval_mir_constant<'tcx>( fx: &FunctionCx<'_, '_, 'tcx>, - constant: &Constant<'tcx>, + constant: &ConstOperand<'tcx>, ) -> (ConstValue<'tcx>, Ty<'tcx>) { - let cv = fx.monomorphize(constant.literal); + let cv = fx.monomorphize(constant.const_); // This cannot fail because we checked all required_consts in advance. let val = cv .eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span)) @@ -76,7 +76,7 @@ pub(crate) fn eval_mir_constant<'tcx>( pub(crate) fn codegen_constant_operand<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - constant: &Constant<'tcx>, + constant: &ConstOperand<'tcx>, ) -> CValue<'tcx> { let (const_val, ty) = eval_mir_constant(fx, constant); codegen_const_value(fx, const_val, ty) diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index eba90949b5e5..50bbf8105fdb 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -252,8 +252,8 @@ pub(crate) fn codegen_inline_asm<'tcx>( CInlineAsmOperand::Const { value } } InlineAsmOperand::SymFn { ref value } => { - let literal = fx.monomorphize(value.literal); - if let ty::FnDef(def_id, args) = *literal.ty().kind() { + let const_ = fx.monomorphize(value.const_); + if let ty::FnDef(def_id, args) = *const_.ty().kind() { let instance = ty::Instance::resolve_for_fn_ptr( fx.tcx, ty::ParamEnv::reveal_all(), diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b738a49bf119..bd0707edfd99 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1098,8 +1098,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { InlineAsmOperandRef::Const { string } } mir::InlineAsmOperand::SymFn { ref value } => { - let literal = self.monomorphize(value.literal); - if let ty::FnDef(def_id, args) = *literal.ty().kind() { + let const_ = self.monomorphize(value.const_); + if let ty::FnDef(def_id, args) = *const_.ty().kind() { let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), ty::ParamEnv::reveal_all(), diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 7fec4047a95c..fde4e85f9662 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -13,37 +13,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn eval_mir_constant_to_operand( &self, bx: &mut Bx, - constant: &mir::Constant<'tcx>, + constant: &mir::ConstOperand<'tcx>, ) -> OperandRef<'tcx, Bx::Value> { let val = self.eval_mir_constant(constant); let ty = self.monomorphize(constant.ty()); OperandRef::from_const(bx, val, ty) } - pub fn eval_mir_constant(&self, constant: &mir::Constant<'tcx>) -> mir::ConstValue<'tcx> { - self.monomorphize(constant.literal) + pub fn eval_mir_constant(&self, constant: &mir::ConstOperand<'tcx>) -> mir::ConstValue<'tcx> { + self.monomorphize(constant.const_) .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span)) .expect("erroneous constant not captured by required_consts") } /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition - /// that the given `constant` is an `ConstantKind::Unevaluated` and must be convertible to + /// that the given `constant` is an `Const::Unevaluated` and must be convertible to /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip. /// /// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees! pub fn eval_unevaluated_mir_constant_to_valtree( &self, - constant: &mir::Constant<'tcx>, + constant: &mir::ConstOperand<'tcx>, ) -> Result>, ErrorHandled> { - let uv = match self.monomorphize(constant.literal) { - mir::ConstantKind::Unevaluated(uv, _) => uv.shrink(), - mir::ConstantKind::Ty(c) => match c.kind() { + let uv = match self.monomorphize(constant.const_) { + mir::Const::Unevaluated(uv, _) => uv.shrink(), + mir::Const::Ty(c) => match c.kind() { // A constant that came from a const generic but was then used as an argument to old-style // simd_shuffle (passing as argument instead of as a generic param). rustc_type_ir::ConstKind::Value(valtree) => return Ok(Some(valtree)), other => span_bug!(constant.span, "{other:#?}"), }, - // We should never encounter `ConstantKind::Val` unless MIR opts (like const prop) evaluate + // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate // a constant and write that value back into `Operand`s. This could happen, but is unlikely. // Also: all users of `simd_shuffle` are on unstable and already need to take a lot of care // around intrinsics. For an issue to happen here, it would require a macro expanding to a @@ -65,7 +65,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn simd_shuffle_indices( &mut self, bx: &Bx, - constant: &mir::Constant<'tcx>, + constant: &mir::ConstOperand<'tcx>, ) -> (Bx::Value, Ty<'tcx>) { let ty = self.monomorphize(constant.ty()); let val = self diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index cb14e165b5c4..f908063d6954 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1089,7 +1089,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn eval_mir_constant( &self, - val: &mir::ConstantKind<'tcx>, + val: &mir::Const<'tcx>, span: Option, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 788b50d7c4af..2dbc6eec421d 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -686,7 +686,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Constant(constant) => { let c = - self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?; + self.subst_from_current_frame_and_normalize_erasing_regions(constant.const_)?; // This can still fail: // * During ConstProp, with `TooGeneric` or since the `required_consts` were not all diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index b1b2859ef9dc..34e9b76c4844 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -346,8 +346,8 @@ where }; // Check the qualifs of the value of `const` items. - let uneval = match constant.literal { - ConstantKind::Ty(ct) + let uneval = match constant.const_ { + Const::Ty(ct) if matches!( ct.kind(), ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_) @@ -355,11 +355,11 @@ where { None } - ConstantKind::Ty(c) => { + Const::Ty(c) => { bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c) } - ConstantKind::Unevaluated(uv, _) => Some(uv), - ConstantKind::Val(..) => None, + Const::Unevaluated(uv, _) => Some(uv), + Const::Val(..) => None, }; if let Some(mir::UnevaluatedConst { def, args: _, promoted }) = uneval { @@ -383,5 +383,5 @@ where } // Otherwise use the qualifs of the type. - Q::in_any_value_of_ty(cx, constant.literal.ty()) + Q::in_any_value_of_ty(cx, constant.const_.ty()) } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index d346fd721609..65eed5e05688 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -372,7 +372,7 @@ impl<'tcx> Validator<'_, 'tcx> { StatementKind::Assign(box ( _, Rvalue::Use(Operand::Constant(c)), - )) => c.literal.try_eval_target_usize(self.tcx, self.param_env), + )) => c.const_.try_eval_target_usize(self.tcx, self.param_env), _ => None, } } else { @@ -554,7 +554,7 @@ impl<'tcx> Validator<'_, 'tcx> { // Integer division: the RHS must be a non-zero const. let const_val = match rhs { Operand::Constant(c) => { - c.literal.try_eval_bits(self.tcx, self.param_env) + c.const_.try_eval_bits(self.tcx, self.param_env) } _ => None, }; @@ -766,10 +766,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { if self.keep_original { rhs.clone() } else { - let unit = Rvalue::Use(Operand::Constant(Box::new(Constant { + let unit = Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: statement.source_info.span, user_ty: None, - literal: ConstantKind::zero_sized(self.tcx.types.unit), + const_: Const::zero_sized(self.tcx.types.unit), }))); mem::replace(rhs, unit) }, @@ -844,10 +844,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def)); let uneval = mir::UnevaluatedConst { def, args, promoted: Some(promoted_id) }; - Operand::Constant(Box::new(Constant { + Operand::Constant(Box::new(ConstOperand { span, user_ty: None, - literal: ConstantKind::Unevaluated(uneval, ty), + const_: Const::Unevaluated(uneval, ty), })) }; @@ -1041,8 +1041,8 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>( if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) = &block.terminator { - if let Operand::Constant(box Constant { literal, .. }) = func { - if let ty::FnDef(def_id, _) = *literal.ty().kind() { + if let Operand::Constant(box ConstOperand { const_, .. }) = func { + if let ty::FnDef(def_id, _) = *const_.ty().kind() { if destination == place { if ccx.tcx.is_const_fn(def_id) { return true; diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index cbe84bf840ab..23bbacb1e613 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -6,13 +6,11 @@ use rustc_hir::{self as hir}; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, Size}; -use crate::mir::interpret::{ - alloc_range, AllocId, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar, -}; +use crate::mir::interpret::{alloc_range, AllocId, ConstAllocation, ErrorHandled, Scalar}; use crate::mir::{pretty_print_const_value, Promoted}; +use crate::ty::ScalarInt; use crate::ty::{self, print::pretty_print_const, List, Ty, TyCtxt}; use crate::ty::{GenericArgs, GenericArgsRef}; -use crate::ty::{ScalarInt, UserTypeAnnotationIndex}; /////////////////////////////////////////////////////////////////////////// /// Evaluated Constants @@ -169,29 +167,10 @@ impl<'tcx> ConstValue<'tcx> { /////////////////////////////////////////////////////////////////////////// /// Constants -/// -/// Two constants are equal if they are the same constant. Note that -/// this does not necessarily mean that they are `==` in Rust. In -/// particular, one must be wary of `NaN`! - -#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct Constant<'tcx> { - pub span: Span, - - /// Optional user-given type: for something like - /// `collect::>`, this would be present and would - /// indicate that `Vec<_>` was explicitly specified. - /// - /// Needed for NLL to impose user-given type constraints. - pub user_ty: Option, - - pub literal: ConstantKind<'tcx>, -} #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)] #[derive(TypeFoldable, TypeVisitable)] -pub enum ConstantKind<'tcx> { +pub enum Const<'tcx> { /// This constant came from the type system. /// /// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`; @@ -212,46 +191,27 @@ pub enum ConstantKind<'tcx> { Val(ConstValue<'tcx>, Ty<'tcx>), } -impl<'tcx> Constant<'tcx> { - pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option { - match self.literal.try_to_scalar() { - Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) { - GlobalAlloc::Static(def_id) => { - assert!(!tcx.is_thread_local_static(def_id)); - Some(def_id) - } - _ => None, - }, - _ => None, - } - } - #[inline] - pub fn ty(&self) -> Ty<'tcx> { - self.literal.ty() - } -} - -impl<'tcx> ConstantKind<'tcx> { +impl<'tcx> Const<'tcx> { #[inline(always)] pub fn ty(&self) -> Ty<'tcx> { match self { - ConstantKind::Ty(c) => c.ty(), - ConstantKind::Val(_, ty) | ConstantKind::Unevaluated(_, ty) => *ty, + Const::Ty(c) => c.ty(), + Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty, } } #[inline] pub fn try_to_scalar(self) -> Option { match self { - ConstantKind::Ty(c) => match c.kind() { + Const::Ty(c) => match c.kind() { ty::ConstKind::Value(valtree) => match valtree { ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)), ty::ValTree::Branch(_) => None, }, _ => None, }, - ConstantKind::Val(val, _) => val.try_to_scalar(), - ConstantKind::Unevaluated(..) => None, + Const::Val(val, _) => val.try_to_scalar(), + Const::Unevaluated(..) => None, } } @@ -278,17 +238,17 @@ impl<'tcx> ConstantKind<'tcx> { span: Option, ) -> Result, ErrorHandled> { match self { - ConstantKind::Ty(c) => { + Const::Ty(c) => { // We want to consistently have a "clean" value for type system constants (i.e., no // data hidden in the padding), so we always go through a valtree here. let val = c.eval(tcx, param_env, span)?; Ok(tcx.valtree_to_const_val((self.ty(), val))) } - ConstantKind::Unevaluated(uneval, _) => { + Const::Unevaluated(uneval, _) => { // FIXME: We might want to have a `try_eval`-like function on `Unevaluated` tcx.const_eval_resolve(param_env, uneval, span) } - ConstantKind::Val(val, _) => Ok(val), + Const::Val(val, _) => Ok(val), } } @@ -402,7 +362,7 @@ impl<'tcx> ConstantKind<'tcx> { Self::Val(val, ty) } - /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly + /// Literals are converted to `Const::Val`, const generic parameters are eagerly /// converted to a constant, everything else becomes `Unevaluated`. #[instrument(skip(tcx), level = "debug", ret)] pub fn from_anon_const( @@ -538,29 +498,13 @@ impl<'tcx> UnevaluatedConst<'tcx> { } } -impl<'tcx> Debug for Constant<'tcx> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - write!(fmt, "{self}") - } -} - -impl<'tcx> Display for Constant<'tcx> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - match self.ty().kind() { - ty::FnDef(..) => {} - _ => write!(fmt, "const ")?, - } - Display::fmt(&self.literal, fmt) - } -} - -impl<'tcx> Display for ConstantKind<'tcx> { +impl<'tcx> Display for Const<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { match *self { - ConstantKind::Ty(c) => pretty_print_const(c, fmt, true), - ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt), + Const::Ty(c) => pretty_print_const(c, fmt, true), + Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt), // FIXME(valtrees): Correctly print mir constants. - ConstantKind::Unevaluated(..) => { + Const::Unevaluated(..) => { fmt.write_str("_")?; Ok(()) } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 87180b56baa2..0bb1c66da0cb 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -318,7 +318,7 @@ pub struct Body<'tcx> { /// Constants that are required to evaluate successfully for this MIR to be well-formed. /// We hold in this field all the constants we are not able to evaluate yet. - pub required_consts: Vec>, + pub required_consts: Vec>, /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check. /// @@ -585,12 +585,12 @@ impl<'tcx> Body<'tcx> { &self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - normalize_const: impl Fn(ConstantKind<'tcx>) -> Result, ErrorHandled>, + normalize_const: impl Fn(Const<'tcx>) -> Result, ErrorHandled>, ) -> Result<(), ErrorHandled> { // For now, the only thing we have to check is is to ensure that all the constants used in // the body successfully evaluate. for &const_ in &self.required_consts { - let c = normalize_const(const_.literal)?; + let c = normalize_const(const_.const_)?; c.eval(tcx, param_env, Some(const_.span))?; } @@ -1096,7 +1096,7 @@ impl<'tcx> LocalDecl<'tcx> { pub enum VarDebugInfoContents<'tcx> { /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`. Place(Place<'tcx>), - Const(Constant<'tcx>), + Const(ConstOperand<'tcx>), } impl<'tcx> Debug for VarDebugInfoContents<'tcx> { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 632f159a7a88..cc2a5aa62c8c 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -696,6 +696,17 @@ impl Debug for Statement<'_> { } } +impl Display for NonDivergingIntrinsic<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Assume(op) => write!(f, "assume({op:?})"), + Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { + write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})") + } + } + } +} + impl<'tcx> Debug for TerminatorKind<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { self.fmt_head(fmt)?; @@ -1058,6 +1069,22 @@ impl<'tcx> Debug for Operand<'tcx> { } } +impl<'tcx> Debug for ConstOperand<'tcx> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + write!(fmt, "{self}") + } +} + +impl<'tcx> Display for ConstOperand<'tcx> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + match self.ty().kind() { + ty::FnDef(..) => {} + _ => write!(fmt, "const ")?, + } + Display::fmt(&self.const_, fmt) + } +} + impl Debug for Place<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { self.as_ref().fmt(fmt) @@ -1184,10 +1211,10 @@ fn use_verbose(ty: Ty<'_>, fn_def: bool) -> bool { } impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { - fn visit_constant(&mut self, constant: &Constant<'tcx>, _location: Location) { - let Constant { span, user_ty, literal } = constant; - if use_verbose(literal.ty(), true) { - self.push("mir::Constant"); + fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _location: Location) { + let ConstOperand { span, user_ty, const_ } = constant; + if use_verbose(const_.ty(), true) { + self.push("mir::ConstOperand"); self.push(&format!( "+ span: {}", self.tcx.sess.source_map().span_to_embeddable_string(*span) @@ -1209,8 +1236,8 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { ty::ValTree::Branch(_) => "Branch(..)".to_string(), }; - let val = match literal { - ConstantKind::Ty(ct) => match ct.kind() { + let val = match const_ { + Const::Ty(ct) => match ct.kind() { ty::ConstKind::Param(p) => format!("ty::Param({p})"), ty::ConstKind::Unevaluated(uv) => { format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,) @@ -1222,9 +1249,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { ty::ConstKind::Placeholder(_) | ty::ConstKind::Infer(_) | ty::ConstKind::Expr(_) - | ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", literal), + | ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", const_), }, - ConstantKind::Unevaluated(uv, _) => { + Const::Unevaluated(uv, _) => { format!( "Unevaluated({}, {:?}, {:?})", self.tcx.def_path_str(uv.def), @@ -1232,13 +1259,13 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { uv.promoted, ) } - ConstantKind::Val(val, ty) => format!("Value({})", fmt_val(*val, *ty)), + Const::Val(val, ty) => format!("Value({})", fmt_val(*val, *ty)), }; // This reflects what `Const` looked liked before `val` was renamed // as `kind`. We print it like this to avoid having to update // expected output in a lot of tests. - self.push(&format!("+ literal: Const {{ ty: {}, val: {} }}", literal.ty(), val)); + self.push(&format!("+ const_: Const {{ ty: {}, val: {} }}", const_.ty(), val)); } } @@ -1312,10 +1339,10 @@ pub fn write_allocations<'tcx>( struct CollectAllocIds(BTreeSet); impl<'tcx> Visitor<'tcx> for CollectAllocIds { - fn visit_constant(&mut self, c: &Constant<'tcx>, _: Location) { - match c.literal { - ConstantKind::Ty(_) | ConstantKind::Unevaluated(..) => {} - ConstantKind::Val(val, _) => { + fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) { + match c.const_ { + Const::Ty(_) | Const::Unevaluated(..) => {} + Const::Val(val, _) => { self.0.extend(alloc_ids_from_const_val(val)); } } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 25534f469604..5ac108bc8290 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -1,5 +1,5 @@ /// Functionality for statements, operands, places, and things that appear in them. -use super::*; +use super::{interpret::GlobalAlloc, *}; /////////////////////////////////////////////////////////////////////////// // Statements @@ -302,10 +302,10 @@ impl<'tcx> Operand<'tcx> { span: Span, ) -> Self { let ty = Ty::new_fn_def(tcx, def_id, args); - Operand::Constant(Box::new(Constant { + Operand::Constant(Box::new(ConstOperand { span, user_ty: None, - literal: ConstantKind::Val(ConstValue::ZeroSized, ty), + const_: Const::Val(ConstValue::ZeroSized, ty), })) } @@ -333,10 +333,10 @@ impl<'tcx> Operand<'tcx> { }; scalar_size == type_size }); - Operand::Constant(Box::new(Constant { + Operand::Constant(Box::new(ConstOperand { span, user_ty: None, - literal: ConstantKind::Val(ConstValue::Scalar(val), ty), + const_: Const::Val(ConstValue::Scalar(val), ty), })) } @@ -356,9 +356,9 @@ impl<'tcx> Operand<'tcx> { } } - /// Returns the `Constant` that is the target of this `Operand`, or `None` if this `Operand` is a + /// Returns the `ConstOperand` that is the target of this `Operand`, or `None` if this `Operand` is a /// place. - pub fn constant(&self) -> Option<&Constant<'tcx>> { + pub fn constant(&self) -> Option<&ConstOperand<'tcx>> { match self { Operand::Constant(x) => Some(&**x), Operand::Copy(_) | Operand::Move(_) => None, @@ -370,11 +370,31 @@ impl<'tcx> Operand<'tcx> { /// While this is unlikely in general, it's the normal case of what you'll /// find as the `func` in a [`TerminatorKind::Call`]. pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> { - let const_ty = self.constant()?.literal.ty(); + let const_ty = self.constant()?.const_.ty(); if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None } } } +impl<'tcx> ConstOperand<'tcx> { + pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option { + match self.const_.try_to_scalar() { + Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) { + GlobalAlloc::Static(def_id) => { + assert!(!tcx.is_thread_local_static(def_id)); + Some(def_id) + } + _ => None, + }, + _ => None, + } + } + + #[inline] + pub fn ty(&self) -> Ty<'tcx> { + self.const_.ty() + } +} + /////////////////////////////////////////////////////////////////////////// /// Rvalues diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index f99084d0eb7a..8f651b2a2db4 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -3,7 +3,7 @@ //! This is in a dedicated file so that changes to this file can be reviewed more carefully. //! The intention is that this file only contains datatype declarations, no code. -use super::{BasicBlock, Constant, Local, UserTypeProjection}; +use super::{BasicBlock, Const, Local, UserTypeProjection}; use crate::mir::coverage::{CodeRegion, CoverageKind}; use crate::traits::Reveal; @@ -439,17 +439,6 @@ pub enum NonDivergingIntrinsic<'tcx> { CopyNonOverlapping(CopyNonOverlapping<'tcx>), } -impl std::fmt::Display for NonDivergingIntrinsic<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Assume(op) => write!(f, "assume({op:?})"), - Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { - write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})") - } - } - } -} - /// Describes what kind of retag is to be performed. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] @@ -913,10 +902,10 @@ pub enum InlineAsmOperand<'tcx> { out_place: Option>, }, Const { - value: Box>, + value: Box>, }, SymFn { - value: Box>, + value: Box>, }, SymStatic { def_id: DefId, @@ -1136,7 +1125,22 @@ pub enum Operand<'tcx> { Move(Place<'tcx>), /// Constants are already semantically values, and remain unchanged. - Constant(Box>), + Constant(Box>), +} + +#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub struct ConstOperand<'tcx> { + pub span: Span, + + /// Optional user-given type: for something like + /// `collect::>`, this would be present and would + /// indicate that `Vec<_>` was explicitly specified. + /// + /// Needed for NLL to impose user-given type constraints. + pub user_ty: Option, + + pub const_: Const<'tcx>, } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index f79697936d28..01c04f638905 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -227,7 +227,7 @@ impl<'tcx> Operand<'tcx> { { match self { &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, - Operand::Constant(c) => c.literal.ty(), + Operand::Constant(c) => c.const_.ty(), } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 61244b942893..51ec6da1ac8e 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -186,7 +186,7 @@ macro_rules! make_mir_visitor { fn visit_constant( &mut self, - constant: & $($mutability)? Constant<'tcx>, + constant: & $($mutability)? ConstOperand<'tcx>, location: Location, ) { self.super_constant(constant, location); @@ -870,20 +870,20 @@ macro_rules! make_mir_visitor { fn super_constant( &mut self, - constant: & $($mutability)? Constant<'tcx>, + constant: & $($mutability)? ConstOperand<'tcx>, location: Location ) { - let Constant { + let ConstOperand { span, user_ty: _, // no visit method for this - literal, + const_, } = constant; self.visit_span($(& $mutability)? *span); - match literal { - ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location), - ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), - ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), + match const_ { + Const::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location), + Const::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), + Const::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 247fcd20c6ca..d41b38a8b4bc 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -116,9 +116,8 @@ impl EraseType for Result, mir::interpret::LitToConstError> { type Result = [u8; size_of::, mir::interpret::LitToConstError>>()]; } -impl EraseType for Result, mir::interpret::LitToConstError> { - type Result = - [u8; size_of::, mir::interpret::LitToConstError>>()]; +impl EraseType for Result, mir::interpret::LitToConstError> { + type Result = [u8; size_of::, mir::interpret::LitToConstError>>()]; } impl EraseType for Result, mir::interpret::ErrorHandled> { @@ -311,7 +310,7 @@ macro_rules! tcx_lifetime { tcx_lifetime! { rustc_middle::hir::Owner, rustc_middle::middle::exported_symbols::ExportedSymbol, - rustc_middle::mir::ConstantKind, + rustc_middle::mir::Const, rustc_middle::mir::DestructuredConstant, rustc_middle::mir::ConstAlloc, rustc_middle::mir::ConstValue, diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index af4c57e702f4..b1f837968627 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -416,7 +416,7 @@ impl<'tcx> Key for GenericArg<'tcx> { } } -impl<'tcx> Key for mir::ConstantKind<'tcx> { +impl<'tcx> Key for mir::Const<'tcx> { type CacheSelector = DefaultCacheSelector; fn default_span(&self, _: TyCtxt<'_>) -> Span { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b5529568ff2d..0241820ab722 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1101,7 +1101,7 @@ rustc_queries! { desc { "destructuring type level constant"} } - /// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index + /// Tries to destructure an `mir::Const` ADT or array into its variant index /// and its field values. This should only be used for pretty printing. query try_destructure_mir_constant_for_diagnostics( key: (mir::ConstValue<'tcx>, Ty<'tcx>) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index ebc1c11902bc..8c39614903cb 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -563,11 +563,11 @@ pub enum InlineAsmOperand<'tcx> { out_expr: Option, }, Const { - value: mir::ConstantKind<'tcx>, + value: mir::Const<'tcx>, span: Span, }, SymFn { - value: mir::ConstantKind<'tcx>, + value: mir::Const<'tcx>, span: Span, }, SymStatic { @@ -739,7 +739,7 @@ pub enum PatKind<'tcx> { /// * Opaque constants, that must not be matched structurally. So anything that does not derive /// `PartialEq` and `Eq`. Constant { - value: mir::ConstantKind<'tcx>, + value: mir::Const<'tcx>, }, Range(Box>), @@ -769,8 +769,8 @@ pub enum PatKind<'tcx> { #[derive(Clone, Debug, PartialEq, HashStable)] pub struct PatRange<'tcx> { - pub lo: mir::ConstantKind<'tcx>, - pub hi: mir::ConstantKind<'tcx>, + pub lo: mir::Const<'tcx>, + pub hi: mir::Const<'tcx>, pub end: RangeEnd, } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 681400dbb948..b84e15688848 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -26,13 +26,13 @@ pub trait Visitor<'a, 'tcx: 'a>: Sized { walk_pat(self, pat); } - // Note: We don't have visitors for `ty::Const` and `mir::ConstantKind` + // Note: We don't have visitors for `ty::Const` and `mir::Const` // (even though these types occur in THIR) for consistency and to reduce confusion, // since the lazy creation of constants during thir construction causes most - // 'constants' to not be of type `ty::Const` or `mir::ConstantKind` at that + // 'constants' to not be of type `ty::Const` or `mir::Const` at that // stage (they are mostly still identified by `DefId` or `hir::Lit`, see // the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`). - // You have to manually visit `ty::Const` and `mir::ConstantKind` through the + // You have to manually visit `ty::Const` and `mir::Const` through the // other `visit*` functions. } diff --git a/compiler/rustc_middle/src/util/find_self_call.rs b/compiler/rustc_middle/src/util/find_self_call.rs index 1b845334c49b..9f1e4ac11c23 100644 --- a/compiler/rustc_middle/src/util/find_self_call.rs +++ b/compiler/rustc_middle/src/util/find_self_call.rs @@ -17,8 +17,8 @@ pub fn find_self_call<'tcx>( &body[block].terminator { debug!("find_self_call: func={:?}", func); - if let Operand::Constant(box Constant { literal, .. }) = func { - if let ty::FnDef(def_id, fn_args) = *literal.ty().kind() { + if let Operand::Constant(box ConstOperand { const_, .. }) = func { + if let ty::FnDef(def_id, fn_args) = *const_.ty().kind() { if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = tcx.opt_associated_item(def_id) { diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs index 4f1623b4c6a7..fddcf9de7c7c 100644 --- a/compiler/rustc_mir_build/src/build/cfg.rs +++ b/compiler/rustc_mir_build/src/build/cfg.rs @@ -49,7 +49,7 @@ impl<'tcx> CFG<'tcx> { block: BasicBlock, source_info: SourceInfo, temp: Place<'tcx>, - constant: Constant<'tcx>, + constant: ConstOperand<'tcx>, ) { self.push_assign( block, @@ -70,10 +70,10 @@ impl<'tcx> CFG<'tcx> { block, source_info, place, - Rvalue::Use(Operand::Constant(Box::new(Constant { + Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: source_info.span, user_ty: None, - literal: ConstantKind::zero_sized(tcx.types.unit), + const_: Const::zero_sized(tcx.types.unit), }))), ); } diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 05f135b01f4a..fd2c57a0a6f1 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -283,12 +283,12 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { ExprKind::StaticRef { alloc_id, ty, .. } => { let const_val = ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx)); - let literal = ConstantKind::Val(const_val, *ty); + let const_ = Const::Val(const_val, *ty); - Ok(Operand::Constant(Box::new(Constant { + Ok(Operand::Constant(Box::new(ConstOperand { span: expr.span, user_ty: None, - literal + const_ }))) }, ) @@ -301,7 +301,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { | ExprKind::NonHirLiteral { .. } | ExprKind::ConstBlock { .. } => Ok({ let value = as_constant_inner(expr, |_| None, self.tcx); - value.literal.eval_bits(self.tcx, self.param_env) + value.const_.eval_bits(self.tcx, self.param_env) }), ) } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 22712fd3df08..e1f0dc67ae5c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -15,7 +15,7 @@ use rustc_target::abi::Size; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a compile-time constant. Assumes that /// `expr` is a valid compile-time constant! - pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> { + pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> ConstOperand<'tcx> { let this = self; let tcx = this.tcx; let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; @@ -42,62 +42,62 @@ pub fn as_constant_inner<'tcx>( expr: &Expr<'tcx>, push_cuta: impl FnMut(&Box>) -> Option, tcx: TyCtxt<'tcx>, -) -> Constant<'tcx> { +) -> ConstOperand<'tcx> { let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; match *kind { ExprKind::Literal { lit, neg } => { - let literal = - match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) { - Ok(c) => c, - Err(LitToConstError::Reported(guar)) => { - ConstantKind::Ty(ty::Const::new_error(tcx, guar, ty)) - } - Err(LitToConstError::TypeError) => { - bug!("encountered type error in `lit_to_mir_constant`") - } - }; + let const_ = match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) + { + Ok(c) => c, + Err(LitToConstError::Reported(guar)) => { + Const::Ty(ty::Const::new_error(tcx, guar, ty)) + } + Err(LitToConstError::TypeError) => { + bug!("encountered type error in `lit_to_mir_constant`") + } + }; - Constant { span, user_ty: None, literal } + ConstOperand { span, user_ty: None, const_ } } ExprKind::NonHirLiteral { lit, ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); - let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty); + let const_ = Const::Val(ConstValue::Scalar(Scalar::Int(lit)), ty); - Constant { span, user_ty, literal } + ConstOperand { span, user_ty, const_ } } ExprKind::ZstLiteral { ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); - let literal = ConstantKind::Val(ConstValue::ZeroSized, ty); + let const_ = Const::Val(ConstValue::ZeroSized, ty); - Constant { span, user_ty, literal } + ConstOperand { span, user_ty, const_ } } ExprKind::NamedConst { def_id, args, ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); let uneval = mir::UnevaluatedConst::new(def_id, args); - let literal = ConstantKind::Unevaluated(uneval, ty); + let const_ = Const::Unevaluated(uneval, ty); - Constant { user_ty, span, literal } + ConstOperand { user_ty, span, const_ } } ExprKind::ConstParam { param, def_id: _ } => { let const_param = ty::Const::new_param(tcx, param, expr.ty); - let literal = ConstantKind::Ty(const_param); + let const_ = Const::Ty(const_param); - Constant { user_ty: None, span, literal } + ConstOperand { user_ty: None, span, const_ } } ExprKind::ConstBlock { did: def_id, args } => { let uneval = mir::UnevaluatedConst::new(def_id, args); - let literal = ConstantKind::Unevaluated(uneval, ty); + let const_ = Const::Unevaluated(uneval, ty); - Constant { user_ty: None, span, literal } + ConstOperand { user_ty: None, span, const_ } } ExprKind::StaticRef { alloc_id, ty, .. } => { let const_val = ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &tcx)); - let literal = ConstantKind::Val(const_val, ty); + let const_ = Const::Val(const_val, ty); - Constant { span, user_ty: None, literal } + ConstOperand { span, user_ty: None, const_ } } _ => span_bug!(span, "expression is not a valid constant {:?}", kind), } @@ -107,7 +107,7 @@ pub fn as_constant_inner<'tcx>( fn lit_to_mir_constant<'tcx>( tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>, -) -> Result, LitToConstError> { +) -> Result, LitToConstError> { let LitToConstInput { lit, ty, neg } = lit_input; let trunc = |n| { let param_ty = ty::ParamEnv::reveal_all().and(ty); @@ -173,5 +173,5 @@ fn lit_to_mir_constant<'tcx>( _ => return Err(LitToConstError::TypeError), }; - Ok(ConstantKind::Val(value, ty)) + Ok(Const::Val(value, ty)) } 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 3220a184d49b..d4089eef4833 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -249,7 +249,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> { let range_val = - ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty)); + Const::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_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( @@ -485,10 +485,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { block = unpack!(this.stmt_expr(block, expr, None)); - block.and(Rvalue::Use(Operand::Constant(Box::new(Constant { + block.and(Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: expr_span, user_ty: None, - literal: ConstantKind::zero_sized(this.tcx.types.unit), + const_: Const::zero_sized(this.tcx.types.unit), })))) } @@ -817,7 +817,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { let param_ty = ty::ParamEnv::empty().and(ty); let size = self.tcx.layout_of(param_ty).unwrap().size; - let literal = ConstantKind::from_bits(self.tcx, size.unsigned_int_max(), param_ty); + let literal = Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty); self.literal_operand(span, literal) } @@ -828,7 +828,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let param_ty = ty::ParamEnv::empty().and(ty); let bits = self.tcx.layout_of(param_ty).unwrap().size.bits(); let n = 1 << (bits - 1); - let literal = ConstantKind::from_bits(self.tcx, n, param_ty); + let literal = Const::from_bits(self.tcx, n, param_ty); self.literal_operand(span, literal) } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 1e0a47ead8c5..a4de42d45c99 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -114,10 +114,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { true_block, source_info, destination, - Constant { + ConstOperand { span: expr_span, user_ty: None, - literal: ConstantKind::from_bool(this.tcx, true), + const_: Const::from_bool(this.tcx, true), }, ); @@ -125,10 +125,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { false_block, source_info, destination, - Constant { + ConstOperand { span: expr_span, user_ty: None, - literal: ConstantKind::from_bool(this.tcx, false), + const_: Const::from_bool(this.tcx, false), }, ); @@ -186,10 +186,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { short_circuit, source_info, destination, - Constant { + ConstOperand { span: expr.span, user_ty: None, - literal: ConstantKind::from_bool(this.tcx, constant), + const_: Const::from_bool(this.tcx, constant), }, ); let rhs = unpack!(this.expr_into_dest(destination, continuation, &this.thir[rhs])); @@ -433,12 +433,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } thir::InlineAsmOperand::Const { value, span } => { mir::InlineAsmOperand::Const { - value: Box::new(Constant { span, user_ty: None, literal: value }), + value: Box::new(ConstOperand { + span, + user_ty: None, + const_: value, + }), } } thir::InlineAsmOperand::SymFn { value, span } => { mir::InlineAsmOperand::SymFn { - value: Box::new(Constant { span, user_ty: None, literal: value }), + value: Box::new(ConstOperand { + span, + user_ty: None, + const_: value, + }), } } thir::InlineAsmOperand::SymStatic { def_id } => { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 1a5d8c63f93e..921a5ca1175c 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1005,13 +1005,13 @@ enum TestKind<'tcx> { /// /// For `bool` we always generate two edges, one for `true` and one for /// `false`. - options: FxIndexMap, u128>, + options: FxIndexMap, u128>, }, /// Test for equality with value, possibly after an unsizing coercion to /// `ty`, Eq { - value: ConstantKind<'tcx>, + value: Const<'tcx>, // Integer types are handled by `SwitchInt`, and constants with ADT // types are converted back into patterns, so this can only be `&str`, // `&[T]`, `f32` or `f64`. diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 0fdc0a82da56..795d1db8eecd 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -85,7 +85,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, test_place: &PlaceBuilder<'tcx>, candidate: &Candidate<'pat, 'tcx>, - options: &mut FxIndexMap, u128>, + options: &mut FxIndexMap, u128>, ) -> bool { let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place) else { @@ -252,10 +252,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, TerminatorKind::Call { - func: Operand::Constant(Box::new(Constant { + func: Operand::Constant(Box::new(ConstOperand { span: test.span, user_ty: None, - literal: method, + const_: method, })), args: vec![Operand::Move(ref_string)], destination: ref_str, @@ -385,7 +385,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, make_target_blocks: impl FnOnce(&mut Self) -> Vec, source_info: SourceInfo, - value: ConstantKind<'tcx>, + value: Const<'tcx>, mut val: Place<'tcx>, mut ty: Ty<'tcx>, ) { @@ -482,7 +482,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, TerminatorKind::Call { - func: Operand::Constant(Box::new(Constant { + func: Operand::Constant(Box::new(ConstOperand { span: source_info.span, // FIXME(#54571): This constant comes from user input (a @@ -491,7 +491,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Need to experiment. user_ty: None, - literal: method, + const_: method, })), args: vec![Operand::Copy(val), expect], destination: eq_result, @@ -797,11 +797,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern) } - fn const_range_contains( - &self, - range: &PatRange<'tcx>, - value: ConstantKind<'tcx>, - ) -> Option { + fn const_range_contains(&self, range: &PatRange<'tcx>, value: Const<'tcx>) -> Option { use std::cmp::Ordering::*; // For performance, it's important to only do the second @@ -818,7 +814,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn values_not_contained_in_range( &self, range: &PatRange<'tcx>, - options: &FxIndexMap, u128>, + options: &FxIndexMap, u128>, ) -> Option { for &val in options.keys() { if self.const_range_contains(range, val)? { @@ -863,7 +859,7 @@ fn trait_method<'tcx>( trait_def_id: DefId, method_name: Symbol, args: impl IntoIterator>>, -) -> ConstantKind<'tcx> { +) -> Const<'tcx> { // The unhygienic comparison here is acceptable because this is only // used on known traits. let item = tcx @@ -874,5 +870,5 @@ fn trait_method<'tcx>( let method_ty = Ty::new_fn_def(tcx, item.def_id, args); - ConstantKind::zero_sized(method_ty) + Const::zero_sized(method_ty) } diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index 90d78658f968..c96e99ef0e7e 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -25,19 +25,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Convenience function for creating a literal operand, one /// without any user type annotation. - pub(crate) fn literal_operand( - &mut self, - span: Span, - literal: ConstantKind<'tcx>, - ) -> Operand<'tcx> { - let constant = Box::new(Constant { span, user_ty: None, literal }); + pub(crate) fn literal_operand(&mut self, span: Span, const_: Const<'tcx>) -> Operand<'tcx> { + let constant = Box::new(ConstOperand { span, user_ty: None, const_ }); Operand::Constant(constant) } /// Returns a zero literal operand for the appropriate type, works for /// bool, char and integers. pub(crate) fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { - let literal = ConstantKind::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty)); + let literal = Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty)); self.literal_operand(span, literal) } @@ -54,10 +50,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, temp, - Constant { + ConstOperand { span: source_info.span, user_ty: None, - literal: ConstantKind::from_usize(self.tcx, value), + const_: Const::from_usize(self.tcx, value), }, ); temp diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 18b0e9a643e8..16a85d427617 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -647,21 +647,15 @@ impl<'tcx> Cx<'tcx> { out_expr: out_expr.map(|expr| self.mirror_expr(expr)), }, hir::InlineAsmOperand::Const { ref anon_const } => { - let value = mir::ConstantKind::from_anon_const( - tcx, - anon_const.def_id, - self.param_env, - ); + let value = + mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::Const { value, span } } hir::InlineAsmOperand::SymFn { ref anon_const } => { - let value = mir::ConstantKind::from_anon_const( - tcx, - anon_const.def_id, - self.param_env, - ); + let value = + mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::SymFn { value, span } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 1376344cfdae..00d9fe72cfcb 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -27,7 +27,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self), ret)] pub(super) fn const_to_pat( &self, - cv: mir::ConstantKind<'tcx>, + cv: mir::Const<'tcx>, id: hir::HirId, span: Span, check_body_for_struct_match_violation: Option, @@ -104,7 +104,7 @@ impl<'tcx> ConstToPat<'tcx> { fn to_pat( &mut self, - cv: mir::ConstantKind<'tcx>, + cv: mir::Const<'tcx>, check_body_for_struct_match_violation: Option, ) -> Box> { trace!(self.treat_byte_string_as_slice); @@ -124,7 +124,7 @@ impl<'tcx> ConstToPat<'tcx> { debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation); let inlined_const_as_pat = match cv { - mir::ConstantKind::Ty(c) => match c.kind() { + mir::Const::Ty(c) => match c.kind() { ty::ConstKind::Param(_) | ty::ConstKind::Infer(_) | ty::ConstKind::Bound(_, _) @@ -144,10 +144,10 @@ impl<'tcx> ConstToPat<'tcx> { }) }), }, - mir::ConstantKind::Unevaluated(_, _) => { + mir::Const::Unevaluated(_, _) => { span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}") } - mir::ConstantKind::Val(_, _) => Box::new(Pat { + mir::Const::Val(_, _) => Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Constant { value: cv }, @@ -385,9 +385,9 @@ impl<'tcx> ConstToPat<'tcx> { ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // `&str` is represented as a valtree, let's keep using this // optimization for now. - ty::Str => PatKind::Constant { - value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)), - }, + ty::Str => { + PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } + } // Backwards compatibility hack: support references to non-structural types, // but hard error if we aren't behind a double reference. We could just use // the fallback code path below, but that would allow *more* of this fishy @@ -445,9 +445,9 @@ impl<'tcx> ConstToPat<'tcx> { } } }, - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => PatKind::Constant { - value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)), - }, + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => { + PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } + } ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(), _ => { self.saw_const_match_error.set(true); diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index ee7ac91b148b..b79beb1c537a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -137,12 +137,12 @@ impl IntRange { fn from_constant<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - value: mir::ConstantKind<'tcx>, + value: mir::Const<'tcx>, ) -> Option { let ty = value.ty(); let (target_size, bias) = Self::integral_size_and_signed_bias(tcx, ty)?; let val = match value { - mir::ConstantKind::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => { + mir::Const::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => { valtree.unwrap_leaf().to_bits(target_size).ok() }, // This is a more general form of the previous case. @@ -225,8 +225,8 @@ impl IntRange { let (lo, hi) = (lo ^ bias, hi ^ bias); let env = ty::ParamEnv::empty().and(ty); - let lo_const = mir::ConstantKind::from_bits(tcx, lo, env); - let hi_const = mir::ConstantKind::from_bits(tcx, hi, env); + let lo_const = mir::Const::from_bits(tcx, lo, env); + let hi_const = mir::Const::from_bits(tcx, hi, env); let kind = if lo == hi { PatKind::Constant { value: lo_const } @@ -619,9 +619,9 @@ pub(super) enum Constructor<'tcx> { /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). IntRange(IntRange), /// Ranges of floating-point literal values (`2.0..=5.2`). - FloatRange(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>, RangeEnd), + FloatRange(mir::Const<'tcx>, mir::Const<'tcx>, RangeEnd), /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. - Str(mir::ConstantKind<'tcx>), + Str(mir::Const<'tcx>), /// Array and slice patterns. Slice(Slice), /// Constants that must not be matched structurally. They are treated as black diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8f3e1359700b..f1f75c267175 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -20,7 +20,7 @@ use rustc_index::Idx; use rustc_middle::mir::interpret::{ ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar, }; -use rustc_middle::mir::{self, ConstantKind, UserTypeProjection}; +use rustc_middle::mir::{self, Const, UserTypeProjection}; use rustc_middle::mir::{BorrowKind, Mutability}; use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange}; use rustc_middle::ty::CanonicalUserTypeAnnotation; @@ -100,8 +100,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern_range( &mut self, ty: Ty<'tcx>, - lo: mir::ConstantKind<'tcx>, - hi: mir::ConstantKind<'tcx>, + lo: mir::Const<'tcx>, + hi: mir::Const<'tcx>, end: RangeEnd, span: Span, lo_expr: Option<&hir::Expr<'tcx>>, @@ -191,18 +191,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ty: Ty<'tcx>, lo: Option<&PatKind<'tcx>>, hi: Option<&PatKind<'tcx>>, - ) -> Option<(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>)> { + ) -> Option<(mir::Const<'tcx>, mir::Const<'tcx>)> { match (lo, hi) { (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => { Some((*lo, *hi)) } (Some(PatKind::Constant { value: lo }), None) => { let hi = ty.numeric_max_val(self.tcx)?; - Some((*lo, mir::ConstantKind::from_ty_const(hi, self.tcx))) + Some((*lo, mir::Const::from_ty_const(hi, self.tcx))) } (None, Some(PatKind::Constant { value: hi })) => { let lo = ty.numeric_min_val(self.tcx)?; - Some((mir::ConstantKind::from_ty_const(lo, self.tcx), *hi)) + Some((mir::Const::from_ty_const(lo, self.tcx), *hi)) } _ => None, } @@ -525,8 +525,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .tcx .const_eval_global_id_for_typeck(param_env_reveal_all, cid, Some(span)) .map(|val| match val { - Some(valtree) => mir::ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)), - None => mir::ConstantKind::Val( + Some(valtree) => mir::Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), + None => mir::Const::Val( self.tcx .const_eval_global_id(param_env_reveal_all, cid, Some(span)) .expect("const_eval_global_id_for_typeck should have already failed"), @@ -608,7 +608,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; if let Some(lit_input) = lit_input { match tcx.at(expr.span).lit_to_const(lit_input) { - Ok(c) => return self.const_to_pat(ConstantKind::Ty(c), id, span, None).kind, + Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind, // If an error occurred, ignore that it's a literal // and leave reporting the error up to const eval of // the unevaluated constant below. @@ -632,7 +632,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span)) { self.const_to_pat( - ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)), + Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), id, span, None, @@ -641,7 +641,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } else { // If that fails, convert it to an opaque constant pattern. match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) { - Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind, + Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind, Err(ErrorHandled::TooGeneric(_)) => { // If we land here it means the const can't be evaluated because it's `TooGeneric`. self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); @@ -678,7 +678,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; match self.tcx.at(expr.span).lit_to_const(lit_input) { Ok(constant) => { - self.const_to_pat(ConstantKind::Ty(constant), expr.hir_id, lit.span, None).kind + self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind } Err(LitToConstError::Reported(_)) => PatKind::Wild, Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), @@ -838,8 +838,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { #[instrument(skip(tcx), level = "debug")] pub(crate) fn compare_const_vals<'tcx>( tcx: TyCtxt<'tcx>, - a: mir::ConstantKind<'tcx>, - b: mir::ConstantKind<'tcx>, + a: mir::Const<'tcx>, + b: mir::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option { assert_eq!(a.ty(), b.ty()); @@ -855,10 +855,10 @@ pub(crate) fn compare_const_vals<'tcx>( ty::Float(_) | ty::Int(_) => {} // require special handling, see below _ => match (a, b) { ( - mir::ConstantKind::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty), - mir::ConstantKind::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty), + mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty), + mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty), ) => return Some(a.cmp(&b)), - (mir::ConstantKind::Ty(a), mir::ConstantKind::Ty(b)) => { + (mir::Const::Ty(a), mir::Const::Ty(b)) => { return Some(a.kind().cmp(&b.kind())); } _ => {} diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index ad5f83d9e25e..e24685cb90f7 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -973,10 +973,10 @@ where } fn constant_usize(&self, val: u16) -> Operand<'tcx> { - Operand::Constant(Box::new(Constant { + Operand::Constant(Box::new(ConstOperand { span: self.source_info.span, user_ty: None, - literal: ConstantKind::from_usize(self.tcx(), val.into()), + const_: Const::from_usize(self.tcx(), val.into()), })) } diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 775c522b476f..1ebb59b3a637 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -190,7 +190,7 @@ impl PeekCall { if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = &terminator.kind { - if let ty::FnDef(def_id, fn_args) = *func.literal.ty().kind() { + if let ty::FnDef(def_id, fn_args) = *func.const_.ty().kind() { let name = tcx.item_name(def_id); if !tcx.is_intrinsic(def_id) || name != sym::rustc_peek { return None; diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 514146b50301..dd20e5d7430d 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -225,7 +225,7 @@ pub trait ValueAnalysis<'tcx> { fn handle_constant( &self, - constant: &Constant<'tcx>, + constant: &ConstOperand<'tcx>, state: &mut State, ) -> Self::Value { self.super_constant(constant, state) @@ -233,7 +233,7 @@ pub trait ValueAnalysis<'tcx> { fn super_constant( &self, - _constant: &Constant<'tcx>, + _constant: &ConstOperand<'tcx>, _state: &mut State, ) -> Self::Value { Self::Value::TOP diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index fe66a9a09946..28765af20ad3 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -181,13 +181,10 @@ fn insert_alignment_check<'tcx>( // Subtract 1 from the alignment to get the alignment mask let alignment_mask = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - let one = Operand::Constant(Box::new(Constant { + let one = Operand::Constant(Box::new(ConstOperand { span: source_info.span, user_ty: None, - literal: ConstantKind::Val( - ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), - tcx.types.usize, - ), + const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize), })); block_data.statements.push(Statement { source_info, @@ -213,13 +210,10 @@ fn insert_alignment_check<'tcx>( // Check if the alignment bits are all zero let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); - let zero = Operand::Constant(Box::new(Constant { + let zero = Operand::Constant(Box::new(ConstOperand { span: source_info.span, user_ty: None, - literal: ConstantKind::Val( - ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), - tcx.types.usize, - ), + const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize), })); block_data.statements.push(Statement { source_info, diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index d5af321d7263..bacabc62ee40 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -142,9 +142,9 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) { if let Operand::Constant(constant) = op { - let maybe_uneval = match constant.literal { - ConstantKind::Val(..) | ConstantKind::Ty(_) => None, - ConstantKind::Unevaluated(uv, _) => Some(uv), + let maybe_uneval = match constant.const_ { + Const::Val(..) | Const::Ty(_) => None, + Const::Unevaluated(uv, _) => Some(uv), }; if let Some(uv) = maybe_uneval { diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs index f662ce645b08..40cd2825408d 100644 --- a/compiler/rustc_mir_transform/src/const_debuginfo.rs +++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs @@ -4,7 +4,7 @@ use rustc_middle::{ mir::{ visit::{PlaceContext, Visitor}, - Body, Constant, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents, + Body, ConstOperand, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents, }, ty::TyCtxt, }; @@ -45,7 +45,7 @@ struct LocalUseVisitor { local_assignment_locations: IndexVec>, } -fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> { +fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, ConstOperand<'tcx>)> { let mut visitor = LocalUseVisitor { local_mutating_uses: IndexVec::from_elem(0, &body.local_decls), local_assignment_locations: IndexVec::from_elem(None, &body.local_decls), diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index cd3ea9509efd..fd2d37dbea51 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -99,7 +99,7 @@ impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> { debug_assert_eq!(switch_ty, _const.ty()); // We now know that the Switch matches on the const place, and it is statementless // Now find which value in the Switch matches the const value. - let const_value = _const.literal.try_eval_bits(self.tcx, self.param_env)?; + let const_value = _const.const_.try_eval_bits(self.tcx, self.param_env)?; let target_to_use_in_goto = targets.target_for_value(const_value); self.optimizations.push(OptimizationToApply { bb_with_goto: location.block, diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index c6aac2ca2133..12e8b6554ca5 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -525,7 +525,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } - fn replace_with_const(&mut self, place: Place<'tcx>) -> Option> { + fn replace_with_const(&mut self, place: Place<'tcx>) -> Option> { // This will return None if the above `const_prop` invocation only "wrote" a // type whose creation requires no write. E.g. a generator whose initial state // consists solely of uninitialized memory (so it doesn't capture any locals). @@ -541,7 +541,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let Right(imm) = imm else { return None }; match *imm { Immediate::Scalar(scalar) if scalar.try_to_int().is_ok() => { - Some(ConstantKind::from_scalar(self.tcx, scalar, value.layout.ty)) + Some(Const::from_scalar(self.tcx, scalar, value.layout.ty)) } Immediate::ScalarPair(l, r) if l.try_to_int().is_ok() && r.try_to_int().is_ok() => { let alloc_id = self @@ -551,7 +551,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { }) .ok()?; - Some(ConstantKind::Val( + Some(Const::Val( ConstValue::Indirect { alloc_id, offset: Size::ZERO }, value.layout.ty, )) @@ -731,7 +731,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { if let Some(()) = self.eval_rvalue_with_identities(rvalue, *place) { // If this was already an evaluated constant, keep it. if let Rvalue::Use(Operand::Constant(c)) = rvalue - && let ConstantKind::Val(..) = c.literal + && let Const::Val(..) = c.const_ { trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); } else if let Some(operand) = self.replace_with_const(*place) { diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index fb33b3b49d30..8b124fb35132 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -281,7 +281,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } /// Returns the value, if any, of evaluating `c`. - fn eval_constant(&mut self, c: &Constant<'tcx>, location: Location) -> Option> { + fn eval_constant(&mut self, c: &ConstOperand<'tcx>, location: Location) -> Option> { // FIXME we need to revisit this for #67176 if c.has_param() { return None; @@ -293,7 +293,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // that the `RevealAll` pass has happened and that the body's consts // are normalized, so any call to resolve before that needs to be // manually normalized. - let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.literal).ok()?; + let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.const_).ok()?; self.use_ecx(location, |this| this.ecx.eval_mir_constant(&val, Some(c.span), None)) } @@ -580,7 +580,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { self.super_operand(operand, location); } - fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { trace!("visit_constant: {:?}", constant); self.super_constant(constant, location); self.eval_constant(constant, location); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index cf827c988942..0401593d0481 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -206,7 +206,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { && let operand_ty = operand.ty(self.local_decls, self.tcx) && let Some(operand_ty) = operand_ty.builtin_deref(true) && let ty::Array(_, len) = operand_ty.ty.kind() - && let Some(len) = ConstantKind::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env) + && let Some(len) = Const::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env) { state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map()); } @@ -224,7 +224,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { Rvalue::Len(place) => { let place_ty = place.ty(self.local_decls, self.tcx); if let ty::Array(_, len) = place_ty.ty.kind() { - ConstantKind::Ty(*len) + Const::Ty(*len) .try_eval_scalar(self.tcx, self.param_env) .map_or(FlatSet::Top, FlatSet::Elem) } else if let [ProjectionElem::Deref] = place.projection[..] { @@ -295,11 +295,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { fn handle_constant( &self, - constant: &Constant<'tcx>, + constant: &ConstOperand<'tcx>, _state: &mut State, ) -> Self::Value { constant - .literal + .const_ .try_eval_scalar(self.tcx, self.param_env) .map_or(FlatSet::Top, FlatSet::Elem) } @@ -360,7 +360,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Operand::Constant(box constant) => { - if let Ok(constant) = self.ecx.eval_mir_constant(&constant.literal, None, None) { + if let Ok(constant) = self.ecx.eval_mir_constant(&constant.const_, None, None) { self.assign_constant(state, place, constant, &[]); } } @@ -518,10 +518,10 @@ pub(crate) struct Patch<'tcx> { /// For a given MIR location, this stores the values of the operands used by that location. In /// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are /// properly captured. (This may become UB soon, but it is currently emitted even by safe code.) - pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), ConstantKind<'tcx>>, + pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), Const<'tcx>>, /// Stores the assigned values for assignments where the Rvalue is constant. - pub(crate) assignments: FxHashMap>, + pub(crate) assignments: FxHashMap>, } impl<'tcx> Patch<'tcx> { @@ -529,8 +529,8 @@ impl<'tcx> Patch<'tcx> { Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() } } - fn make_operand(&self, literal: ConstantKind<'tcx>) -> Operand<'tcx> { - Operand::Constant(Box::new(Constant { span: DUMMY_SP, user_ty: None, literal })) + fn make_operand(&self, const_: Const<'tcx>) -> Operand<'tcx> { + Operand::Constant(Box::new(ConstOperand { span: DUMMY_SP, user_ty: None, const_ })) } } @@ -549,12 +549,12 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> { place: Place<'tcx>, state: &State>, map: &Map, - ) -> Option> { + ) -> Option> { let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else { return None; }; let ty = place.ty(self.local_decls, self.patch.tcx).ty; - Some(ConstantKind::Val(ConstValue::Scalar(value.into()), ty)) + Some(Const::Val(ConstValue::Scalar(value.into()), ty)) } } diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs index 909116a77f54..666293cbc307 100644 --- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs +++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs @@ -150,7 +150,7 @@ fn rvalue_hash(hasher: &mut H, rvalue: &Rvalue<'_>) { fn operand_hash(hasher: &mut H, operand: &Operand<'_>) { match operand { - Operand::Constant(box Constant { user_ty: _, literal, span: _ }) => literal.hash(hasher), + Operand::Constant(box ConstOperand { user_ty: _, const_, span: _ }) => const_.hash(hasher), x => x.hash(hasher), }; } @@ -179,9 +179,9 @@ fn rvalue_eq<'tcx>(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool { fn operand_eq<'tcx>(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool { let res = match (lhs, rhs) { ( - Operand::Constant(box Constant { user_ty: _, literal, span: _ }), - Operand::Constant(box Constant { user_ty: _, literal: literal2, span: _ }), - ) => literal == literal2, + Operand::Constant(box ConstOperand { user_ty: _, const_, span: _ }), + Operand::Constant(box ConstOperand { user_ty: _, const_: const2, span: _ }), + ) => const_ == const2, (x, y) => x == y, }; debug!("operand_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 78d7ffb3698a..6a89d0672757 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -402,10 +402,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> { - Rvalue::Use(Operand::Constant(Box::new(Constant { + Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span, user_ty: None, - literal: ConstantKind::from_bool(self.tcx, val), + const_: Const::from_bool(self.tcx, val), }))) } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index eae83448c46f..96c60fdf41b3 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1189,10 +1189,10 @@ fn insert_panic_block<'tcx>( ) -> BasicBlock { let assert_block = BasicBlock::new(body.basic_blocks.len()); let term = TerminatorKind::Assert { - cond: Operand::Constant(Box::new(Constant { + cond: Operand::Constant(Box::new(ConstOperand { span: body.span, user_ty: None, - literal: ConstantKind::from_bool(tcx, false), + const_: Const::from_bool(tcx, false), })), expected: true, msg: Box::new(message), diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 4dc7c3b64444..1d9c89477cba 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -652,11 +652,11 @@ impl<'tcx> Inliner<'tcx> { // `required_consts`, here we may not only have `ConstKind::Unevaluated` // because we are calling `subst_and_normalize_erasing_regions`. caller_body.required_consts.extend( - callee_body.required_consts.iter().copied().filter(|&ct| match ct.literal { - ConstantKind::Ty(_) => { + callee_body.required_consts.iter().copied().filter(|&ct| match ct.const_ { + Const::Ty(_) => { bug!("should never encounter ty::UnevaluatedConst in `required_consts`") } - ConstantKind::Val(..) | ConstantKind::Unevaluated(..) => true, + Const::Val(..) | Const::Unevaluated(..) => true, }), ); } @@ -824,7 +824,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { } } TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => { - let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.literal.ty())); + let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.const_.ty())); self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) { // Don't give intrinsics the extra penalty for calls INSTR_COST diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 6e191b285be9..a6ef2e11aa82 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -104,7 +104,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { fn try_eval_bool(&self, a: &Operand<'_>) -> Option { let a = a.constant()?; - if a.literal.ty().is_bool() { a.literal.try_to_bool() } else { None } + if a.const_.ty().is_bool() { a.const_.try_to_bool() } else { None } } /// Transform "&(*a)" ==> "a". @@ -136,8 +136,8 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { return; } - let literal = ConstantKind::from_ty_const(len, self.tcx); - let constant = Constant { span: source_info.span, literal, user_ty: None }; + let const_ = Const::from_ty_const(len, self.tcx); + let constant = ConstOperand { span: source_info.span, const_, user_ty: None }; *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); } } diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index fc49c9ba348d..4eee45f8d000 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -149,10 +149,10 @@ impl EnumSizeOpt { }; let place = Place::from(size_array_local); - let constant_vals = Constant { + let constant_vals = ConstOperand { span, user_ty: None, - literal: ConstantKind::Val( + const_: Const::Val( ConstValue::Indirect { alloc_id, offset: Size::ZERO }, tmp_ty, ), diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 70d4ea74d1a7..ec82c4c61bd6 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -31,9 +31,9 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_index::IndexVec; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{ - traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, - MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, - Statement, StatementKind, TerminatorKind, START_BLOCK, + traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, + LocalDecl, MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, + SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK, }; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; @@ -149,14 +149,14 @@ fn remap_mir_for_const_eval_select<'tcx>( let terminator = bb.terminator.as_mut().expect("invalid terminator"); match terminator.kind { TerminatorKind::Call { - func: Operand::Constant(box Constant { ref literal, .. }), + func: Operand::Constant(box ConstOperand { ref const_, .. }), ref mut args, destination, target, unwind, fn_span, .. - } if let ty::FnDef(def_id, _) = *literal.ty().kind() + } if let ty::FnDef(def_id, _) = *const_.ty().kind() && tcx.item_name(def_id) == sym::const_eval_select && tcx.is_intrinsic(def_id) => { diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 13277d62bf4c..0d2d764c422a 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -32,10 +32,10 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { source_info: terminator.source_info, kind: StatementKind::Assign(Box::new(( *destination, - Rvalue::Use(Operand::Constant(Box::new(Constant { + Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: terminator.source_info.span, user_ty: None, - literal: ConstantKind::zero_sized(tcx.types.unit), + const_: Const::zero_sized(tcx.types.unit), }))), ))), }); diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index bc29fb8ded16..3dc627b61460 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -98,10 +98,10 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), ) if lhs_f == lhs_s - && f_c.literal.ty().is_bool() - && s_c.literal.ty().is_bool() - && f_c.literal.try_eval_bool(tcx, param_env).is_some() - && s_c.literal.try_eval_bool(tcx, param_env).is_some() => {} + && f_c.const_.ty().is_bool() + && s_c.const_.ty().is_bool() + && f_c.const_.try_eval_bool(tcx, param_env).is_some() + && s_c.const_.try_eval_bool(tcx, param_env).is_some() => {} // Otherwise we cannot optimize. Try another block. _ => continue 'outer, @@ -128,8 +128,8 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))), ) => { // From earlier loop we know that we are dealing with bool constants only: - let f_b = f_c.literal.try_eval_bool(tcx, param_env).unwrap(); - let s_b = s_c.literal.try_eval_bool(tcx, param_env).unwrap(); + let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap(); + let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap(); if f_b == s_b { // Same value in both blocks. Use statement as is. (*f).clone() diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 1b846987d38b..d1a4b26a0466 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -90,10 +90,10 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { && let [PlaceElem::Deref] = &place.projection[..] && let Some(len) = self.slice_lengths[place.local] { - *rvalue = Rvalue::Use(Operand::Constant(Box::new(Constant { + *rvalue = Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: rustc_span::DUMMY_SP, user_ty: None, - literal: ConstantKind::from_ty_const(len, self.tcx), + const_: Const::from_ty_const(len, self.tcx), }))); } self.super_rvalue(rvalue, loc); diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index dcc4cd85cda9..a34d4b027648 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -62,12 +62,12 @@ impl<'tcx> Replacer<'_, 'tcx> { layout.is_zst() } - fn make_zst(&self, ty: Ty<'tcx>) -> Constant<'tcx> { + fn make_zst(&self, ty: Ty<'tcx>) -> ConstOperand<'tcx> { debug_assert!(self.known_to_be_zst(ty)); - Constant { + ConstOperand { span: rustc_span::DUMMY_SP, user_ty: None, - literal: ConstantKind::Val(ConstValue::ZeroSized, ty), + const_: Const::Val(ConstValue::ZeroSized, ty), } } } diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs index 243cb463560e..abde6a47e83a 100644 --- a/compiler/rustc_mir_transform/src/required_consts.rs +++ b/compiler/rustc_mir_transform/src/required_consts.rs @@ -1,27 +1,27 @@ use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Constant, ConstantKind, Location}; +use rustc_middle::mir::{Const, ConstOperand, Location}; use rustc_middle::ty::ConstKind; pub struct RequiredConstsVisitor<'a, 'tcx> { - required_consts: &'a mut Vec>, + required_consts: &'a mut Vec>, } impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { - pub fn new(required_consts: &'a mut Vec>) -> Self { + pub fn new(required_consts: &'a mut Vec>) -> Self { RequiredConstsVisitor { required_consts } } } impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> { - fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) { - let literal = constant.literal; - match literal { - ConstantKind::Ty(c) => match c.kind() { + fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _: Location) { + let const_ = constant.const_; + match const_ { + Const::Ty(c) => match c.kind() { ConstKind::Param(_) | ConstKind::Error(_) | ConstKind::Value(_) => {} _ => bug!("only ConstKind::Param/Value should be encountered here, got {:#?}", c), }, - ConstantKind::Unevaluated(..) => self.required_consts.push(*constant), - ConstantKind::Val(..) => {} + Const::Unevaluated(..) => self.required_consts.push(*constant), + Const::Val(..) => {} } } } diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index 23442f8b97b7..065793348e4c 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -35,12 +35,12 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { } #[inline] - fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _: Location) { + fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, _: Location) { // We have to use `try_normalize_erasing_regions` here, since it's // possible that we visit impossible-to-satisfy where clauses here, // see #91745 - if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.literal) { - constant.literal = c; + if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.const_) { + constant.const_ = c; } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index e1000d969323..e9895d97dfef 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -497,10 +497,10 @@ impl<'tcx> CloneShimBuilder<'tcx> { // `func == Clone::clone(&ty) -> ty` let func_ty = Ty::new_fn_def(tcx, self.def_id, [ty]); - let func = Operand::Constant(Box::new(Constant { + let func = Operand::Constant(Box::new(ConstOperand { span: self.span, user_ty: None, - literal: ConstantKind::zero_sized(func_ty), + const_: Const::zero_sized(func_ty), })); let ref_loc = self.make_place( @@ -764,10 +764,10 @@ fn build_call_shim<'tcx>( CallKind::Direct(def_id) => { let ty = tcx.type_of(def_id).instantiate_identity(); ( - Operand::Constant(Box::new(Constant { + Operand::Constant(Box::new(ConstOperand { span, user_ty: None, - literal: ConstantKind::zero_sized(ty), + const_: Const::zero_sized(ty), })), rcvr.into_iter().collect::>(), ) diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 495f66417666..b508cd1c9cc5 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -23,7 +23,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition { TerminatorKind::SwitchInt { discr: Operand::Constant(ref c), ref targets, .. } => { - let constant = c.literal.try_eval_bits(tcx, param_env); + let constant = c.const_.try_eval_bits(tcx, param_env); if let Some(constant) = constant { let target = targets.target_for_value(constant); TerminatorKind::Goto { target } @@ -33,7 +33,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition { } TerminatorKind::Assert { target, cond: Operand::Constant(ref c), expected, .. - } => match c.literal.try_eval_bool(tcx, param_env) { + } => match c.const_.try_eval_bool(tcx, param_env) { Some(v) if v == expected => TerminatorKind::Goto { target }, _ => continue, }, diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index 113ca2fc5ada..1a8cfc411784 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -206,12 +206,12 @@ fn find_branch_value_info<'tcx>( match (left, right) { (Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on)) | (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => { - let branch_value_ty = branch_value.literal.ty(); + let branch_value_ty = branch_value.const_.ty(); // we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats if !branch_value_ty.is_integral() && !branch_value_ty.is_char() { return None; }; - let branch_value_scalar = branch_value.literal.try_to_scalar()?; + let branch_value_scalar = branch_value.const_.try_to_scalar()?; Some((branch_value_scalar, branch_value_ty, *to_switch_on)) } _ => None, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 67e821dcf5a3..8e9cb902d86d 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -746,20 +746,20 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { /// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily /// work, as some constants cannot be represented in the type system. #[instrument(skip(self), level = "debug")] - fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) { - let literal = self.monomorphize(constant.literal); + fn visit_constant(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) { + let const_ = self.monomorphize(constant.const_); let param_env = ty::ParamEnv::reveal_all(); - let val = match literal.eval(self.tcx, param_env, None) { + let val = match const_.eval(self.tcx, param_env, None) { Ok(v) => v, Err(ErrorHandled::Reported(..)) => return, Err(ErrorHandled::TooGeneric(..)) => span_bug!( self.body.source_info(location).span, "collection encountered polymorphic constant: {:?}", - literal + const_ ), }; collect_const_value(self.tcx, val, self.output); - MirVisitor::visit_ty(self, literal.ty(), TyContext::Location(location)); + MirVisitor::visit_ty(self, const_.ty(), TyContext::Location(location)); } fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { @@ -796,7 +796,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { for op in operands { match *op { mir::InlineAsmOperand::SymFn { ref value } => { - let fn_ty = self.monomorphize(value.literal.ty()); + let fn_ty = self.monomorphize(value.const_.ty()); visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output, &[]); } mir::InlineAsmOperand::SymStatic { def_id } => { diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index a8b7a0dbb681..0e85f35fc1b9 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -9,13 +9,13 @@ use rustc_hir::{def::DefKind, def_id::DefId, ConstContext}; use rustc_middle::mir::{ self, visit::{TyContext, Visitor}, - Constant, ConstantKind, Local, LocalDecl, Location, + Local, LocalDecl, Location, }; use rustc_middle::query::Providers; use rustc_middle::ty::{ self, visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}, - Const, GenericArgsRef, Ty, TyCtxt, UnusedGenericParams, + GenericArgsRef, Ty, TyCtxt, UnusedGenericParams, }; use rustc_span::symbol::sym; use std::ops::ControlFlow; @@ -261,12 +261,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.super_local_decl(local, local_decl); } - fn visit_constant(&mut self, ct: &Constant<'tcx>, location: Location) { - match ct.literal { - ConstantKind::Ty(c) => { + fn visit_constant(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) { + match ct.const_ { + mir::Const::Ty(c) => { c.visit_with(self); } - ConstantKind::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => { + mir::Const::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => { // Avoid considering `T` unused when constants are of the form: // `>::foo::promoted[p]` if let Some(p) = promoted { @@ -280,7 +280,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { Visitor::visit_ty(self, ty, TyContext::Location(location)); } - ConstantKind::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)), + mir::Const::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)), } } @@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor> for MarkUsedGenericParams<'a, 'tcx> { #[instrument(level = "debug", skip(self))] - fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow { + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { if !c.has_non_region_param() { return ControlFlow::Continue(()); } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 93b5b9654d35..ad5f17cab6c7 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -14,8 +14,8 @@ use crate::stable_mir::ty::{ }; use crate::stable_mir::{self, CompilerError, Context}; use rustc_hir as hir; +use rustc_middle::mir; use rustc_middle::mir::interpret::{alloc_range, AllocId}; -use rustc_middle::mir::{self, ConstantKind}; use rustc_middle::ty::{self, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_span::ErrorGuaranteed; @@ -539,14 +539,14 @@ impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> { } } -impl<'tcx> Stable<'tcx> for mir::Constant<'tcx> { +impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> { type T = stable_mir::mir::Constant; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { stable_mir::mir::Constant { span: self.span.stable(tables), user_ty: self.user_ty.map(|u| u.as_usize()).or(None), - literal: self.literal.stable(tables), + literal: self.const_.stable(tables), } } } @@ -1247,13 +1247,13 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef { } } -impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> { +impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { type T = stable_mir::ty::Const; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { match *self { - ConstantKind::Ty(c) => c.stable(tables), - ConstantKind::Unevaluated(unev_const, ty) => stable_mir::ty::Const { + mir::Const::Ty(c) => c.stable(tables), + mir::Const::Unevaluated(unev_const, ty) => stable_mir::ty::Const { literal: stable_mir::ty::ConstantKind::Unevaluated( stable_mir::ty::UnevaluatedConst { def: tables.const_def(unev_const.def), @@ -1263,7 +1263,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> { ), ty: tables.intern_ty(ty), }, - ConstantKind::Val(val, ty) => stable_mir::ty::Const { + mir::Const::Val(val, ty) => stable_mir::ty::Const { literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation( ty, val, tables, )), diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 8cddd5f9a877..fd850ed74fc4 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -283,7 +283,7 @@ pub(crate) fn print_evaluated_const( (_, &ty::Ref(..)) => None, (mir::ConstValue::Scalar(_), &ty::Adt(_, _)) => None, (mir::ConstValue::Scalar(_), _) => { - let const_ = mir::ConstantKind::from_value(val, ty); + let const_ = mir::Const::from_value(val, ty); Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type)) } _ => None, @@ -319,20 +319,20 @@ fn format_integer_with_underscore_sep(num: &str) -> String { fn print_const_with_custom_print_scalar<'tcx>( tcx: TyCtxt<'tcx>, - ct: mir::ConstantKind<'tcx>, + ct: mir::Const<'tcx>, underscores_and_type: bool, ) -> String { // Use a slightly different format for integer types which always shows the actual value. // For all other types, fallback to the original `pretty_print_const`. match (ct, ct.ty().kind()) { - (mir::ConstantKind::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => { + (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => { if underscores_and_type { format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str()) } else { int.to_string() } } - (mir::ConstantKind::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => { + (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => { let ty = ct.ty(); let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; let data = int.assert_bits(size); diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index 96c5c7fc5093..3f60e5a7c4d6 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { .tcx .const_eval_poly(def_id.to_def_id()) .ok() - .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty)); + .map(|val| rustc_middle::mir::Const::from_value(val, ty)); if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) { if let ty::Adt(adt, _) = ty.kind() { if adt.is_enum() { diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs index 6e13148f2fc1..7c0485914b83 100644 --- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs @@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) Some(lhs) => constant(cx, cx.typeck_results(), lhs)?, None => { let min_val_const = ty.numeric_min_val(cx.tcx)?; - miri_to_const(cx, mir::ConstantKind::from_ty_const(min_val_const, cx.tcx))? + miri_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))? }, }; let rhs_const = match rhs { Some(rhs) => constant(cx, cx.typeck_results(), rhs)?, None => { let max_val_const = ty.numeric_max_val(cx.tcx)?; - miri_to_const(cx, mir::ConstantKind::from_ty_const(max_val_const, cx.tcx))? + miri_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))? }, }; let lhs_val = lhs_const.int_value(cx, ty)?; diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index c88fce22f7fb..a136de862408 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -21,7 +21,7 @@ use std::iter; /// A `LitKind`-like enum to fold constant `Expr`s into. #[derive(Debug, Clone)] pub enum Constant<'tcx> { - Adt(rustc_middle::mir::ConstantKind<'tcx>), + Adt(rustc_middle::mir::Const<'tcx>), /// A `String` (e.g., "abc"). Str(String), /// A binary string (e.g., `b"abc"`). @@ -482,7 +482,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .tcx .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None) .ok() - .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?; + .map(|val| rustc_middle::mir::Const::from_value(val, ty))?; let result = miri_to_const(self.lcx, result)?; self.source = ConstantSource::Constant; Some(result) @@ -655,10 +655,10 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } -pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'tcx>) -> Option> { +pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option> { use rustc_middle::mir::ConstValue; match result { - mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() { + mir::Const::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))), @@ -671,11 +671,11 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))), _ => None, }, - mir::ConstantKind::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) => { + mir::Const::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) => { let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?; String::from_utf8(data.to_owned()).ok().map(Constant::Str) } - mir::ConstantKind::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => { + mir::Const::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => { let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory(); match result.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), @@ -714,17 +714,17 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t fn field_of_struct<'tcx>( adt_def: ty::AdtDef<'tcx>, lcx: &LateContext<'tcx>, - result: mir::ConstantKind<'tcx>, + result: mir::Const<'tcx>, field: &Ident, -) -> Option> { - if let mir::ConstantKind::Val(result, ty) = result +) -> Option> { + if let mir::Const::Val(result, ty) = result && let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_diagnostics((result, ty)) && let Some(dc_variant) = dc.variant && let Some(variant) = adt_def.variants().get(dc_variant) && let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name) && let Some(&(val, ty)) = dc.fields.get(field_idx) { - Some(mir::ConstantKind::Val(val, ty)) + Some(mir::Const::Val(val, ty)) } else { None diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 4ef3ec19647e..1e464db8087e 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -97,7 +97,7 @@ use rustc_hir::{ use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; -use rustc_middle::mir::ConstantKind; +use rustc_middle::mir::Const; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; use rustc_middle::ty::fast_reject::SimplifiedType; @@ -1510,7 +1510,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let bnd_ty = subst.type_at(0) && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) - && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty) + && let min_const_kind = Const::from_value(const_val, bnd_ty) && let Some(min_const) = miri_to_const(cx, min_const_kind) && let Some(start_const) = constant(cx, cx.typeck_results(), start) { @@ -1526,7 +1526,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let bnd_ty = subst.type_at(0) && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) - && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty) + && let max_const_kind = Const::from_value(const_val, bnd_ty) && let Some(max_const) = miri_to_const(cx, max_const_kind) && let Some(end_const) = constant(cx, cx.typeck_results(), end) { diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir index 18a663d9f9e9..1d3317efd41d 100644 --- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir @@ -9,9 +9,9 @@ fn outer(_1: u8) -> u8 { StorageLive(_2); // scope 0 at $DIR/spans.rs:10:11: 10:13 _2 = &_1; // scope 0 at $DIR/spans.rs:10:11: 10:13 _0 = inner(move _2) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/spans.rs:10:5: 10:14 - // mir::Constant + // mir::ConstOperand // + span: $DIR/spans.rs:10:5: 10:10 - // + literal: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) } + // + const_: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) } } bb1: { diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir index 1c02fb72bcd6..aba66861f7d2 100644 --- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir @@ -9,9 +9,9 @@ fn outer(_1: u8) -> u8 { StorageLive(_2); // scope 0 at $DIR/spans.rs:10:11: 10:13 _2 = &_1; // scope 0 at $DIR/spans.rs:10:11: 10:13 _0 = inner(move _2) -> [return: bb1, unwind continue]; // scope 0 at $DIR/spans.rs:10:5: 10:14 - // mir::Constant + // mir::ConstOperand // + span: $DIR/spans.rs:10:5: 10:10 - // + literal: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) } + // + const_: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) } } bb1: { From f156d3bc5720603b8ce7a6a33bbfd464f9ca2e84 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 26 Aug 2023 22:09:18 +0200 Subject: [PATCH 13/26] Improve invalid UTF-8 lint by finding the expression initializer --- compiler/rustc_lint/src/invalid_from_utf8.rs | 25 ++-- tests/ui/lint/invalid_from_utf8.rs | 27 ++++ tests/ui/lint/invalid_from_utf8.stderr | 147 +++++++++++++------ 3 files changed, 143 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index 3291286ad679..1841e7c85a81 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -1,6 +1,6 @@ use std::str::Utf8Error; -use rustc_ast::{BorrowKind, LitKind}; +use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_span::source_map::Spanned; use rustc_span::sym; @@ -11,7 +11,7 @@ use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { /// The `invalid_from_utf8_unchecked` lint checks for calls to /// `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut` - /// with an invalid UTF-8 literal. + /// with a known invalid UTF-8 value. /// /// ### Example /// @@ -36,7 +36,7 @@ declare_lint! { declare_lint! { /// The `invalid_from_utf8` lint checks for calls to /// `std::str::from_utf8` and `std::str::from_utf8_mut` - /// with an invalid UTF-8 literal. + /// with a known invalid UTF-8 value. /// /// ### Example /// @@ -67,8 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { && [sym::str_from_utf8, sym::str_from_utf8_mut, sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) { - let lint = |utf8_error: Utf8Error| { - let label = arg.span; + let lint = |label, utf8_error: Utf8Error| { let method = diag_item.as_str().strip_prefix("str_").unwrap(); let method = format!("std::str::{method}"); let valid_up_to = utf8_error.valid_up_to(); @@ -78,22 +77,26 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { INVALID_FROM_UTF8 }, expr.span, if is_unchecked_variant { - InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label } + InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label } } else { - InvalidFromUtf8Diag::Checked { method, valid_up_to, label } + InvalidFromUtf8Diag::Checked { method, valid_up_to, label } } ) }; - match &arg.kind { + let mut init = cx.expr_or_init(arg); + while let ExprKind::AddrOf(.., inner) = init.kind { + init = cx.expr_or_init(inner); + } + match init.kind { ExprKind::Lit(Spanned { node: lit, .. }) => { if let LitKind::ByteStr(bytes, _) = &lit && let Err(utf8_error) = std::str::from_utf8(bytes) { - lint(utf8_error); + lint(init.span, utf8_error); } }, - ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => { + ExprKind::Array(args) => { let elements = args.iter().map(|e|{ match &e.kind { ExprKind::Lit(Spanned { node: lit, .. }) => match lit { @@ -108,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { if let Some(elements) = elements && let Err(utf8_error) = std::str::from_utf8(&elements) { - lint(utf8_error); + lint(init.span, utf8_error); } } _ => {} diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs index 9c8c636812e0..43ceffb71e50 100644 --- a/tests/ui/lint/invalid_from_utf8.rs +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -1,6 +1,8 @@ // check-pass +#![feature(inline_const)] #![feature(concat_bytes)] + #![warn(invalid_from_utf8_unchecked)] #![warn(invalid_from_utf8)] @@ -90,4 +92,29 @@ pub fn from_utf8() { } } +pub fn from_utf8_with_indirections() { + let mut a = [99, 108, 130, 105, 112, 112, 121]; + std::str::from_utf8_mut(&mut a); + //~^ WARN calls to `std::str::from_utf8_mut` + let mut b = &mut a; + let mut c = b; + std::str::from_utf8_mut(c); + //~^ WARN calls to `std::str::from_utf8_mut` + let mut c = &[99, 108, 130, 105, 112, 112, 121]; + std::str::from_utf8(c); + //~^ WARN calls to `std::str::from_utf8` + const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; + std::str::from_utf8(&INVALID_1); + //~^ WARN calls to `std::str::from_utf8` + static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; + std::str::from_utf8(&INVALID_2); + //~^ WARN calls to `std::str::from_utf8` + const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121]; + std::str::from_utf8(INVALID_3); + //~^ WARN calls to `std::str::from_utf8` + const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] }; + std::str::from_utf8(INVALID_4); + //~^ WARN calls to `std::str::from_utf8` +} + fn main() {} diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr index 8e00d3bf872f..884165d4f123 100644 --- a/tests/ui/lint/invalid_from_utf8.stderr +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -1,51 +1,51 @@ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:19:9 + --> $DIR/invalid_from_utf8.rs:21:9 | LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes | note: the lint level is defined here - --> $DIR/invalid_from_utf8.rs:4:9 + --> $DIR/invalid_from_utf8.rs:6:9 | LL | #![warn(invalid_from_utf8_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:21:9 + --> $DIR/invalid_from_utf8.rs:23:9 | LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes - -warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:39:9 - | -LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior --> $DIR/invalid_from_utf8.rs:41:9 | -LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior --> $DIR/invalid_from_utf8.rs:43:9 | +LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:45:9 + | LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ | | | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior - --> $DIR/invalid_from_utf8.rs:45:9 + --> $DIR/invalid_from_utf8.rs:47:9 | LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ @@ -53,58 +53,115 @@ LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:62:9 + --> $DIR/invalid_from_utf8.rs:64:9 | LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes | note: the lint level is defined here - --> $DIR/invalid_from_utf8.rs:5:9 + --> $DIR/invalid_from_utf8.rs:7:9 | LL | #![warn(invalid_from_utf8)] | ^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:64:9 + --> $DIR/invalid_from_utf8.rs:66:9 | LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes - -warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:82:9 - | -LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^-----------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error --> $DIR/invalid_from_utf8.rs:84:9 | -LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ - | | - | the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error --> $DIR/invalid_from_utf8.rs:86:9 | +LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^---------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:88:9 + | LL | std::str::from_utf8(b"cl\x82ippy"); | ^^^^^^^^^^^^^^^^^^^^-------------^ | | | the literal was valid UTF-8 up to the 2 bytes warning: calls to `std::str::from_utf8` with a invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:88:9 + --> $DIR/invalid_from_utf8.rs:90:9 | LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); | ^^^^^^^^^^^^^^^^^^^^---------------------------------^ | | | the literal was valid UTF-8 up to the 2 bytes -warning: 12 warnings emitted +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:97:5 + | +LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8_mut(&mut a); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:101:5 + | +LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +... +LL | std::str::from_utf8_mut(c); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:104:5 + | +LL | let mut c = &[99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8(c); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:107:5 + | +LL | const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8(&INVALID_1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:110:5 + | +LL | static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8(&INVALID_2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:113:5 + | +LL | const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8(INVALID_3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:116:5 + | +LL | const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] }; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | std::str::from_utf8(INVALID_4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 19 warnings emitted From 659575aade611f19b8e75e39224781b1f6f15ee6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 2 Aug 2023 15:55:37 +1000 Subject: [PATCH 14/26] coverage: Make the zero counter a constant --- .../src/coverageinfo/ffi.rs | 19 ++++++++----------- .../src/coverageinfo/map_data.rs | 8 ++++---- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index 7a82d05ce9ea..fe334b292657 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -30,11 +30,8 @@ pub struct Counter { } impl Counter { - /// Constructs a new `Counter` of kind `Zero`. For this `CounterKind`, the - /// `id` is not used. - pub fn zero() -> Self { - Self { kind: CounterKind::Zero, id: 0 } - } + /// A `Counter` of kind `Zero`. For this counter kind, the `id` is not used. + pub(crate) const ZERO: Self = Self { kind: CounterKind::Zero, id: 0 }; /// Constructs a new `Counter` of kind `CounterValueReference`. pub fn counter_value_reference(counter_id: CounterId) -> Self { @@ -172,7 +169,7 @@ impl CounterMappingRegion { ) -> Self { Self { counter, - false_counter: Counter::zero(), + false_counter: Counter::ZERO, file_id, expanded_file_id: 0, start_line, @@ -220,8 +217,8 @@ impl CounterMappingRegion { end_col: u32, ) -> Self { Self { - counter: Counter::zero(), - false_counter: Counter::zero(), + counter: Counter::ZERO, + false_counter: Counter::ZERO, file_id, expanded_file_id, start_line, @@ -243,8 +240,8 @@ impl CounterMappingRegion { end_col: u32, ) -> Self { Self { - counter: Counter::zero(), - false_counter: Counter::zero(), + counter: Counter::ZERO, + false_counter: Counter::ZERO, file_id, expanded_file_id: 0, start_line, @@ -268,7 +265,7 @@ impl CounterMappingRegion { ) -> Self { Self { counter, - false_counter: Counter::zero(), + false_counter: Counter::ZERO, file_id, expanded_file_id: 0, start_line, diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index f1e68af25d40..cf0de817f486 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -191,7 +191,7 @@ impl<'tcx> FunctionCoverage<'tcx> { // vector is only complete up to the current `ExpressionIndex`. type NewIndexes = IndexSlice>; let id_to_counter = |new_indexes: &NewIndexes, operand: Operand| match operand { - Operand::Zero => Some(Counter::zero()), + Operand::Zero => Some(Counter::ZERO), Operand::Counter(id) => Some(Counter::counter_value_reference(id)), Operand::Expression(id) => { self.expressions @@ -201,7 +201,7 @@ impl<'tcx> FunctionCoverage<'tcx> { // If an expression was optimized out, assume it would have produced a count // of zero. This ensures that expressions dependent on optimized-out // expressions are still valid. - .map_or(Some(Counter::zero()), |_| new_indexes[id].map(Counter::expression)) + .map_or(Some(Counter::ZERO), |_| new_indexes[id].map(Counter::expression)) } }; @@ -237,7 +237,7 @@ impl<'tcx> FunctionCoverage<'tcx> { original_index={:?}, lhs={:?}, op={:?}, rhs={:?}, region={:?}", original_index, lhs, op, rhs, optional_region, ); - rhs_counter = Counter::zero(); + rhs_counter = Counter::ZERO; } debug_assert!( lhs_counter.is_zero() @@ -306,6 +306,6 @@ impl<'tcx> FunctionCoverage<'tcx> { } fn unreachable_regions(&self) -> impl Iterator { - self.unreachable_regions.iter().map(|region| (Counter::zero(), region)) + self.unreachable_regions.iter().map(|region| (Counter::ZERO, region)) } } From 527c629cd9d2cc689eabb99d4e246b01401f2564 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 14 Aug 2023 18:01:28 +1000 Subject: [PATCH 15/26] coverage: Explicitly simplify coverage expressions in codegen After coverage instrumentation and MIR transformations, we can sometimes end up with coverage expressions that always have a value of zero. Any expression operand that refers to an always-zero expression can be replaced with a literal `Operand::Zero`, making the emitted coverage mapping data smaller and simpler. This simplification step is mostly redundant with the simplifications performed inline in `expressions_with_regions`, except that it does a slightly more thorough job in some cases (because it checks for always-zero expressions *after* other simplifications). However, adding this simplification step will then let us greatly simplify that code, without affecting the quality of the emitted coverage maps. --- .../src/coverageinfo/map_data.rs | 53 ++++ .../src/coverageinfo/mapgen.rs | 5 +- .../status-quo/loops_branches.cov-map | 264 +++++++++--------- 3 files changed, 185 insertions(+), 137 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index cf0de817f486..31fcbbad0e60 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -1,5 +1,6 @@ use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind}; +use rustc_data_structures::fx::FxIndexSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::bug; use rustc_middle::mir::coverage::{ @@ -128,6 +129,58 @@ impl<'tcx> FunctionCoverage<'tcx> { self.unreachable_regions.push(region) } + /// Perform some simplifications to make the final coverage mappings + /// slightly smaller. + /// + /// This method mainly exists to preserve the simplifications that were + /// already being performed by the Rust-side expression renumbering, so that + /// the resulting coverage mappings don't get worse. + pub(crate) fn simplify_expressions(&mut self) { + // The set of expressions that either were optimized out entirely, or + // have zero as both of their operands, and will therefore always have + // a value of zero. Other expressions that refer to these as operands + // can have those operands replaced with `Operand::Zero`. + let mut zero_expressions = FxIndexSet::default(); + + // For each expression, perform simplifications based on lower-numbered + // expressions, and then update the set of always-zero expressions if + // necessary. + // (By construction, expressions can only refer to other expressions + // that have lower IDs, so one simplification pass is sufficient.) + for (id, maybe_expression) in self.expressions.iter_enumerated_mut() { + let Some(expression) = maybe_expression else { + // If an expression is missing, it must have been optimized away, + // so any operand that refers to it can be replaced with zero. + zero_expressions.insert(id); + continue; + }; + + // If an operand refers to an expression that is always zero, then + // that operand can be replaced with `Operand::Zero`. + let maybe_set_operand_to_zero = |operand: &mut Operand| match &*operand { + Operand::Expression(id) if zero_expressions.contains(id) => { + *operand = Operand::Zero; + } + _ => (), + }; + maybe_set_operand_to_zero(&mut expression.lhs); + maybe_set_operand_to_zero(&mut expression.rhs); + + // Coverage counter values cannot be negative, so if an expression + // involves subtraction from zero, assume that its RHS must also be zero. + // (Do this after simplifications that could set the LHS to zero.) + if let Expression { lhs: Operand::Zero, op: Op::Subtract, .. } = expression { + expression.rhs = Operand::Zero; + } + + // After the above simplifications, if both operands are zero, then + // we know that this expression is always zero too. + if let Expression { lhs: Operand::Zero, rhs: Operand::Zero, .. } = expression { + zero_expressions.insert(id); + } + } + } + /// Return the source hash, generated from the HIR node structure, and used to indicate whether /// or not the source code structure changed between different compilations. pub fn source_hash(&self) -> u64 { diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 8ba7a11abe5c..d4e775256985 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -60,8 +60,11 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { // Encode coverage mappings and generate function records let mut function_data = Vec::new(); - for (instance, function_coverage) in function_coverage_map { + for (instance, mut function_coverage) in function_coverage_map { debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance); + function_coverage.simplify_expressions(); + let function_coverage = function_coverage; + let mangled_function_name = tcx.symbol_name(instance).name; let source_hash = function_coverage.source_hash(); let is_used = function_coverage.is_used(); diff --git a/tests/coverage-map/status-quo/loops_branches.cov-map b/tests/coverage-map/status-quo/loops_branches.cov-map index 56fafc0a67b1..480bbfd97957 100644 --- a/tests/coverage-map/status-quo/loops_branches.cov-map +++ b/tests/coverage-map/status-quo/loops_branches.cov-map @@ -1,62 +1,58 @@ Function name: ::fmt -Raw bytes (262): 0x[01, 01, 36, 05, 09, 0a, 02, 00, 00, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, d3, 01, d7, 01, 0d, 00, 11, 15, ca, 01, 00, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, bb, 01, 11, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, 25, b3, 01, b6, 01, 19, bb, 01, 11, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, ca, 01, 03, 0d, 00, 0e, cf, 01, 00, 12, 00, 17, 2b, 01, 10, 00, 14, c6, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, c2, 01, 01, 12, 00, 13, bb, 01, 01, 11, 00, 22, b6, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, af, 01, 01, 05, 00, 06] +Raw bytes (251): 0x[01, 01, 32, 05, 09, 00, 02, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, c3, 01, c7, 01, 0d, 00, 11, 15, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, 00, b2, 01, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, af, 01, 11, 00, b2, 01, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, 25, a7, 01, aa, 01, 19, af, 01, 11, 00, b2, 01, b6, 01, 1d, ba, 01, 15, bf, 01, 19, c3, 01, c7, 01, 0d, 00, 11, 15, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, ba, 01, 03, 0d, 00, 0e, bf, 01, 00, 12, 00, 17, 27, 01, 10, 00, 14, b6, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b2, 01, 01, 12, 00, 13, af, 01, 01, 11, 00, 22, aa, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, a3, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 -Number of expressions: 54 +Number of expressions: 50 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) -- expression 1 operands: lhs = Expression(2, Sub), rhs = Expression(0, Sub) -- expression 2 operands: lhs = Zero, rhs = Zero -- expression 3 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 4 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 5 operands: lhs = Counter(3), rhs = Zero -- expression 6 operands: lhs = Counter(4), rhs = Counter(5) -- expression 7 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 8 operands: lhs = Counter(3), rhs = Zero -- expression 9 operands: lhs = Counter(4), rhs = Counter(5) -- expression 10 operands: lhs = Expression(50, Sub), rhs = Zero -- expression 11 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 12 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 13 operands: lhs = Counter(3), rhs = Zero -- expression 14 operands: lhs = Counter(4), rhs = Counter(5) -- expression 15 operands: lhs = Expression(50, Sub), rhs = Counter(5) -- expression 16 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 17 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 18 operands: lhs = Counter(3), rhs = Zero -- expression 19 operands: lhs = Counter(4), rhs = Counter(5) -- expression 20 operands: lhs = Expression(49, Sub), rhs = Counter(7) -- expression 21 operands: lhs = Expression(50, Sub), rhs = Counter(5) -- expression 22 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 23 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 24 operands: lhs = Counter(3), rhs = Zero -- expression 25 operands: lhs = Counter(4), rhs = Counter(5) -- expression 26 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub) -- expression 27 operands: lhs = Zero, rhs = Zero -- expression 28 operands: lhs = Expression(49, Sub), rhs = Counter(7) -- expression 29 operands: lhs = Expression(50, Sub), rhs = Counter(5) -- expression 30 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 31 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 32 operands: lhs = Counter(3), rhs = Zero -- expression 33 operands: lhs = Counter(4), rhs = Counter(5) -- expression 34 operands: lhs = Expression(46, Add), rhs = Counter(4) -- expression 35 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub) -- expression 36 operands: lhs = Zero, rhs = Zero -- expression 37 operands: lhs = Expression(49, Sub), rhs = Counter(7) -- expression 38 operands: lhs = Expression(50, Sub), rhs = Counter(5) -- expression 39 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 40 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 41 operands: lhs = Counter(3), rhs = Zero -- expression 42 operands: lhs = Counter(4), rhs = Counter(5) -- expression 43 operands: lhs = Counter(9), rhs = Expression(44, Add) -- expression 44 operands: lhs = Expression(45, Sub), rhs = Counter(6) -- expression 45 operands: lhs = Expression(46, Add), rhs = Counter(4) -- expression 46 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub) -- expression 47 operands: lhs = Zero, rhs = Zero -- expression 48 operands: lhs = Expression(49, Sub), rhs = Counter(7) -- expression 49 operands: lhs = Expression(50, Sub), rhs = Counter(5) -- expression 50 operands: lhs = Expression(51, Add), rhs = Counter(6) -- expression 51 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) -- expression 52 operands: lhs = Counter(3), rhs = Zero -- expression 53 operands: lhs = Counter(4), rhs = Counter(5) +- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub) +- expression 2 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 3 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 4 operands: lhs = Counter(3), rhs = Zero +- expression 5 operands: lhs = Counter(4), rhs = Counter(5) +- expression 6 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 7 operands: lhs = Counter(3), rhs = Zero +- expression 8 operands: lhs = Counter(4), rhs = Counter(5) +- expression 9 operands: lhs = Expression(46, Sub), rhs = Zero +- expression 10 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 11 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 12 operands: lhs = Counter(3), rhs = Zero +- expression 13 operands: lhs = Counter(4), rhs = Counter(5) +- expression 14 operands: lhs = Expression(46, Sub), rhs = Counter(5) +- expression 15 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 16 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 17 operands: lhs = Counter(3), rhs = Zero +- expression 18 operands: lhs = Counter(4), rhs = Counter(5) +- expression 19 operands: lhs = Expression(45, Sub), rhs = Counter(7) +- expression 20 operands: lhs = Expression(46, Sub), rhs = Counter(5) +- expression 21 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 22 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 23 operands: lhs = Counter(3), rhs = Zero +- expression 24 operands: lhs = Counter(4), rhs = Counter(5) +- expression 25 operands: lhs = Zero, rhs = Expression(44, Sub) +- expression 26 operands: lhs = Expression(45, Sub), rhs = Counter(7) +- expression 27 operands: lhs = Expression(46, Sub), rhs = Counter(5) +- expression 28 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 29 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 30 operands: lhs = Counter(3), rhs = Zero +- expression 31 operands: lhs = Counter(4), rhs = Counter(5) +- expression 32 operands: lhs = Expression(43, Add), rhs = Counter(4) +- expression 33 operands: lhs = Zero, rhs = Expression(44, Sub) +- expression 34 operands: lhs = Expression(45, Sub), rhs = Counter(7) +- expression 35 operands: lhs = Expression(46, Sub), rhs = Counter(5) +- expression 36 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 37 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 38 operands: lhs = Counter(3), rhs = Zero +- expression 39 operands: lhs = Counter(4), rhs = Counter(5) +- expression 40 operands: lhs = Counter(9), rhs = Expression(41, Add) +- expression 41 operands: lhs = Expression(42, Sub), rhs = Counter(6) +- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(4) +- expression 43 operands: lhs = Zero, rhs = Expression(44, Sub) +- expression 44 operands: lhs = Expression(45, Sub), rhs = Counter(7) +- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(5) +- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(6) +- expression 47 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 48 operands: lhs = Counter(3), rhs = Zero +- expression 49 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 16) to (start + 0, 21) @@ -65,91 +61,87 @@ Number of file 0 mappings: 20 - Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 15) = (c1 - c2) - Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 30) - = ((Zero - Zero) + (c1 - c2)) + = (Zero + (c1 - c2)) - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31) - Code(Zero) at (prev + 1, 16) to (start + 1, 10) -- Code(Expression(50, Sub)) at (prev + 3, 13) to (start + 0, 14) +- Code(Expression(46, Sub)) at (prev + 3, 13) to (start + 0, 14) = (((c3 + Zero) + (c4 + c5)) - c6) -- Code(Expression(51, Add)) at (prev + 0, 18) to (start + 0, 23) +- Code(Expression(47, Add)) at (prev + 0, 18) to (start + 0, 23) = ((c3 + Zero) + (c4 + c5)) -- Code(Expression(10, Add)) at (prev + 1, 16) to (start + 0, 20) +- Code(Expression(9, Add)) at (prev + 1, 16) to (start + 0, 20) = ((((c3 + Zero) + (c4 + c5)) - c6) + Zero) -- Code(Expression(49, Sub)) at (prev + 1, 20) to (start + 0, 25) +- Code(Expression(45, Sub)) at (prev + 1, 20) to (start + 0, 25) = ((((c3 + Zero) + (c4 + c5)) - c6) - c5) - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) -- Code(Expression(48, Sub)) at (prev + 1, 18) to (start + 0, 19) +- Code(Expression(44, Sub)) at (prev + 1, 18) to (start + 0, 19) = (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7) -- Code(Expression(46, Add)) at (prev + 1, 17) to (start + 0, 34) - = ((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) -- Code(Expression(45, Sub)) at (prev + 0, 34) to (start + 0, 35) - = (((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) +- Code(Expression(43, Add)) at (prev + 1, 17) to (start + 0, 34) + = (Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) +- Code(Expression(42, Sub)) at (prev + 0, 34) to (start + 0, 35) + = ((Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) - Code(Zero) at (prev + 1, 20) to (start + 1, 14) - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15) -- Code(Expression(43, Add)) at (prev + 1, 5) to (start + 0, 6) - = (c9 + ((((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) + c6)) +- Code(Expression(40, Add)) at (prev + 1, 5) to (start + 0, 6) + = (c9 + (((Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) + c6)) Function name: ::fmt -Raw bytes (266): 0x[01, 01, 38, 01, 05, 02, 09, 0e, 12, 00, 00, 02, 09, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, d7, 01, db, 01, 05, 0d, 11, 15, ce, 01, 00, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, bf, 01, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ba, 01, df, 01, bf, 01, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, 19, 25, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 12, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, ce, 01, 02, 0d, 00, 0e, d3, 01, 00, 12, 00, 17, 33, 01, 10, 00, 15, 00, 00, 16, 01, 0e, ca, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, c6, 01, 01, 12, 00, 13, bf, 01, 01, 11, 00, 22, ba, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, b7, 01, 01, 05, 00, 06] +Raw bytes (255): 0x[01, 01, 34, 01, 05, 02, 09, 00, 0e, 02, 09, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, c7, 01, cb, 01, 05, 0d, 11, 15, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, 00, b6, 01, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, b3, 01, 15, 00, b6, 01, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, ae, 01, cf, 01, b3, 01, 15, 00, b6, 01, ba, 01, 1d, be, 01, 11, c3, 01, 19, c7, 01, cb, 01, 05, 0d, 11, 15, 19, 25, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 0e, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, be, 01, 02, 0d, 00, 0e, c3, 01, 00, 12, 00, 17, 2f, 01, 10, 00, 15, 00, 00, 16, 01, 0e, ba, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b6, 01, 01, 12, 00, 13, b3, 01, 01, 11, 00, 22, ae, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, ab, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 -Number of expressions: 56 +Number of expressions: 52 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Expression(0, Sub), rhs = Counter(2) -- expression 2 operands: lhs = Expression(3, Sub), rhs = Expression(4, Sub) -- expression 3 operands: lhs = Zero, rhs = Zero -- expression 4 operands: lhs = Expression(0, Sub), rhs = Counter(2) -- expression 5 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 6 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 7 operands: lhs = Counter(1), rhs = Counter(3) -- expression 8 operands: lhs = Counter(4), rhs = Counter(5) -- expression 9 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 10 operands: lhs = Counter(1), rhs = Counter(3) -- expression 11 operands: lhs = Counter(4), rhs = Counter(5) -- expression 12 operands: lhs = Expression(51, Sub), rhs = Zero -- expression 13 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 14 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 15 operands: lhs = Counter(1), rhs = Counter(3) -- expression 16 operands: lhs = Counter(4), rhs = Counter(5) -- expression 17 operands: lhs = Expression(51, Sub), rhs = Counter(4) -- expression 18 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 19 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 20 operands: lhs = Counter(1), rhs = Counter(3) -- expression 21 operands: lhs = Counter(4), rhs = Counter(5) -- expression 22 operands: lhs = Expression(50, Sub), rhs = Counter(7) -- expression 23 operands: lhs = Expression(51, Sub), rhs = Counter(4) -- expression 24 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 25 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 26 operands: lhs = Counter(1), rhs = Counter(3) -- expression 27 operands: lhs = Counter(4), rhs = Counter(5) -- expression 28 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub) -- expression 29 operands: lhs = Zero, rhs = Zero -- expression 30 operands: lhs = Expression(50, Sub), rhs = Counter(7) -- expression 31 operands: lhs = Expression(51, Sub), rhs = Counter(4) -- expression 32 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 33 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 34 operands: lhs = Counter(1), rhs = Counter(3) -- expression 35 operands: lhs = Counter(4), rhs = Counter(5) -- expression 36 operands: lhs = Expression(47, Add), rhs = Counter(5) -- expression 37 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub) -- expression 38 operands: lhs = Zero, rhs = Zero -- expression 39 operands: lhs = Expression(50, Sub), rhs = Counter(7) -- expression 40 operands: lhs = Expression(51, Sub), rhs = Counter(4) -- expression 41 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 42 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 43 operands: lhs = Counter(1), rhs = Counter(3) -- expression 44 operands: lhs = Counter(4), rhs = Counter(5) -- expression 45 operands: lhs = Expression(46, Sub), rhs = Expression(55, Add) -- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(5) -- expression 47 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub) -- expression 48 operands: lhs = Zero, rhs = Zero -- expression 49 operands: lhs = Expression(50, Sub), rhs = Counter(7) -- expression 50 operands: lhs = Expression(51, Sub), rhs = Counter(4) -- expression 51 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 52 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) -- expression 53 operands: lhs = Counter(1), rhs = Counter(3) -- expression 54 operands: lhs = Counter(4), rhs = Counter(5) -- expression 55 operands: lhs = Counter(6), rhs = Counter(9) +- expression 2 operands: lhs = Zero, rhs = Expression(3, Sub) +- expression 3 operands: lhs = Expression(0, Sub), rhs = Counter(2) +- expression 4 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 5 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 6 operands: lhs = Counter(1), rhs = Counter(3) +- expression 7 operands: lhs = Counter(4), rhs = Counter(5) +- expression 8 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 9 operands: lhs = Counter(1), rhs = Counter(3) +- expression 10 operands: lhs = Counter(4), rhs = Counter(5) +- expression 11 operands: lhs = Expression(47, Sub), rhs = Zero +- expression 12 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 13 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 14 operands: lhs = Counter(1), rhs = Counter(3) +- expression 15 operands: lhs = Counter(4), rhs = Counter(5) +- expression 16 operands: lhs = Expression(47, Sub), rhs = Counter(4) +- expression 17 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 18 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 19 operands: lhs = Counter(1), rhs = Counter(3) +- expression 20 operands: lhs = Counter(4), rhs = Counter(5) +- expression 21 operands: lhs = Expression(46, Sub), rhs = Counter(7) +- expression 22 operands: lhs = Expression(47, Sub), rhs = Counter(4) +- expression 23 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 24 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 25 operands: lhs = Counter(1), rhs = Counter(3) +- expression 26 operands: lhs = Counter(4), rhs = Counter(5) +- expression 27 operands: lhs = Zero, rhs = Expression(45, Sub) +- expression 28 operands: lhs = Expression(46, Sub), rhs = Counter(7) +- expression 29 operands: lhs = Expression(47, Sub), rhs = Counter(4) +- expression 30 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 31 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 32 operands: lhs = Counter(1), rhs = Counter(3) +- expression 33 operands: lhs = Counter(4), rhs = Counter(5) +- expression 34 operands: lhs = Expression(44, Add), rhs = Counter(5) +- expression 35 operands: lhs = Zero, rhs = Expression(45, Sub) +- expression 36 operands: lhs = Expression(46, Sub), rhs = Counter(7) +- expression 37 operands: lhs = Expression(47, Sub), rhs = Counter(4) +- expression 38 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 39 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 40 operands: lhs = Counter(1), rhs = Counter(3) +- expression 41 operands: lhs = Counter(4), rhs = Counter(5) +- expression 42 operands: lhs = Expression(43, Sub), rhs = Expression(51, Add) +- expression 43 operands: lhs = Expression(44, Add), rhs = Counter(5) +- expression 44 operands: lhs = Zero, rhs = Expression(45, Sub) +- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(7) +- expression 46 operands: lhs = Expression(47, Sub), rhs = Counter(4) +- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 48 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 49 operands: lhs = Counter(1), rhs = Counter(3) +- expression 50 operands: lhs = Counter(4), rhs = Counter(5) +- expression 51 operands: lhs = Counter(6), rhs = Counter(9) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17) - Code(Zero) at (prev + 1, 18) to (start + 1, 10) @@ -157,31 +149,31 @@ Number of file 0 mappings: 20 = (c0 - c1) - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) -- Code(Expression(4, Sub)) at (prev + 1, 14) to (start + 0, 15) +- Code(Expression(3, Sub)) at (prev + 1, 14) to (start + 0, 15) = ((c0 - c1) - c2) - Code(Expression(2, Add)) at (prev + 1, 13) to (start + 0, 30) - = ((Zero - Zero) + ((c0 - c1) - c2)) + = (Zero + ((c0 - c1) - c2)) - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31) -- Code(Expression(51, Sub)) at (prev + 2, 13) to (start + 0, 14) +- Code(Expression(47, Sub)) at (prev + 2, 13) to (start + 0, 14) = (((c1 + c3) + (c4 + c5)) - c6) -- Code(Expression(52, Add)) at (prev + 0, 18) to (start + 0, 23) +- Code(Expression(48, Add)) at (prev + 0, 18) to (start + 0, 23) = ((c1 + c3) + (c4 + c5)) -- Code(Expression(12, Add)) at (prev + 1, 16) to (start + 0, 21) +- Code(Expression(11, Add)) at (prev + 1, 16) to (start + 0, 21) = ((((c1 + c3) + (c4 + c5)) - c6) + Zero) - Code(Zero) at (prev + 0, 22) to (start + 1, 14) -- Code(Expression(50, Sub)) at (prev + 2, 20) to (start + 0, 25) +- Code(Expression(46, Sub)) at (prev + 2, 20) to (start + 0, 25) = ((((c1 + c3) + (c4 + c5)) - c6) - c4) - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) -- Code(Expression(49, Sub)) at (prev + 1, 18) to (start + 0, 19) +- Code(Expression(45, Sub)) at (prev + 1, 18) to (start + 0, 19) = (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7) -- Code(Expression(47, Add)) at (prev + 1, 17) to (start + 0, 34) - = ((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) -- Code(Expression(46, Sub)) at (prev + 0, 34) to (start + 0, 35) - = (((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) +- Code(Expression(44, Add)) at (prev + 1, 17) to (start + 0, 34) + = (Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) +- Code(Expression(43, Sub)) at (prev + 0, 34) to (start + 0, 35) + = ((Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15) -- Code(Expression(45, Add)) at (prev + 1, 5) to (start + 0, 6) - = ((((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) + (c6 + c9)) +- Code(Expression(42, Add)) at (prev + 1, 5) to (start + 0, 6) + = (((Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) + (c6 + c9)) Function name: loops_branches::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02] From 041a232b62dba833a4cfdca3f74e4029b53200a0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 23 Jul 2023 11:48:31 +1000 Subject: [PATCH 16/26] coverage: Don't bother renumbering expressions on the Rust side The LLVM API that we use to encode coverage mappings already has its own code for removing unused coverage expressions and renumbering the rest. This lets us get rid of our own complex renumbering code, making it easier to change our coverage code in other ways. --- .../src/coverageinfo/ffi.rs | 27 +-- .../src/coverageinfo/map_data.rs | 193 +++++------------- compiler/rustc_middle/src/mir/coverage.rs | 10 - .../rustc_middle/src/ty/structural_impls.rs | 1 - 4 files changed, 64 insertions(+), 167 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index fe334b292657..763186a58bf9 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -1,4 +1,4 @@ -use rustc_middle::mir::coverage::{CounterId, MappedExpressionIndex}; +use rustc_middle::mir::coverage::{CounterId, ExpressionId, Operand}; /// Must match the layout of `LLVMRustCounterKind`. #[derive(Copy, Clone, Debug)] @@ -39,20 +39,16 @@ impl Counter { } /// Constructs a new `Counter` of kind `Expression`. - pub fn expression(mapped_expression_index: MappedExpressionIndex) -> Self { - Self { kind: CounterKind::Expression, id: mapped_expression_index.into() } + pub(crate) fn expression(expression_id: ExpressionId) -> Self { + Self { kind: CounterKind::Expression, id: expression_id.as_u32() } } - /// Returns true if the `Counter` kind is `Zero`. - pub fn is_zero(&self) -> bool { - matches!(self.kind, CounterKind::Zero) - } - - /// An explicitly-named function to get the ID value, making it more obvious - /// that the stored value is now 0-based. - pub fn zero_based_id(&self) -> u32 { - debug_assert!(!self.is_zero(), "`id` is undefined for CounterKind::Zero"); - self.id + pub(crate) fn from_operand(operand: Operand) -> Self { + match operand { + Operand::Zero => Self::ZERO, + Operand::Counter(id) => Self::counter_value_reference(id), + Operand::Expression(id) => Self::expression(id), + } } } @@ -78,6 +74,11 @@ pub struct CounterExpression { } impl CounterExpression { + /// The dummy expression `(0 - 0)` has a representation of all zeroes, + /// making it marginally more efficient to initialize than `(0 + 0)`. + pub(crate) const DUMMY: Self = + Self { lhs: Counter::ZERO, kind: ExprKind::Subtract, rhs: Counter::ZERO }; + pub fn new(lhs: Counter, kind: ExprKind, rhs: Counter) -> Self { Self { kind, lhs, rhs } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index 31fcbbad0e60..e83110dcad46 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -1,11 +1,8 @@ use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind}; use rustc_data_structures::fx::FxIndexSet; -use rustc_index::{IndexSlice, IndexVec}; -use rustc_middle::bug; -use rustc_middle::mir::coverage::{ - CodeRegion, CounterId, ExpressionId, MappedExpressionIndex, Op, Operand, -}; +use rustc_index::IndexVec; +use rustc_middle::mir::coverage::{CodeRegion, CounterId, ExpressionId, Op, Operand}; use rustc_middle::ty::Instance; use rustc_middle::ty::TyCtxt; @@ -199,8 +196,14 @@ impl<'tcx> FunctionCoverage<'tcx> { self.instance ); + let counter_expressions = self.counter_expressions(); + // Expression IDs are indices into `self.expressions`, and on the LLVM + // side they will be treated as indices into `counter_expressions`, so + // the two vectors should correspond 1:1. + assert_eq!(self.expressions.len(), counter_expressions.len()); + let counter_regions = self.counter_regions(); - let (counter_expressions, expression_regions) = self.expressions_with_regions(); + let expression_regions = self.expression_regions(); let unreachable_regions = self.unreachable_regions(); let counter_regions = @@ -216,146 +219,50 @@ impl<'tcx> FunctionCoverage<'tcx> { }) } - fn expressions_with_regions( - &self, - ) -> (Vec, impl Iterator) { - let mut counter_expressions = Vec::with_capacity(self.expressions.len()); - let mut expression_regions = Vec::with_capacity(self.expressions.len()); - let mut new_indexes = IndexVec::from_elem_n(None, self.expressions.len()); + /// Convert this function's coverage expression data into a form that can be + /// passed through FFI to LLVM. + fn counter_expressions(&self) -> Vec { + // We know that LLVM will optimize out any unused expressions before + // producing the final coverage map, so there's no need to do the same + // thing on the Rust side unless we're confident we can do much better. + // (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.) - // This closure converts any `Expression` operand (`lhs` or `rhs` of the `Op::Add` or - // `Op::Subtract` operation) into its native `llvm::coverage::Counter::CounterKind` type - // and value. - // - // Expressions will be returned from this function in a sequential vector (array) of - // `CounterExpression`, so the expression IDs must be mapped from their original, - // potentially sparse set of indexes. - // - // An `Expression` as an operand will have already been encountered as an `Expression` with - // operands, so its new_index will already have been generated (as a 1-up index value). - // (If an `Expression` as an operand does not have a corresponding new_index, it was - // probably optimized out, after the expression was injected into the MIR, so it will - // get a `CounterKind::Zero` instead.) - // - // In other words, an `Expression`s at any given index can include other expressions as - // operands, but expression operands can only come from the subset of expressions having - // `expression_index`s lower than the referencing `Expression`. Therefore, it is - // reasonable to look up the new index of an expression operand while the `new_indexes` - // vector is only complete up to the current `ExpressionIndex`. - type NewIndexes = IndexSlice>; - let id_to_counter = |new_indexes: &NewIndexes, operand: Operand| match operand { - Operand::Zero => Some(Counter::ZERO), - Operand::Counter(id) => Some(Counter::counter_value_reference(id)), - Operand::Expression(id) => { - self.expressions - .get(id) - .expect("expression id is out of range") - .as_ref() - // If an expression was optimized out, assume it would have produced a count - // of zero. This ensures that expressions dependent on optimized-out - // expressions are still valid. - .map_or(Some(Counter::ZERO), |_| new_indexes[id].map(Counter::expression)) - } - }; - - for (original_index, expression) in - self.expressions.iter_enumerated().filter_map(|(original_index, entry)| { - // Option::map() will return None to filter out missing expressions. This may happen - // if, for example, a MIR-instrumented expression is removed during an optimization. - entry.as_ref().map(|expression| (original_index, expression)) + self.expressions + .iter() + .map(|expression| match expression { + None => { + // This expression ID was allocated, but we never saw the + // actual expression, so it must have been optimized out. + // Replace it with a dummy expression, and let LLVM take + // care of omitting it from the expression list. + CounterExpression::DUMMY + } + &Some(Expression { lhs, op, rhs, .. }) => { + // Convert the operands and operator as normal. + CounterExpression::new( + Counter::from_operand(lhs), + match op { + Op::Add => ExprKind::Add, + Op::Subtract => ExprKind::Subtract, + }, + Counter::from_operand(rhs), + ) + } }) - { - let optional_region = &expression.region; - let Expression { lhs, op, rhs, .. } = *expression; + .collect::>() + } - if let Some(Some((lhs_counter, mut rhs_counter))) = id_to_counter(&new_indexes, lhs) - .map(|lhs_counter| { - id_to_counter(&new_indexes, rhs).map(|rhs_counter| (lhs_counter, rhs_counter)) - }) - { - if lhs_counter.is_zero() && op.is_subtract() { - // The left side of a subtraction was probably optimized out. As an example, - // a branch condition might be evaluated as a constant expression, and the - // branch could be removed, dropping unused counters in the process. - // - // Since counters are unsigned, we must assume the result of the expression - // can be no more and no less than zero. An expression known to evaluate to zero - // does not need to be added to the coverage map. - // - // Coverage test `loops_branches.rs` includes multiple variations of branches - // based on constant conditional (literal `true` or `false`), and demonstrates - // that the expected counts are still correct. - debug!( - "Expression subtracts from zero (assume unreachable): \ - original_index={:?}, lhs={:?}, op={:?}, rhs={:?}, region={:?}", - original_index, lhs, op, rhs, optional_region, - ); - rhs_counter = Counter::ZERO; - } - debug_assert!( - lhs_counter.is_zero() - // Note: with `as usize` the ID _could_ overflow/wrap if `usize = u16` - || ((lhs_counter.zero_based_id() as usize) - <= usize::max(self.counters.len(), self.expressions.len())), - "lhs id={} > both counters.len()={} and expressions.len()={} - ({:?} {:?} {:?})", - lhs_counter.zero_based_id(), - self.counters.len(), - self.expressions.len(), - lhs_counter, - op, - rhs_counter, - ); - - debug_assert!( - rhs_counter.is_zero() - // Note: with `as usize` the ID _could_ overflow/wrap if `usize = u16` - || ((rhs_counter.zero_based_id() as usize) - <= usize::max(self.counters.len(), self.expressions.len())), - "rhs id={} > both counters.len()={} and expressions.len()={} - ({:?} {:?} {:?})", - rhs_counter.zero_based_id(), - self.counters.len(), - self.expressions.len(), - lhs_counter, - op, - rhs_counter, - ); - - // Both operands exist. `Expression` operands exist in `self.expressions` and have - // been assigned a `new_index`. - let mapped_expression_index = - MappedExpressionIndex::from(counter_expressions.len()); - let expression = CounterExpression::new( - lhs_counter, - match op { - Op::Add => ExprKind::Add, - Op::Subtract => ExprKind::Subtract, - }, - rhs_counter, - ); - debug!( - "Adding expression {:?} = {:?}, region: {:?}", - mapped_expression_index, expression, optional_region - ); - counter_expressions.push(expression); - new_indexes[original_index] = Some(mapped_expression_index); - if let Some(region) = optional_region { - expression_regions.push((Counter::expression(mapped_expression_index), region)); - } - } else { - bug!( - "expression has one or more missing operands \ - original_index={:?}, lhs={:?}, op={:?}, rhs={:?}, region={:?}", - original_index, - lhs, - op, - rhs, - optional_region, - ); - } - } - (counter_expressions, expression_regions.into_iter()) + fn expression_regions(&self) -> Vec<(Counter, &CodeRegion)> { + // Find all of the expression IDs that weren't optimized out AND have + // an attached code region, and return the corresponding mapping as a + // counter/region pair. + self.expressions + .iter_enumerated() + .filter_map(|(id, expression)| { + let code_region = expression.as_ref()?.region.as_ref()?; + Some((Counter::expression(id), code_region)) + }) + .collect::>() } fn unreachable_regions(&self) -> impl Iterator { diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 1efb54bdb087..9ef673922911 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -45,16 +45,6 @@ impl ExpressionId { } } -rustc_index::newtype_index! { - /// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their - /// array position in the LLVM coverage map "Expressions" array, which is assembled during the - /// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s. - #[derive(HashStable)] - #[max = 0xFFFF_FFFF] - #[debug_format = "MappedExpressionIndex({})"] - pub struct MappedExpressionIndex {} -} - /// Operand of a coverage-counter expression. /// /// Operands can be a constant zero value, an actual coverage counter, or another diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 268339ed4028..b66c0f20990f 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -479,7 +479,6 @@ TrivialTypeTraversalImpls! { ::rustc_target::asm::InlineAsmRegOrRegClass, crate::mir::coverage::CounterId, crate::mir::coverage::ExpressionId, - crate::mir::coverage::MappedExpressionIndex, crate::mir::Local, crate::mir::Promoted, crate::traits::Reveal, From 44e199bf300a79df302a5b068dba0c39d9a12c0f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 18 Sep 2023 15:20:36 +0000 Subject: [PATCH 17/26] Add regression test --- tests/ui/inline-const/promotion.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/ui/inline-const/promotion.rs diff --git a/tests/ui/inline-const/promotion.rs b/tests/ui/inline-const/promotion.rs new file mode 100644 index 000000000000..e211f46acf9b --- /dev/null +++ b/tests/ui/inline-const/promotion.rs @@ -0,0 +1,21 @@ +#![feature(inline_const)] +#![allow(arithmetic_overflow, unconditional_panic)] +// check-pass + +// The only way to have promoteds that fail is in `const fn` called from `const`/`static`. +const fn div_by_zero() -> i32 { + 1 / 0 +} + +const fn mk_false() -> bool { + false +} + +fn main() { + let v = const { + if mk_false() { + let _x: &'static i32 = &div_by_zero(); + } + 42 + }; +} From 9c762b58ba9f46e806f7e07b80ef59b45de87471 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 18 Sep 2023 15:30:07 +0000 Subject: [PATCH 18/26] Prevent promotion of const fn calls in inline consts --- compiler/rustc_borrowck/src/universal_regions.rs | 2 +- .../src/transform/check_consts/check.rs | 2 +- .../src/transform/promote_consts.rs | 2 +- compiler/rustc_errors/src/diagnostic_impls.rs | 2 +- compiler/rustc_hir/src/hir.rs | 12 ++++++------ compiler/rustc_hir_typeck/src/callee.rs | 4 +++- compiler/rustc_hir_typeck/src/writeback.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 7 ++++--- compiler/rustc_mir_build/src/build/mod.rs | 4 ++-- compiler/rustc_mir_transform/src/lib.rs | 2 +- compiler/rustc_passes/src/check_const.rs | 4 ++-- .../src/operators/arithmetic_side_effects.rs | 2 +- .../src/operators/numeric_arithmetic.rs | 2 +- tests/ui/inline-const/promotion.rs | 3 ++- tests/ui/inline-const/promotion.stderr | 14 ++++++++++++++ 15 files changed, 41 insertions(+), 23 deletions(-) create mode 100644 tests/ui/inline-const/promotion.stderr diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 3b5f1178db52..02b52784edec 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -580,7 +580,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } } - BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { + BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => { let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); if self.mir_def.to_def_id() == typeck_root_def_id { let args = diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index f288ddc25d3a..129e74425b6d 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -167,7 +167,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { false } - hir::ConstContext::Const | hir::ConstContext::Static(_) => { + hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => { let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx) .into_engine(ccx.tcx, &ccx.body) .iterate_to_fixpoint() diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index d79c65f1d1fe..81168c318023 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -644,7 +644,7 @@ impl<'tcx> Validator<'_, 'tcx> { // Everywhere else, we require `#[rustc_promotable]` on the callee. let promote_all_const_fn = matches!( self.const_kind, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { inline: false }) ); if !promote_all_const_fn { if let ty::FnDef(def_id, _) = *fn_ty.kind() { diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index a170e3a8943f..4f77f09b26ec 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -161,7 +161,7 @@ impl IntoDiagnosticArg for hir::ConstContext { DiagnosticArgValue::Str(Cow::Borrowed(match self { hir::ConstContext::ConstFn => "const_fn", hir::ConstContext::Static(_) => "static", - hir::ConstContext::Const => "const", + hir::ConstContext::Const { .. } => "const", })) } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index cb78da425970..0c4a0e5d4a5e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1581,8 +1581,8 @@ pub enum BodyOwnerKind { /// Closures Closure, - /// Constants and associated constants. - Const, + /// Constants and associated constants, also including inline constants. + Const { inline: bool }, /// Initializer of a `static` item. Static(Mutability), @@ -1592,7 +1592,7 @@ impl BodyOwnerKind { pub fn is_fn_or_closure(self) -> bool { match self { BodyOwnerKind::Fn | BodyOwnerKind::Closure => true, - BodyOwnerKind::Const | BodyOwnerKind::Static(_) => false, + BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false, } } } @@ -1615,7 +1615,7 @@ pub enum ConstContext { /// /// For the most part, other contexts are treated just like a regular `const`, so they are /// lumped into the same category. - Const, + Const { inline: bool }, } impl ConstContext { @@ -1624,7 +1624,7 @@ impl ConstContext { /// E.g. `const` or `static mut`. pub fn keyword_name(self) -> &'static str { match self { - Self::Const => "const", + Self::Const { .. } => "const", Self::Static(Mutability::Not) => "static", Self::Static(Mutability::Mut) => "static mut", Self::ConstFn => "const fn", @@ -1637,7 +1637,7 @@ impl ConstContext { impl fmt::Display for ConstContext { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - Self::Const => write!(f, "constant"), + Self::Const { .. } => write!(f, "constant"), Self::Static(_) => write!(f, "static"), Self::ConstFn => write!(f, "constant function"), } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index b39919ece714..f2c58ee27029 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -788,7 +788,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let effect = match const_context { _ if host_always_on => tcx.consts.true_, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_, + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => { + tcx.consts.false_ + } Some(hir::ConstContext::ConstFn) => { let args = ty::GenericArgs::identity_for_item(tcx, context); args.host_effect_param().expect("ConstContext::Maybe must have host effect param") diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 603681bbc994..2fe41c1197fd 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Type only exists for constants and statics, not functions. match self.tcx.hir().body_owner_kind(item_def_id) { - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => { + hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => { let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(item_def_id); wbcx.visit_node_id(body.value.span, item_hir_id); } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index f67f8015c040..3491c487f3e6 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -442,9 +442,10 @@ impl<'hir> Map<'hir> { /// Panics if `LocalDefId` does not have an associated body. pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind { match self.tcx.def_kind(def_id) { - DefKind::Const | DefKind::AssocConst | DefKind::InlineConst | DefKind::AnonConst => { - BodyOwnerKind::Const + DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => { + BodyOwnerKind::Const { inline: false } } + DefKind::InlineConst => BodyOwnerKind::Const { inline: true }, DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn, DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure, DefKind::Static(mt) => BodyOwnerKind::Static(mt), @@ -461,7 +462,7 @@ impl<'hir> Map<'hir> { /// just that it has to be checked as if it were. pub fn body_const_context(self, def_id: LocalDefId) -> Option { let ccx = match self.body_owner_kind(def_id) { - BodyOwnerKind::Const => ConstContext::Const, + BodyOwnerKind::Const { inline } => ConstContext::Const { inline }, BodyOwnerKind::Static(mt) => ConstContext::Static(mt), BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None, diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 7748ffab79cc..bba47056457d 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -633,7 +633,7 @@ fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Bo _ => bug!("expected closure or generator, found {ty:?}"), } } - hir::BodyOwnerKind::Const => 0, + hir::BodyOwnerKind::Const { .. } => 0, hir::BodyOwnerKind::Static(_) => 0, }; let mut cfg = CFG { basic_blocks: IndexVec::new() }; @@ -700,7 +700,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Constants always need overflow checks. check_overflow |= matches!( tcx.hir().body_owner_kind(def), - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) + hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) ); let lint_level = LintLevel::Explicit(hir_id); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 70d4ea74d1a7..c44192957b1a 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -343,7 +343,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { let body = match tcx.hir().body_const_context(def) { // consts and statics do not have `optimized_mir`, so we can steal the body instead of // cloning it. - Some(hir::ConstContext::Const | hir::ConstContext::Static(_)) => body.steal(), + Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => body.steal(), Some(hir::ConstContext::ConstFn) => body.borrow().clone(), None => bug!("`mir_for_ctfe` called on non-const {def:?}"), }; diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 8437e9a40e2a..6d176af80980 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -193,12 +193,12 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { } fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) { - let kind = Some(hir::ConstContext::Const); + let kind = Some(hir::ConstContext::Const { inline: false }); self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); } fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) { - let kind = Some(hir::ConstContext::Const); + let kind = Some(hir::ConstContext::Const { inline: true }); self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block)); } diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index 8072aded8513..a10aa65e5948 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -315,7 +315,7 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id()); let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id); - if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind { + if let hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) = body_owner_kind { let body_span = cx.tcx.hir().span_with_body(body_owner); if let Some(span) = self.const_span && span.contains(body_span) { return; diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index 102845ceed09..80389cbf84be 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -72,7 +72,7 @@ impl Context { let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id()); match cx.tcx.hir().body_owner_kind(body_owner_def_id) { - hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => { + hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const { .. } => { let body_span = cx.tcx.hir().span_with_body(body_owner); if let Some(span) = self.const_span { diff --git a/tests/ui/inline-const/promotion.rs b/tests/ui/inline-const/promotion.rs index e211f46acf9b..242959c6b516 100644 --- a/tests/ui/inline-const/promotion.rs +++ b/tests/ui/inline-const/promotion.rs @@ -1,8 +1,8 @@ #![feature(inline_const)] #![allow(arithmetic_overflow, unconditional_panic)] -// check-pass // The only way to have promoteds that fail is in `const fn` called from `const`/`static`. +// Make sure that in a `const` block, we do not promote such calls. const fn div_by_zero() -> i32 { 1 / 0 } @@ -15,6 +15,7 @@ fn main() { let v = const { if mk_false() { let _x: &'static i32 = &div_by_zero(); + //~^ ERROR: temporary value dropped while borrowed } 42 }; diff --git a/tests/ui/inline-const/promotion.stderr b/tests/ui/inline-const/promotion.stderr new file mode 100644 index 000000000000..795fc8f5921a --- /dev/null +++ b/tests/ui/inline-const/promotion.stderr @@ -0,0 +1,14 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promotion.rs:17:37 + | +LL | let _x: &'static i32 = &div_by_zero(); + | ------------ ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. From 1806efe7f2757c5fbcf99d1ac9ca2d26fb0a7c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 15 Sep 2023 15:39:11 +0200 Subject: [PATCH 19/26] Move `DepKind` to `rustc_query_system` and define it as `u16` --- .../rustc_incremental/src/assert_dep_graph.rs | 4 +- .../rustc_incremental/src/persist/load.rs | 4 +- compiler/rustc_interface/src/callbacks.rs | 43 ++++- .../src/rmeta/decoder/cstore_impl.rs | 4 +- .../rustc_middle/src/dep_graph/dep_node.rs | 81 +++------ compiler/rustc_middle/src/dep_graph/mod.rs | 64 ++----- compiler/rustc_middle/src/query/mod.rs | 1 - compiler/rustc_middle/src/query/plumbing.rs | 8 +- compiler/rustc_middle/src/values.rs | 72 +++----- compiler/rustc_query_impl/src/lib.rs | 6 +- compiler/rustc_query_impl/src/plumbing.rs | 37 ++-- .../rustc_query_system/src/dep_graph/debug.rs | 14 +- .../src/dep_graph/dep_node.rs | 92 ++++++++-- .../rustc_query_system/src/dep_graph/graph.rs | 163 +++++++++--------- .../rustc_query_system/src/dep_graph/mod.rs | 84 ++++----- .../rustc_query_system/src/dep_graph/query.rs | 22 +-- .../src/dep_graph/serialized.rs | 107 ++++++------ .../rustc_query_system/src/query/config.rs | 10 +- compiler/rustc_query_system/src/query/job.rs | 113 ++++++------ compiler/rustc_query_system/src/query/mod.rs | 10 +- .../rustc_query_system/src/query/plumbing.rs | 70 ++++---- compiler/rustc_query_system/src/values.rs | 10 +- .../src/solve/search_graph/mod.rs | 4 +- .../src/traits/select/mod.rs | 5 +- 24 files changed, 509 insertions(+), 519 deletions(-) diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 5e7ae3ecdb85..1b160eca92db 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -42,7 +42,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::dep_graph::{ - DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter, + dep_kinds, DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter, }; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; @@ -129,7 +129,7 @@ impl<'tcx> IfThisChanged<'tcx> { let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { None => { - DepNode::from_def_path_hash(self.tcx, def_path_hash, DepKind::hir_owner) + DepNode::from_def_path_hash(self.tcx, def_path_hash, dep_kinds::hir_owner) } Some(n) => { match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 8d67f6925687..25e694fa1c15 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -3,7 +3,7 @@ use crate::errors; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::unord::UnordMap; -use rustc_middle::dep_graph::{SerializedDepGraph, WorkProductMap}; +use rustc_middle::dep_graph::{DepsType, SerializedDepGraph, WorkProductMap}; use rustc_middle::query::on_disk_cache::OnDiskCache; use rustc_serialize::opaque::MemDecoder; use rustc_serialize::Decodable; @@ -208,7 +208,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { return LoadResult::DataOutOfDate; } - let dep_graph = SerializedDepGraph::decode(&mut decoder); + let dep_graph = SerializedDepGraph::decode::(&mut decoder); LoadResult::Ok { data: (dep_graph, prev_work_products) } } diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index bc6d7c209971..45b1aeb4a5c3 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -10,8 +10,10 @@ //! origin crate when the `TyCtxt` is not present in TLS. use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS}; -use rustc_middle::dep_graph::TaskDepsRef; +use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef}; use rustc_middle::ty::tls; +use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug; +use rustc_query_system::dep_graph::{DepContext, DepKind, DepNode}; use std::fmt; fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { @@ -59,10 +61,49 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> write!(f, ")") } +/// This is a callback from `rustc_query_system` as it cannot access the implicit state +/// in `rustc_middle` otherwise. +pub fn dep_kind_debug(kind: DepKind, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + write!(f, "{}", tcx.dep_kind_info(kind).name) + } else { + default_dep_kind_debug(kind, f) + } + }) +} + +/// This is a callback from `rustc_query_system` as it cannot access the implicit state +/// in `rustc_middle` otherwise. +pub fn dep_node_debug(node: DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}(", node.kind)?; + + tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_id) = node.extract_def_id(tcx) { + write!(f, "{}", tcx.def_path_debug_str(def_id))?; + } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(node) { + write!(f, "{s}")?; + } else { + write!(f, "{}", node.hash)?; + } + } else { + write!(f, "{}", node.hash)?; + } + Ok(()) + })?; + + write!(f, ")") +} + /// Sets up the callbacks in prior crates which we want to refer to the /// TyCtxt in. pub fn setup_callbacks() { rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_))); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + rustc_query_system::dep_graph::dep_node::DEP_KIND_DEBUG + .swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG + .swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _)); } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index f964a8c76c06..e8c2fe5d1780 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -126,8 +126,8 @@ macro_rules! provide_one { // External query providers call `crate_hash` in order to register a dependency // on the crate metadata. The exception is `crate_hash` itself, which obviously // doesn't need to do this (and can't, as it would cause a query cycle). - use rustc_middle::dep_graph::DepKind; - if DepKind::$name != DepKind::crate_hash && $tcx.dep_graph.is_fully_enabled() { + use rustc_middle::dep_graph::dep_kinds; + if dep_kinds::$name != dep_kinds::crate_hash && $tcx.dep_graph.is_fully_enabled() { $tcx.ensure().crate_hash($def_id.krate); } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 78a0f82db132..39d82c489d53 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -65,9 +65,9 @@ use rustc_hir::definitions::DefPathHash; use rustc_hir::{HirId, ItemLocalId, OwnerId}; use rustc_query_system::dep_graph::FingerprintStyle; use rustc_span::symbol::Symbol; -use std::hash::Hash; -pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; +pub use rustc_query_system::dep_graph::dep_node::DepKind; +pub use rustc_query_system::dep_graph::{DepContext, DepNode, DepNodeParams}; macro_rules! define_dep_nodes { ( @@ -84,55 +84,39 @@ macro_rules! define_dep_nodes { // encoding. The derived Encodable/Decodable uses leb128 encoding which is // dense when only considering this enum. But DepKind is encoded in a larger // struct, and there we can take advantage of the unused bits in the u16. - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[allow(non_camel_case_types)] - #[repr(u16)] - pub enum DepKind { + #[repr(u16)] // Must be kept in sync with the inner type of `DepKind`. + enum DepKindDefs { $( $( #[$attr] )* $variant),* } - impl DepKind { - // This const implements two things: A bounds check so that we can decode - // a DepKind from a u16 with just one check, and a const check that the - // discriminants of the variants have been assigned consecutively from 0 - // so that just the one comparison suffices to check that the u16 can be - // transmuted to a DepKind. - pub const VARIANTS: u16 = { - let deps: &[DepKind] = &[$(DepKind::$variant,)*]; - let mut i = 0; - while i < deps.len() { - if i as u16 != deps[i] as u16 { - panic!(); - } - i += 1; - } - deps.len() as u16 - }; + #[allow(non_upper_case_globals)] + pub mod dep_kinds { + use super::*; + + $( + // The `as u16` cast must be kept in sync with the inner type of `DepKind`. + pub const $variant: DepKind = DepKind::new(DepKindDefs::$variant as u16); + )* } - impl rustc_serialize::Encodable for DepKind { - #[inline] - fn encode(&self, s: &mut S) { - s.emit_u16(*self as u16); - } - } - - impl rustc_serialize::Decodable for DepKind { - #[inline] - fn decode(d: &mut D) -> DepKind { - let discrim = d.read_u16(); - assert!(discrim < DepKind::VARIANTS); - // SAFETY: DepKind::VARIANTS checks that the discriminant values permit - // this one check to soundly guard the transmute. - unsafe { - std::mem::transmute::(discrim) + // This checks that the discriminants of the variants have been assigned consecutively + // from 0 so that they can be used as a dense index. + pub const DEP_KIND_VARIANTS: u16 = { + let deps = &[$(dep_kinds::$variant,)*]; + let mut i = 0; + while i < deps.len() { + if i != deps[i].as_usize() { + panic!(); } + i += 1; } - } + deps.len() as u16 + }; pub(super) fn dep_kind_from_label_string(label: &str) -> Result { match label { - $(stringify!($variant) => Ok(DepKind::$variant),)* + $(stringify!($variant) => Ok(dep_kinds::$variant),)* _ => Err(()), } } @@ -158,12 +142,10 @@ rustc_query_append!(define_dep_nodes![ [] fn CompileMonoItem() -> (), ]); -static_assert_size!(DepKind, 2); - // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. // Be very careful changing this type signature! pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode { - DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name) + DepNode::construct(tcx, dep_kinds::CompileCodegenUnit, &name) } // WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys. @@ -172,20 +154,9 @@ pub(crate) fn make_compile_mono_item<'tcx>( tcx: TyCtxt<'tcx>, mono_item: &MonoItem<'tcx>, ) -> DepNode { - DepNode::construct(tcx, DepKind::CompileMonoItem, mono_item) + DepNode::construct(tcx, dep_kinds::CompileMonoItem, mono_item) } -pub type DepNode = rustc_query_system::dep_graph::DepNode; - -// We keep a lot of `DepNode`s in memory during compilation. It's not -// required that their size stay the same, but we don't want to change -// it inadvertently. This assert just ensures we're aware of any change. -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -static_assert_size!(DepNode, 18); - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -static_assert_size!(DepNode, 24); - pub trait DepNodeExt: Sized { /// Extracts the DefId corresponding to this DepNode. This will work /// if two conditions are met: diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 87436f9eeed8..76ef62f9f272 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -6,49 +6,24 @@ use rustc_session::Session; #[macro_use] mod dep_node; +pub use rustc_query_system::dep_graph::debug::EdgeFilter; pub use rustc_query_system::dep_graph::{ - debug::DepNodeFilter, hash_result, DepContext, DepNodeColor, DepNodeIndex, - SerializedDepNodeIndex, WorkProduct, WorkProductId, WorkProductMap, + debug::DepNodeFilter, hash_result, DepContext, DepGraphQuery, DepNodeColor, DepNodeIndex, Deps, + SerializedDepGraph, SerializedDepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct, WorkProductId, + WorkProductMap, }; -pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt}; +pub use dep_node::{dep_kinds, label_strs, DepKind, DepNode, DepNodeExt}; pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; -pub type DepGraph = rustc_query_system::dep_graph::DepGraph; +pub type DepGraph = rustc_query_system::dep_graph::DepGraph; -pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps; -pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>; -pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery; -pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph; -pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter; pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct>; -impl rustc_query_system::dep_graph::DepKind for DepKind { - const NULL: Self = DepKind::Null; - const RED: Self = DepKind::Red; - const MAX: u16 = DepKind::VARIANTS - 1; - - fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}(", node.kind)?; - - ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - if let Some(def_id) = node.extract_def_id(tcx) { - write!(f, "{}", tcx.def_path_debug_str(def_id))?; - } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) { - write!(f, "{s}")?; - } else { - write!(f, "{}", node.hash)?; - } - } else { - write!(f, "{}", node.hash)?; - } - Ok(()) - })?; - - write!(f, ")") - } +#[derive(Clone)] +pub struct DepsType; +impl Deps for DepsType { fn with_deps(task_deps: TaskDepsRef<'_>, op: OP) -> R where OP: FnOnce() -> R, @@ -70,24 +45,13 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { }) } - #[track_caller] - #[inline] - fn from_u16(u: u16) -> Self { - if u > Self::MAX { - panic!("Invalid DepKind {u}"); - } - // SAFETY: See comment on DepKind::VARIANTS - unsafe { std::mem::transmute(u) } - } - - #[inline] - fn to_u16(self) -> u16 { - self as u16 - } + const DEP_KIND_NULL: DepKind = dep_kinds::Null; + const DEP_KIND_RED: DepKind = dep_kinds::Red; + const DEP_KIND_MAX: u16 = dep_node::DEP_KIND_VARIANTS - 1; } impl<'tcx> DepContext for TyCtxt<'tcx> { - type DepKind = DepKind; + type Deps = DepsType; #[inline] fn with_stable_hashing_context(self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R { @@ -111,6 +75,6 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { #[inline] fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> { - &self.query_kinds[dk as usize] + &self.query_kinds[dk.as_usize()] } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0241820ab722..0238d27e9d82 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -7,7 +7,6 @@ #![allow(unused_parens)] use crate::dep_graph; -use crate::dep_graph::DepKind; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintExpectation; use crate::metadata::ModChild; diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index a342b5231e9a..34e5b02ba5be 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -37,7 +37,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> { pub eval_always: bool, pub dep_kind: DepKind, pub handle_cycle_error: HandleCycleError, - pub query_state: FieldOffset, QueryState>, + pub query_state: FieldOffset, QueryState>, pub query_cache: FieldOffset, C>, pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool, pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value, @@ -53,7 +53,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> { fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool, pub hash_result: HashResult, pub value_from_cycle_error: - fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> C::Value, + fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> C::Value, pub format_value: fn(&C::Value) -> String, } @@ -402,7 +402,7 @@ macro_rules! define_callbacks { #[derive(Default)] pub struct QueryStates<'tcx> { $( - pub $name: QueryState<$($K)*, DepKind>, + pub $name: QueryState<$($K)*>, )* } @@ -516,7 +516,7 @@ macro_rules! define_feedable { } } None => { - let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key); + let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::dep_kinds::$name, &key); let dep_node_index = tcx.dep_graph.with_feed_task( dep_node, tcx, diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 962faf56cb87..dec063633807 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::DepKind; +use crate::dep_graph::dep_kinds; use crate::query::plumbing::CyclePlaceholder; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; @@ -13,34 +13,22 @@ use rustc_span::{ErrorGuaranteed, Span}; use std::fmt::Write; -impl<'tcx> Value, DepKind> for Ty<'_> { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - _: &[QueryInfo], - guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value> for Ty<'_> { + fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { std::mem::transmute::, Ty<'_>>(Ty::new_error(tcx, guar)) } } } -impl<'tcx> Value, DepKind> for Result>, CyclePlaceholder> { - fn from_cycle_error( - _tcx: TyCtxt<'tcx>, - _: &[QueryInfo], - guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value> for Result>, CyclePlaceholder> { + fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self { Err(CyclePlaceholder(guar)) } } -impl<'tcx> Value, DepKind> for ty::SymbolName<'_> { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - _: &[QueryInfo], - _guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value> for ty::SymbolName<'_> { + fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], _guar: ErrorGuaranteed) -> Self { // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { @@ -51,16 +39,12 @@ impl<'tcx> Value, DepKind> for ty::SymbolName<'_> { } } -impl<'tcx> Value, DepKind> for ty::Binder<'_, ty::FnSig<'_>> { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - stack: &[QueryInfo], - guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { + fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo], guar: ErrorGuaranteed) -> Self { let err = Ty::new_error(tcx, guar); let arity = if let Some(frame) = stack.get(0) - && frame.query.dep_kind == DepKind::fn_sig + && frame.query.dep_kind == dep_kinds::fn_sig && let Some(def_id) = frame.query.def_id && let Some(node) = tcx.hir().get_if_local(def_id) && let Some(sig) = node.fn_sig() @@ -85,16 +69,12 @@ impl<'tcx> Value, DepKind> for ty::Binder<'_, ty::FnSig<'_>> { } } -impl<'tcx> Value, DepKind> for Representability { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo], - _guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value> for Representability { + fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self { let mut item_and_field_ids = Vec::new(); let mut representable_ids = FxHashSet::default(); for info in cycle { - if info.query.dep_kind == DepKind::representability + if info.query.dep_kind == dep_kinds::representability && let Some(field_id) = info.query.def_id && let Some(field_id) = field_id.as_local() && let Some(DefKind::Field) = info.query.def_kind @@ -108,7 +88,7 @@ impl<'tcx> Value, DepKind> for Representability { } } for info in cycle { - if info.query.dep_kind == DepKind::representability_adt_ty + if info.query.dep_kind == dep_kinds::representability_adt_ty && let Some(def_id) = info.query.ty_adt_id && let Some(def_id) = def_id.as_local() && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) @@ -121,32 +101,20 @@ impl<'tcx> Value, DepKind> for Representability { } } -impl<'tcx> Value, DepKind> for ty::EarlyBinder> { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo], - guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value> for ty::EarlyBinder> { + fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self { ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle, guar)) } } -impl<'tcx> Value, DepKind> for ty::EarlyBinder>> { - fn from_cycle_error( - tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo], - guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx> Value> for ty::EarlyBinder>> { + fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self { ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle, guar)) } } -impl<'tcx, T> Value, DepKind> for Result> { - fn from_cycle_error( - _tcx: TyCtxt<'tcx>, - _cycle: &[QueryInfo], - _guar: ErrorGuaranteed, - ) -> Self { +impl<'tcx, T> Value> for Result> { + fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self { // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really, // tcx.arena.alloc is pretty much equal to leaking). diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 9a0fcbb37a72..30621a135ebc 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -92,7 +92,7 @@ where } #[inline(always)] - fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState + fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState where QueryCtxt<'tcx>: 'a, { @@ -145,7 +145,7 @@ where fn value_from_cycle_error( self, tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo], + cycle: &[QueryInfo], guar: ErrorGuaranteed, ) -> Self::Value { (self.dynamic.value_from_cycle_error)(tcx, cycle, guar) @@ -198,6 +198,8 @@ trait QueryConfigRestored<'tcx> { type RestoredValue; type Config: QueryConfig>; + const NAME: &'static &'static str; + fn config(tcx: TyCtxt<'tcx>) -> Self::Config; fn restore(value: >>::Value) -> Self::RestoredValue; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index f2fdf066d15c..4516708ce17c 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -8,7 +8,9 @@ use crate::QueryConfigRestored; use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_data_structures::sync::Lock; use rustc_errors::Diagnostic; + use rustc_index::Idx; +use rustc_middle::dep_graph::dep_kinds; use rustc_middle::dep_graph::{ self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex, }; @@ -53,7 +55,7 @@ impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> { } impl<'tcx> HasDepContext for QueryCtxt<'tcx> { - type DepKind = rustc_middle::dep_graph::DepKind; + type Deps = rustc_middle::dep_graph::DepsType; type DepContext = TyCtxt<'tcx>; #[inline] @@ -78,7 +80,7 @@ impl QueryContext for QueryCtxt<'_> { tls::with_related_context(self.tcx, |icx| icx.query) } - fn try_collect_active_jobs(self) -> Option> { + fn try_collect_active_jobs(self) -> Option { let mut jobs = QueryMap::default(); for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() { @@ -154,7 +156,7 @@ impl QueryContext for QueryCtxt<'_> { let mut span = None; let mut layout_of_depth = None; if let Some(map) = self.try_collect_active_jobs() { - if let Some((info, depth)) = job.try_find_layout_root(map) { + if let Some((info, depth)) = job.try_find_layout_root(map, dep_kinds::layout_of) { span = Some(info.job.span); layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth }); } @@ -300,7 +302,7 @@ pub(crate) fn create_query_frame< key: K, kind: DepKind, name: &'static str, -) -> QueryStackFrame { +) -> QueryStackFrame { // Avoid calling queries while formatting the description let description = ty::print::with_no_queries!( // Disable visible paths printing for performance reasons. @@ -312,7 +314,7 @@ pub(crate) fn create_query_frame< ); let description = if tcx.sess.verbose() { format!("{description} [{name:?}]") } else { description }; - let span = if kind == dep_graph::DepKind::def_span || with_no_queries() { + let span = if kind == dep_graph::dep_kinds::def_span || with_no_queries() { // The `def_span` query is used to calculate `default_span`, // so exit to avoid infinite recursion. None @@ -320,7 +322,7 @@ pub(crate) fn create_query_frame< Some(key.default_span(tcx)) }; let def_id = key.key_as_def_id(); - let def_kind = if kind == dep_graph::DepKind::opt_def_kind || with_no_queries() { + let def_kind = if kind == dep_graph::dep_kinds::opt_def_kind || with_no_queries() { // Try to avoid infinite recursion. None } else { @@ -329,7 +331,7 @@ pub(crate) fn create_query_frame< let hash = || { tcx.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); - std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher); + kind.as_usize().hash_stable(&mut hcx, &mut hasher); key.hash_stable(&mut hcx, &mut hasher); hasher.finish::() }) @@ -430,8 +432,8 @@ where // hit the cache instead of having to go through `force_from_dep_node`. // This assertion makes sure, we actually keep applying the solution above. debug_assert!( - dep_node.kind != DepKind::codegen_unit, - "calling force_from_dep_node() on DepKind::codegen_unit" + dep_node.kind != dep_kinds::codegen_unit, + "calling force_from_dep_node() on dep_kinds::codegen_unit" ); if let Some(key) = Q::Key::recover(tcx, &dep_node) { @@ -457,6 +459,7 @@ where fingerprint_style, force_from_dep_node: None, try_load_from_on_disk_cache: None, + name: Q::NAME, }; } @@ -470,6 +473,7 @@ where try_load_from_on_disk_cache: Some(|tcx, dep_node| { try_load_from_on_disk_cache(Q::config(tcx), tcx, dep_node) }), + name: Q::NAME, } } @@ -565,7 +569,7 @@ macro_rules! define_queries { DynamicQuery { name: stringify!($name), eval_always: is_eval_always!([$($modifiers)*]), - dep_kind: dep_graph::DepKind::$name, + dep_kind: dep_graph::dep_kinds::$name, handle_cycle_error: handle_cycle_error!([$($modifiers)*]), query_state: offset_of!(QueryStates<'tcx> => $name), query_cache: offset_of!(QueryCaches<'tcx> => $name), @@ -636,6 +640,8 @@ macro_rules! define_queries { { feedable!([$($modifiers)*]) }, >; + const NAME: &'static &'static str = &stringify!($name); + #[inline(always)] fn config(tcx: TyCtxt<'tcx>) -> Self::Config { DynamicConfig { @@ -649,9 +655,9 @@ macro_rules! define_queries { } } - pub fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap) { + pub fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap) { let make_query = |tcx, key| { - let kind = rustc_middle::dep_graph::DepKind::$name; + let kind = rustc_middle::dep_graph::dep_kinds::$name; let name = stringify!($name); $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name) }; @@ -709,7 +715,7 @@ macro_rules! define_queries { // These arrays are used for iteration and can't be indexed by `DepKind`. - const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap)] = + const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap)] = &[$(query_impl::$name::try_collect_active_jobs),*]; const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[ @@ -737,6 +743,7 @@ macro_rules! define_queries { fingerprint_style: FingerprintStyle::Unit, force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)), try_load_from_on_disk_cache: None, + name: &"Null", } } @@ -748,6 +755,7 @@ macro_rules! define_queries { fingerprint_style: FingerprintStyle::Unit, force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)), try_load_from_on_disk_cache: None, + name: &"Red", } } @@ -758,6 +766,7 @@ macro_rules! define_queries { fingerprint_style: FingerprintStyle::Unit, force_from_dep_node: None, try_load_from_on_disk_cache: None, + name: &"TraitSelect", } } @@ -768,6 +777,7 @@ macro_rules! define_queries { fingerprint_style: FingerprintStyle::Opaque, force_from_dep_node: None, try_load_from_on_disk_cache: None, + name: &"CompileCodegenUnit", } } @@ -778,6 +788,7 @@ macro_rules! define_queries { fingerprint_style: FingerprintStyle::Opaque, force_from_dep_node: None, try_load_from_on_disk_cache: None, + name: &"CompileMonoItem", } } diff --git a/compiler/rustc_query_system/src/dep_graph/debug.rs b/compiler/rustc_query_system/src/dep_graph/debug.rs index c2c9600f5552..103a6c01bd27 100644 --- a/compiler/rustc_query_system/src/dep_graph/debug.rs +++ b/compiler/rustc_query_system/src/dep_graph/debug.rs @@ -1,6 +1,6 @@ //! Code for debugging the dep-graph. -use super::{DepKind, DepNode, DepNodeIndex}; +use super::{DepNode, DepNodeIndex}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lock; use std::error::Error; @@ -28,7 +28,7 @@ impl DepNodeFilter { } /// Tests whether `node` meets the filter, returning true if so. - pub fn test(&self, node: &DepNode) -> bool { + pub fn test(&self, node: &DepNode) -> bool { let debug_str = format!("{node:?}"); self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f)) } @@ -36,14 +36,14 @@ impl DepNodeFilter { /// A filter like `F -> G` where `F` and `G` are valid dep-node /// filters. This can be used to test the source/target independently. -pub struct EdgeFilter { +pub struct EdgeFilter { pub source: DepNodeFilter, pub target: DepNodeFilter, - pub index_to_node: Lock>>, + pub index_to_node: Lock>, } -impl EdgeFilter { - pub fn new(test: &str) -> Result, Box> { +impl EdgeFilter { + pub fn new(test: &str) -> Result> { let parts: Vec<_> = test.split("->").collect(); if parts.len() != 2 { Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into()) @@ -57,7 +57,7 @@ impl EdgeFilter { } #[cfg(debug_assertions)] - pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { + pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { self.source.test(source) && self.target.test(target) } } diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index 39a4cb1b179b..17f96896a504 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -42,36 +42,84 @@ //! `DefId` it was computed from. In other cases, too much information gets //! lost during fingerprint computation. -use super::{DepContext, DepKind, FingerprintStyle}; +use super::{DepContext, FingerprintStyle}; use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey}; +use rustc_data_structures::AtomicRef; use rustc_hir::definitions::DefPathHash; use std::fmt; use std::hash::Hash; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] -pub struct DepNode { - pub kind: K, +/// This serves as an index into arrays built by `make_dep_kind_array`. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct DepKind { + variant: u16, +} + +impl DepKind { + #[inline] + pub const fn new(variant: u16) -> Self { + Self { variant } + } + + #[inline] + pub const fn as_inner(&self) -> u16 { + self.variant + } + + #[inline] + pub const fn as_usize(&self) -> usize { + self.variant as usize + } +} + +static_assert_size!(DepKind, 2); + +pub fn default_dep_kind_debug(kind: DepKind, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DepKind").field("variant", &kind.variant).finish() +} + +pub static DEP_KIND_DEBUG: AtomicRef) -> fmt::Result> = + AtomicRef::new(&(default_dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + +impl fmt::Debug for DepKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (*DEP_KIND_DEBUG)(*self, f) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct DepNode { + pub kind: DepKind, pub hash: PackedFingerprint, } -impl DepNode { +// We keep a lot of `DepNode`s in memory during compilation. It's not +// required that their size stay the same, but we don't want to change +// it inadvertently. This assert just ensures we're aware of any change. +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +static_assert_size!(DepNode, 18); + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +static_assert_size!(DepNode, 24); + +impl DepNode { /// Creates a new, parameterless DepNode. This method will assert /// that the DepNode corresponding to the given DepKind actually /// does not require any parameters. - pub fn new_no_params(tcx: Tcx, kind: K) -> DepNode + pub fn new_no_params(tcx: Tcx, kind: DepKind) -> DepNode where - Tcx: super::DepContext, + Tcx: super::DepContext, { debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit); DepNode { kind, hash: Fingerprint::ZERO.into() } } - pub fn construct(tcx: Tcx, kind: K, arg: &Key) -> DepNode + pub fn construct(tcx: Tcx, kind: DepKind, arg: &Key) -> DepNode where - Tcx: super::DepContext, + Tcx: super::DepContext, Key: DepNodeParams, { let hash = arg.to_fingerprint(tcx); @@ -93,18 +141,25 @@ impl DepNode { /// Construct a DepNode from the given DepKind and DefPathHash. This /// method will assert that the given DepKind actually requires a /// single DefId/DefPathHash parameter. - pub fn from_def_path_hash(tcx: Tcx, def_path_hash: DefPathHash, kind: K) -> Self + pub fn from_def_path_hash(tcx: Tcx, def_path_hash: DefPathHash, kind: DepKind) -> Self where - Tcx: super::DepContext, + Tcx: super::DepContext, { debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash); DepNode { kind, hash: def_path_hash.0.into() } } } -impl fmt::Debug for DepNode { +pub fn default_dep_node_debug(node: DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DepNode").field("kind", &node.kind).field("hash", &node.hash).finish() +} + +pub static DEP_NODE_DEBUG: AtomicRef) -> fmt::Result> = + AtomicRef::new(&(default_dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + +impl fmt::Debug for DepNode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - K::debug_node(self, f) + (*DEP_NODE_DEBUG)(*self, f) } } @@ -129,7 +184,7 @@ pub trait DepNodeParams: fmt::Debug + Sized { /// `fingerprint_style()` is not `FingerprintStyle::Opaque`. /// It is always valid to return `None` here, in which case incremental /// compilation will treat the query as having changed instead of forcing it. - fn recover(tcx: Tcx, dep_node: &DepNode) -> Option; + fn recover(tcx: Tcx, dep_node: &DepNode) -> Option; } impl DepNodeParams for T @@ -156,7 +211,7 @@ where } #[inline(always)] - default fn recover(_: Tcx, _: &DepNode) -> Option { + default fn recover(_: Tcx, _: &DepNode) -> Option { None } } @@ -216,10 +271,13 @@ pub struct DepKindStruct { /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` /// is actually a `DefPathHash`, and can therefore just look up the corresponding /// `DefId` in `tcx.def_path_hash_to_def_id`. - pub force_from_dep_node: Option) -> bool>, + pub force_from_dep_node: Option bool>, /// Invoke a query to put the on-disk cached value in memory. - pub try_load_from_on_disk_cache: Option)>, + pub try_load_from_on_disk_cache: Option, + + /// The name of this dep kind. + pub name: &'static &'static str, } /// A "work product" corresponds to a `.o` (or other) file that we diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index fa54e1a2e6a7..c7e92d7b2b22 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -17,7 +17,7 @@ use std::sync::atomic::Ordering::Relaxed; use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; -use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId}; +use super::{DepContext, DepKind, DepNode, Deps, HasDepContext, WorkProductId}; use crate::dep_graph::EdgesVec; use crate::ich::StableHashingContext; use crate::query::{QueryContext, QuerySideEffects}; @@ -26,8 +26,8 @@ use crate::query::{QueryContext, QuerySideEffects}; use {super::debug::EdgeFilter, std::env}; #[derive(Clone)] -pub struct DepGraph { - data: Option>>, +pub struct DepGraph { + data: Option>>, /// This field is used for assigning DepNodeIndices when running in /// non-incremental mode. Even in non-incremental mode we make sure that @@ -74,16 +74,16 @@ impl DepNodeColor { } } -pub struct DepGraphData { +pub struct DepGraphData { /// The new encoding of the dependency graph, optimized for red/green /// tracking. The `current` field is the dependency graph of only the /// current compilation session: We don't merge the previous dep-graph into /// current one anymore, but we do reference shared data to save space. - current: CurrentDepGraph, + current: CurrentDepGraph, /// The dep-graph from the previous compilation session. It contains all /// nodes and edges as well as all fingerprints of nodes that have them. - previous: SerializedDepGraph, + previous: SerializedDepGraph, colors: DepNodeColorMap, @@ -95,12 +95,12 @@ pub struct DepGraphData { /// this map. We can later look for and extract that data. previous_work_products: WorkProductMap, - dep_node_debug: Lock, String>>, + dep_node_debug: Lock>, /// Used by incremental compilation tests to assert that /// a particular query result was decoded from disk /// (not just marked green) - debug_loaded_from_disk: Lock>>, + debug_loaded_from_disk: Lock>, } pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint @@ -112,15 +112,15 @@ where stable_hasher.finish() } -impl DepGraph { +impl DepGraph { pub fn new( profiler: &SelfProfilerRef, - prev_graph: SerializedDepGraph, + prev_graph: SerializedDepGraph, prev_work_products: WorkProductMap, encoder: FileEncoder, record_graph: bool, record_stats: bool, - ) -> DepGraph { + ) -> DepGraph { let prev_graph_node_count = prev_graph.node_count(); let current = CurrentDepGraph::new( @@ -136,7 +136,7 @@ impl DepGraph { // Instantiate a dependy-less node only once for anonymous queries. let _green_node_index = current.intern_new_node( profiler, - DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() }, + DepNode { kind: D::DEP_KIND_NULL, hash: current.anon_id_seed.into() }, EdgesVec::new(), Fingerprint::ZERO, ); @@ -146,7 +146,7 @@ impl DepGraph { let (red_node_index, red_node_prev_index_and_color) = current.intern_node( profiler, &prev_graph, - DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() }, + DepNode { kind: D::DEP_KIND_RED, hash: Fingerprint::ZERO.into() }, EdgesVec::new(), None, false, @@ -181,12 +181,12 @@ impl DepGraph { } } - pub fn new_disabled() -> DepGraph { + pub fn new_disabled() -> DepGraph { DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) } } #[inline] - pub fn data(&self) -> Option<&DepGraphData> { + pub fn data(&self) -> Option<&DepGraphData> { self.data.as_deref() } @@ -196,7 +196,7 @@ impl DepGraph { self.data.is_some() } - pub fn with_query(&self, f: impl Fn(&DepGraphQuery)) { + pub fn with_query(&self, f: impl Fn(&DepGraphQuery)) { if let Some(data) = &self.data { data.current.encoder.borrow().with_query(f) } @@ -204,7 +204,7 @@ impl DepGraph { pub fn assert_ignored(&self) { if let Some(..) = self.data { - K::read_deps(|task_deps| { + D::read_deps(|task_deps| { assert_matches!( task_deps, TaskDepsRef::Ignore, @@ -218,7 +218,7 @@ impl DepGraph { where OP: FnOnce() -> R, { - K::with_deps(TaskDepsRef::Ignore, op) + D::with_deps(TaskDepsRef::Ignore, op) } /// Used to wrap the deserialization of a query result from disk, @@ -271,13 +271,13 @@ impl DepGraph { where OP: FnOnce() -> R, { - K::with_deps(TaskDepsRef::Forbid, op) + D::with_deps(TaskDepsRef::Forbid, op) } #[inline(always)] - pub fn with_task, A: Debug, R>( + pub fn with_task, A: Debug, R>( &self, - key: DepNode, + key: DepNode, cx: Ctxt, arg: A, task: fn(Ctxt, A) -> R, @@ -289,10 +289,10 @@ impl DepGraph { } } - pub fn with_anon_task, OP, R>( + pub fn with_anon_task, OP, R>( &self, cx: Tcx, - dep_kind: K, + dep_kind: DepKind, op: OP, ) -> (R, DepNodeIndex) where @@ -305,7 +305,7 @@ impl DepGraph { } } -impl DepGraphData { +impl DepGraphData { /// Starts a new dep-graph task. Dep-graph tasks are specified /// using a free function (`task`) and **not** a closure -- this /// is intentional because we want to exercise tight control over @@ -334,9 +334,9 @@ impl DepGraphData { /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html #[inline(always)] - pub fn with_task, A: Debug, R>( + pub fn with_task, A: Debug, R>( &self, - key: DepNode, + key: DepNode, cx: Ctxt, arg: A, task: fn(Ctxt, A) -> R, @@ -354,7 +354,7 @@ impl DepGraphData { - dep-node: {key:?}" ); - let with_deps = |task_deps| K::with_deps(task_deps, || task(cx, arg)); + let with_deps = |task_deps| D::with_deps(task_deps, || task(cx, arg)); let (result, edges) = if cx.dep_context().is_eval_always(key.kind) { (with_deps(TaskDepsRef::EvalAlways), EdgesVec::new()) } else { @@ -402,10 +402,10 @@ impl DepGraphData { /// Executes something within an "anonymous" task, that is, a task the /// `DepNode` of which is determined by the list of inputs it read from. - pub fn with_anon_task, OP, R>( + pub fn with_anon_task, OP, R>( &self, cx: Tcx, - dep_kind: K, + dep_kind: DepKind, op: OP, ) -> (R, DepNodeIndex) where @@ -414,7 +414,7 @@ impl DepGraphData { debug_assert!(!cx.is_eval_always(dep_kind)); let task_deps = Lock::new(TaskDeps::default()); - let result = K::with_deps(TaskDepsRef::Allow(&task_deps), op); + let result = D::with_deps(TaskDepsRef::Allow(&task_deps), op); let task_deps = task_deps.into_inner(); let task_deps = task_deps.reads; @@ -461,11 +461,11 @@ impl DepGraphData { } } -impl DepGraph { +impl DepGraph { #[inline] pub fn read_index(&self, dep_node_index: DepNodeIndex) { if let Some(ref data) = self.data { - K::read_deps(|task_deps| { + D::read_deps(|task_deps| { let mut task_deps = match task_deps { TaskDepsRef::Allow(deps) => deps.lock(), TaskDepsRef::EvalAlways => { @@ -532,9 +532,9 @@ impl DepGraph { /// FIXME: If the code is changed enough for this node to be marked before requiring the /// caller's node, we suppose that those changes will be enough to mark this node red and /// force a recomputation using the "normal" way. - pub fn with_feed_task, A: Debug, R: Debug>( + pub fn with_feed_task, A: Debug, R: Debug>( &self, - node: DepNode, + node: DepNode, cx: Ctxt, key: A, result: &R, @@ -573,7 +573,7 @@ impl DepGraph { } let mut edges = EdgesVec::new(); - K::read_deps(|task_deps| match task_deps { + D::read_deps(|task_deps| match task_deps { TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()), TaskDepsRef::EvalAlways => { edges.push(DepNodeIndex::FOREVER_RED_NODE); @@ -623,9 +623,9 @@ impl DepGraph { } } -impl DepGraphData { +impl DepGraphData { #[inline] - pub fn dep_node_index_of_opt(&self, dep_node: &DepNode) -> Option { + pub fn dep_node_index_of_opt(&self, dep_node: &DepNode) -> Option { if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) { self.current.prev_index_to_index.lock()[prev_index] } else { @@ -634,11 +634,11 @@ impl DepGraphData { } #[inline] - pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { + pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { self.dep_node_index_of_opt(dep_node).is_some() } - fn node_color(&self, dep_node: &DepNode) -> Option { + fn node_color(&self, dep_node: &DepNode) -> Option { if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) { self.colors.get(prev_index) } else { @@ -660,18 +660,18 @@ impl DepGraphData { } #[inline] - pub fn prev_node_of(&self, prev_index: SerializedDepNodeIndex) -> DepNode { + pub fn prev_node_of(&self, prev_index: SerializedDepNodeIndex) -> DepNode { self.previous.index_to_node(prev_index) } - pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode) { + pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode) { self.debug_loaded_from_disk.lock().insert(dep_node); } } -impl DepGraph { +impl DepGraph { #[inline] - pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { + pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { self.data.as_ref().is_some_and(|data| data.dep_node_exists(dep_node)) } @@ -687,12 +687,12 @@ impl DepGraph { &self.data.as_ref().unwrap().previous_work_products } - pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode) -> bool { + pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode) -> bool { self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node) } #[inline(always)] - pub fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str_gen: F) + pub fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str_gen: F) where F: FnOnce() -> String, { @@ -705,11 +705,11 @@ impl DepGraph { dep_node_debug.borrow_mut().insert(dep_node, debug_str); } - pub fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { + pub fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned() } - fn node_color(&self, dep_node: &DepNode) -> Option { + fn node_color(&self, dep_node: &DepNode) -> Option { if let Some(ref data) = self.data { return data.node_color(dep_node); } @@ -717,25 +717,25 @@ impl DepGraph { None } - pub fn try_mark_green>( + pub fn try_mark_green>( &self, qcx: Qcx, - dep_node: &DepNode, + dep_node: &DepNode, ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { self.data().and_then(|data| data.try_mark_green(qcx, dep_node)) } } -impl DepGraphData { +impl DepGraphData { /// Try to mark a node index for the node dep_node. /// /// A node will have an index, when it's already been marked green, or when we can mark it /// green. This function will mark the current task as a reader of the specified node, when /// a node index can be found for that node. - pub fn try_mark_green>( + pub fn try_mark_green>( &self, qcx: Qcx, - dep_node: &DepNode, + dep_node: &DepNode, ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind)); @@ -757,11 +757,11 @@ impl DepGraphData { } #[instrument(skip(self, qcx, parent_dep_node_index, frame), level = "debug")] - fn try_mark_parent_green>( + fn try_mark_parent_green>( &self, qcx: Qcx, parent_dep_node_index: SerializedDepNodeIndex, - dep_node: &DepNode, + dep_node: &DepNode, frame: Option<&MarkFrame<'_>>, ) -> Option<()> { let dep_dep_node_color = self.colors.get(parent_dep_node_index); @@ -845,11 +845,11 @@ impl DepGraphData { /// Try to mark a dep-node which existed in the previous compilation session as green. #[instrument(skip(self, qcx, prev_dep_node_index, frame), level = "debug")] - fn try_mark_previous_green>( + fn try_mark_previous_green>( &self, qcx: Qcx, prev_dep_node_index: SerializedDepNodeIndex, - dep_node: &DepNode, + dep_node: &DepNode, frame: Option<&MarkFrame<'_>>, ) -> Option { let frame = MarkFrame { index: prev_dep_node_index, parent: frame }; @@ -916,7 +916,7 @@ impl DepGraphData { /// This may be called concurrently on multiple threads for the same dep node. #[cold] #[inline(never)] - fn emit_side_effects>( + fn emit_side_effects>( &self, qcx: Qcx, dep_node_index: DepNodeIndex, @@ -940,16 +940,16 @@ impl DepGraphData { } } -impl DepGraph { +impl DepGraph { /// Returns true if the given node has been marked as red during the /// current compilation session. Used in various assertions - pub fn is_red(&self, dep_node: &DepNode) -> bool { + pub fn is_red(&self, dep_node: &DepNode) -> bool { self.node_color(dep_node) == Some(DepNodeColor::Red) } /// Returns true if the given node has been marked as green during the /// current compilation session. Used in various assertions - pub fn is_green(&self, dep_node: &DepNode) -> bool { + pub fn is_green(&self, dep_node: &DepNode) -> bool { self.node_color(dep_node).is_some_and(|c| c.is_green()) } @@ -961,7 +961,7 @@ impl DepGraph { /// /// This method will only load queries that will end up in the disk cache. /// Other queries will not be executed. - pub fn exec_cache_promotions>(&self, tcx: Tcx) { + pub fn exec_cache_promotions(&self, tcx: Tcx) { let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion"); let data = self.data.as_ref().unwrap(); @@ -1076,9 +1076,9 @@ rustc_index::newtype_index! { /// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When /// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index` /// first, and `data` second. -pub(super) struct CurrentDepGraph { - encoder: Steal>, - new_node_to_index: Sharded, DepNodeIndex>>, +pub(super) struct CurrentDepGraph { + encoder: Steal>, + new_node_to_index: Sharded>, prev_index_to_index: Lock>>, /// This is used to verify that fingerprints do not change between the creation of a node @@ -1089,7 +1089,7 @@ pub(super) struct CurrentDepGraph { /// Used to trap when a specific edge is added to the graph. /// This is used for debug purposes and is only active with `debug_assertions`. #[cfg(debug_assertions)] - forbidden_edge: Option>, + forbidden_edge: Option, /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of /// their edges. This has the beneficial side-effect that multiple anonymous @@ -1116,14 +1116,14 @@ pub(super) struct CurrentDepGraph { node_intern_event_id: Option, } -impl CurrentDepGraph { +impl CurrentDepGraph { fn new( profiler: &SelfProfilerRef, prev_graph_node_count: usize, encoder: FileEncoder, record_graph: bool, record_stats: bool, - ) -> CurrentDepGraph { + ) -> Self { use std::time::{SystemTime, UNIX_EPOCH}; let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); @@ -1178,7 +1178,7 @@ impl CurrentDepGraph { } #[cfg(debug_assertions)] - fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode, fingerprint: Fingerprint) { + fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode, fingerprint: Fingerprint) { if let Some(forbidden_edge) = &self.forbidden_edge { forbidden_edge.index_to_node.lock().insert(dep_node_index, key); } @@ -1192,7 +1192,7 @@ impl CurrentDepGraph { fn intern_new_node( &self, profiler: &SelfProfilerRef, - key: DepNode, + key: DepNode, edges: EdgesVec, current_fingerprint: Fingerprint, ) -> DepNodeIndex { @@ -1215,8 +1215,8 @@ impl CurrentDepGraph { fn intern_node( &self, profiler: &SelfProfilerRef, - prev_graph: &SerializedDepGraph, - key: DepNode, + prev_graph: &SerializedDepGraph, + key: DepNode, edges: EdgesVec, fingerprint: Option, print_status: bool, @@ -1289,7 +1289,7 @@ impl CurrentDepGraph { fn promote_node_and_deps_to_current( &self, profiler: &SelfProfilerRef, - prev_graph: &SerializedDepGraph, + prev_graph: &SerializedDepGraph, prev_index: SerializedDepNodeIndex, ) -> DepNodeIndex { self.debug_assert_not_in_new_nodes(prev_graph, prev_index); @@ -1317,7 +1317,7 @@ impl CurrentDepGraph { #[inline] fn debug_assert_not_in_new_nodes( &self, - prev_graph: &SerializedDepGraph, + prev_graph: &SerializedDepGraph, prev_index: SerializedDepNodeIndex, ) { let node = &prev_graph.index_to_node(prev_index); @@ -1329,11 +1329,11 @@ impl CurrentDepGraph { } #[derive(Debug, Clone, Copy)] -pub enum TaskDepsRef<'a, K: DepKind> { +pub enum TaskDepsRef<'a> { /// New dependencies can be added to the /// `TaskDeps`. This is used when executing a 'normal' query /// (no `eval_always` modifier) - Allow(&'a Lock>), + Allow(&'a Lock), /// This is used when executing an `eval_always` query. We don't /// need to track dependencies for a query that's always /// re-executed -- but we need to know that this is an `eval_always` @@ -1350,15 +1350,15 @@ pub enum TaskDepsRef<'a, K: DepKind> { } #[derive(Debug)] -pub struct TaskDeps { +pub struct TaskDeps { #[cfg(debug_assertions)] - node: Option>, + node: Option, reads: EdgesVec, read_set: FxHashSet, - phantom_data: PhantomData>, + phantom_data: PhantomData, } -impl Default for TaskDeps { +impl Default for TaskDeps { fn default() -> Self { Self { #[cfg(debug_assertions)] @@ -1410,10 +1410,7 @@ impl DepNodeColorMap { #[inline(never)] #[cold] -pub(crate) fn print_markframe_trace( - graph: &DepGraph, - frame: Option<&MarkFrame<'_>>, -) { +pub(crate) fn print_markframe_trace(graph: &DepGraph, frame: Option<&MarkFrame<'_>>) { let data = graph.data.as_ref().unwrap(); eprintln!("there was a panic while trying to force a dep node"); diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 272028d35bf7..624ae680a8ff 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -1,11 +1,11 @@ pub mod debug; -mod dep_node; +pub mod dep_node; mod edges; mod graph; mod query; mod serialized; -pub use dep_node::{DepKindStruct, DepNode, DepNodeParams, WorkProductId}; +pub use dep_node::{DepKind, DepKindStruct, DepNode, DepNodeParams, WorkProductId}; pub use edges::EdgesVec; pub use graph::{ hash_result, DepGraph, DepGraphData, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef, @@ -16,22 +16,20 @@ pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use crate::ich::StableHashingContext; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_serialize::{opaque::FileEncoder, Encodable}; use rustc_session::Session; -use std::hash::Hash; -use std::{fmt, panic}; +use std::panic; use self::graph::{print_markframe_trace, MarkFrame}; pub trait DepContext: Copy { - type DepKind: self::DepKind; + type Deps: Deps; /// Create a hashing context for hashing new results. fn with_stable_hashing_context(self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R; /// Access the DepGraph. - fn dep_graph(&self) -> &DepGraph; + fn dep_graph(&self) -> &DepGraph; /// Access the profiler. fn profiler(&self) -> &SelfProfilerRef; @@ -39,10 +37,10 @@ pub trait DepContext: Copy { /// Access the compiler session. fn sess(&self) -> &Session; - fn dep_kind_info(&self, dep_node: Self::DepKind) -> &DepKindStruct; + fn dep_kind_info(&self, dep_node: DepKind) -> &DepKindStruct; #[inline(always)] - fn fingerprint_style(self, kind: Self::DepKind) -> FingerprintStyle { + fn fingerprint_style(self, kind: DepKind) -> FingerprintStyle { let data = self.dep_kind_info(kind); if data.is_anon { return FingerprintStyle::Opaque; @@ -52,18 +50,14 @@ pub trait DepContext: Copy { #[inline(always)] /// Return whether this kind always require evaluation. - fn is_eval_always(self, kind: Self::DepKind) -> bool { + fn is_eval_always(self, kind: DepKind) -> bool { self.dep_kind_info(kind).is_eval_always } /// Try to force a dep node to execute and see if it's green. #[inline] #[instrument(skip(self, frame), level = "debug")] - fn try_force_from_dep_node( - self, - dep_node: DepNode, - frame: Option<&MarkFrame<'_>>, - ) -> bool { + fn try_force_from_dep_node(self, dep_node: DepNode, frame: Option<&MarkFrame<'_>>) -> bool { let cb = self.dep_kind_info(dep_node.kind); if let Some(f) = cb.force_from_dep_node { if let Err(value) = panic::catch_unwind(panic::AssertUnwindSafe(|| { @@ -81,7 +75,7 @@ pub trait DepContext: Copy { } /// Load data from the on-disk cache. - fn try_load_from_on_disk_cache(self, dep_node: DepNode) { + fn try_load_from_on_disk_cache(self, dep_node: DepNode) { let cb = self.dep_kind_info(dep_node.kind); if let Some(f) = cb.try_load_from_on_disk_cache { f(self, dep_node) @@ -89,15 +83,37 @@ pub trait DepContext: Copy { } } +pub trait Deps { + /// Execute the operation with provided dependencies. + fn with_deps(deps: TaskDepsRef<'_>, op: OP) -> R + where + OP: FnOnce() -> R; + + /// Access dependencies from current implicit context. + fn read_deps(op: OP) + where + OP: for<'a> FnOnce(TaskDepsRef<'a>); + + /// We use this for most things when incr. comp. is turned off. + const DEP_KIND_NULL: DepKind; + + /// We use this to create a forever-red node. + const DEP_KIND_RED: DepKind; + + /// This is the highest value a `DepKind` can have. It's used during encoding to + /// pack information into the unused bits. + const DEP_KIND_MAX: u16; +} + pub trait HasDepContext: Copy { - type DepKind: self::DepKind; - type DepContext: self::DepContext; + type Deps: self::Deps; + type DepContext: self::DepContext; fn dep_context(&self) -> &Self::DepContext; } impl HasDepContext for T { - type DepKind = T::DepKind; + type Deps = T::Deps; type DepContext = Self; fn dep_context(&self) -> &Self::DepContext { @@ -106,7 +122,7 @@ impl HasDepContext for T { } impl HasDepContext for (T, Q) { - type DepKind = T::DepKind; + type Deps = T::Deps; type DepContext = T::DepContext; fn dep_context(&self) -> &Self::DepContext { @@ -138,31 +154,3 @@ impl FingerprintStyle { } } } - -/// Describe the different families of dependency nodes. -pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable + 'static { - /// DepKind to use when incr. comp. is turned off. - const NULL: Self; - - /// DepKind to use to create the initial forever-red node. - const RED: Self; - - /// Implementation of `std::fmt::Debug` for `DepNode`. - fn debug_node(node: &DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result; - - /// Execute the operation with provided dependencies. - fn with_deps(deps: TaskDepsRef<'_, Self>, op: OP) -> R - where - OP: FnOnce() -> R; - - /// Access dependencies from current implicit context. - fn read_deps(op: OP) - where - OP: for<'a> FnOnce(TaskDepsRef<'a, Self>); - - fn from_u16(u: u16) -> Self; - - fn to_u16(self) -> u16; - - const MAX: u16; -} diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index 5cbc6bf8f8af..5969e5fbe98f 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -2,16 +2,16 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::implementation::{Direction, Graph, NodeIndex, INCOMING}; use rustc_index::IndexVec; -use super::{DepKind, DepNode, DepNodeIndex}; +use super::{DepNode, DepNodeIndex}; -pub struct DepGraphQuery { - pub graph: Graph, ()>, - pub indices: FxHashMap, NodeIndex>, +pub struct DepGraphQuery { + pub graph: Graph, + pub indices: FxHashMap, pub dep_index_to_index: IndexVec>, } -impl DepGraphQuery { - pub fn new(prev_node_count: usize) -> DepGraphQuery { +impl DepGraphQuery { + pub fn new(prev_node_count: usize) -> DepGraphQuery { let node_count = prev_node_count + prev_node_count / 4; let edge_count = 6 * node_count; @@ -22,7 +22,7 @@ impl DepGraphQuery { DepGraphQuery { graph, indices, dep_index_to_index } } - pub fn push(&mut self, index: DepNodeIndex, node: DepNode, edges: &[DepNodeIndex]) { + pub fn push(&mut self, index: DepNodeIndex, node: DepNode, edges: &[DepNodeIndex]) { let source = self.graph.add_node(node); self.dep_index_to_index.insert(index, source); self.indices.insert(node, source); @@ -37,11 +37,11 @@ impl DepGraphQuery { } } - pub fn nodes(&self) -> Vec<&DepNode> { + pub fn nodes(&self) -> Vec<&DepNode> { self.graph.all_nodes().iter().map(|n| &n.data).collect() } - pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { + pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { self.graph .all_edges() .iter() @@ -50,7 +50,7 @@ impl DepGraphQuery { .collect() } - fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { + fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { if let Some(&index) = self.indices.get(node) { self.graph.depth_traverse(index, direction).map(|s| self.graph.node_data(s)).collect() } else { @@ -59,7 +59,7 @@ impl DepGraphQuery { } /// All nodes that can reach `node`. - pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { + pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { self.reachable_nodes(node, INCOMING) } } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 07eb10cba02c..fcf46be6e6f5 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -36,7 +36,7 @@ //! store it directly after the header with leb128. use super::query::DepGraphQuery; -use super::{DepKind, DepNode, DepNodeIndex}; +use super::{DepKind, DepNode, DepNodeIndex, Deps}; use crate::dep_graph::EdgesVec; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::PackedFingerprint; @@ -70,9 +70,9 @@ const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2; /// Data for use when recompiling the **current crate**. #[derive(Debug)] -pub struct SerializedDepGraph { +pub struct SerializedDepGraph { /// The set of all DepNodes in the graph - nodes: IndexVec>, + nodes: IndexVec, /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to /// the DepNode at the same index in the nodes vector. fingerprints: IndexVec, @@ -88,7 +88,7 @@ pub struct SerializedDepGraph { index: Vec>, } -impl Default for SerializedDepGraph { +impl Default for SerializedDepGraph { fn default() -> Self { SerializedDepGraph { nodes: Default::default(), @@ -100,7 +100,7 @@ impl Default for SerializedDepGraph { } } -impl SerializedDepGraph { +impl SerializedDepGraph { #[inline] pub fn edge_targets_from( &self, @@ -134,13 +134,13 @@ impl SerializedDepGraph { } #[inline] - pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { + pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { self.nodes[dep_node_index] } #[inline] - pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { - self.index.get(dep_node.kind.to_u16() as usize)?.get(&dep_node.hash).cloned() + pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { + self.index.get(dep_node.kind.as_usize())?.get(&dep_node.hash).cloned() } #[inline] @@ -184,11 +184,9 @@ fn mask(bits: usize) -> usize { usize::MAX >> ((std::mem::size_of::() * 8) - bits) } -impl<'a, K: DepKind + Decodable>> Decodable> - for SerializedDepGraph -{ +impl SerializedDepGraph { #[instrument(level = "debug", skip(d))] - fn decode(d: &mut MemDecoder<'a>) -> SerializedDepGraph { + pub fn decode(d: &mut MemDecoder<'_>) -> SerializedDepGraph { // The last 16 bytes are the node count and edge count. debug!("position: {:?}", d.position()); let (node_count, edge_count) = @@ -217,14 +215,14 @@ impl<'a, K: DepKind + Decodable>> Decodable> // least (34 byte header + 1 byte len + 64 bytes edge data), which is ~1%. A 2-byte leb128 // length is about the same fractional overhead and it amortizes for yet greater lengths. let mut edge_list_data = Vec::with_capacity( - graph_bytes - node_count * std::mem::size_of::>(), + graph_bytes - node_count * std::mem::size_of::>(), ); for _index in 0..node_count { // Decode the header for this edge; the header packs together as many of the fixed-size // fields as possible to limit the number of times we update decoder state. let node_header = - SerializedNodeHeader:: { bytes: d.read_array(), _marker: PhantomData }; + SerializedNodeHeader:: { bytes: d.read_array(), _marker: PhantomData }; let _i: SerializedDepNodeIndex = nodes.push(node_header.node()); debug_assert_eq!(_i.index(), _index); @@ -256,12 +254,12 @@ impl<'a, K: DepKind + Decodable>> Decodable> edge_list_data.extend(&[0u8; DEP_NODE_PAD]); // Read the number of each dep kind and use it to create an hash map with a suitable size. - let mut index: Vec<_> = (0..(K::MAX as usize + 1)) + let mut index: Vec<_> = (0..(D::DEP_KIND_MAX + 1)) .map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default())) .collect(); for (idx, node) in nodes.iter_enumerated() { - index[node.kind.to_u16() as usize].insert(node.hash, idx); + index[node.kind.as_usize()].insert(node.hash, idx); } SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index } @@ -276,20 +274,20 @@ impl<'a, K: DepKind + Decodable>> Decodable> /// * The `DepKind`'s discriminant (a u16, but not all bits are used...) /// * The byte width of the encoded edges for this node /// * In whatever bits remain, the length of the edge list for this node, if it fits -struct SerializedNodeHeader { +struct SerializedNodeHeader { // 2 bytes for the DepNode // 16 for Fingerprint in DepNode // 16 for Fingerprint in NodeInfo bytes: [u8; 34], - _marker: PhantomData, + _marker: PhantomData, } // The fields of a `SerializedNodeHeader`, this struct is an implementation detail and exists only // to make the implementation of `SerializedNodeHeader` simpler. -struct Unpacked { +struct Unpacked { len: Option, bytes_per_index: usize, - kind: K, + kind: DepKind, hash: PackedFingerprint, fingerprint: Fingerprint, } @@ -301,20 +299,20 @@ struct Unpacked { // 0..M length of the edge // M..M+N bytes per index // M+N..16 kind -impl SerializedNodeHeader { - const TOTAL_BITS: usize = std::mem::size_of::() * 8; +impl SerializedNodeHeader { + const TOTAL_BITS: usize = std::mem::size_of::() * 8; const LEN_BITS: usize = Self::TOTAL_BITS - Self::KIND_BITS - Self::WIDTH_BITS; const WIDTH_BITS: usize = DEP_NODE_WIDTH_BITS; - const KIND_BITS: usize = Self::TOTAL_BITS - K::MAX.leading_zeros() as usize; + const KIND_BITS: usize = Self::TOTAL_BITS - D::DEP_KIND_MAX.leading_zeros() as usize; const MAX_INLINE_LEN: usize = (u16::MAX as usize >> (Self::TOTAL_BITS - Self::LEN_BITS)) - 1; #[inline] - fn new(node_info: &NodeInfo) -> Self { + fn new(node_info: &NodeInfo) -> Self { debug_assert_eq!(Self::TOTAL_BITS, Self::LEN_BITS + Self::WIDTH_BITS + Self::KIND_BITS); let NodeInfo { node, fingerprint, edges } = node_info; - let mut head = node.kind.to_u16(); + let mut head = node.kind.as_inner(); let free_bytes = edges.max_index().leading_zeros() as usize / 8; let bytes_per_index = (DEP_NODE_SIZE - free_bytes).saturating_sub(1); @@ -347,7 +345,7 @@ impl SerializedNodeHeader { } #[inline] - fn unpack(&self) -> Unpacked { + fn unpack(&self) -> Unpacked { let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap()); let hash = self.bytes[2..18].try_into().unwrap(); let fingerprint = self.bytes[18..].try_into().unwrap(); @@ -359,7 +357,7 @@ impl SerializedNodeHeader { Unpacked { len: len.checked_sub(1), bytes_per_index: bytes_per_index as usize + 1, - kind: DepKind::from_u16(kind), + kind: DepKind::new(kind), hash: Fingerprint::from_le_bytes(hash).into(), fingerprint: Fingerprint::from_le_bytes(fingerprint), } @@ -381,7 +379,7 @@ impl SerializedNodeHeader { } #[inline] - fn node(&self) -> DepNode { + fn node(&self) -> DepNode { let Unpacked { kind, hash, .. } = self.unpack(); DepNode { kind, hash } } @@ -395,15 +393,15 @@ impl SerializedNodeHeader { } #[derive(Debug)] -struct NodeInfo { - node: DepNode, +struct NodeInfo { + node: DepNode, fingerprint: Fingerprint, edges: EdgesVec, } -impl Encodable for NodeInfo { - fn encode(&self, e: &mut FileEncoder) { - let header = SerializedNodeHeader::new(self); +impl NodeInfo { + fn encode(&self, e: &mut FileEncoder) { + let header = SerializedNodeHeader::::new(self); e.write_array(header.bytes); if header.len().is_none() { @@ -420,41 +418,43 @@ impl Encodable for NodeInfo { } } -struct Stat { - kind: K, +struct Stat { + kind: DepKind, node_counter: u64, edge_counter: u64, } -struct EncoderState { +struct EncoderState { encoder: FileEncoder, total_node_count: usize, total_edge_count: usize, - stats: Option>>, + stats: Option>, /// Stores the number of times we've encoded each dep kind. kind_stats: Vec, + marker: PhantomData, } -impl EncoderState { +impl EncoderState { fn new(encoder: FileEncoder, record_stats: bool) -> Self { Self { encoder, total_edge_count: 0, total_node_count: 0, stats: record_stats.then(FxHashMap::default), - kind_stats: iter::repeat(0).take(K::MAX as usize + 1).collect(), + kind_stats: iter::repeat(0).take(D::DEP_KIND_MAX as usize + 1).collect(), + marker: PhantomData, } } fn encode_node( &mut self, - node: &NodeInfo, - record_graph: &Option>>, + node: &NodeInfo, + record_graph: &Option>, ) -> DepNodeIndex { let index = DepNodeIndex::new(self.total_node_count); self.total_node_count += 1; - self.kind_stats[node.node.kind.to_u16() as usize] += 1; + self.kind_stats[node.node.kind.as_usize()] += 1; let edge_count = node.edges.len(); self.total_edge_count += edge_count; @@ -475,12 +475,19 @@ impl EncoderState { } let encoder = &mut self.encoder; - node.encode(encoder); + node.encode::(encoder); index } fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult { - let Self { mut encoder, total_node_count, total_edge_count, stats: _, kind_stats } = self; + let Self { + mut encoder, + total_node_count, + total_edge_count, + stats: _, + kind_stats, + marker: _, + } = self; let node_count = total_node_count.try_into().unwrap(); let edge_count = total_edge_count.try_into().unwrap(); @@ -506,12 +513,12 @@ impl EncoderState { } } -pub struct GraphEncoder { - status: Lock>, - record_graph: Option>>, +pub struct GraphEncoder { + status: Lock>, + record_graph: Option>, } -impl> GraphEncoder { +impl GraphEncoder { pub fn new( encoder: FileEncoder, prev_node_count: usize, @@ -523,7 +530,7 @@ impl> GraphEncoder { GraphEncoder { status, record_graph } } - pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery)) { + pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery)) { if let Some(record_graph) = &self.record_graph { f(&record_graph.lock()) } @@ -584,7 +591,7 @@ impl> GraphEncoder { pub(crate) fn send( &self, profiler: &SelfProfilerRef, - node: DepNode, + node: DepNode, fingerprint: Fingerprint, edges: EdgesVec, ) -> DepNodeIndex { diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index d14c6315dc10..c025fac2631a 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -1,6 +1,6 @@ //! Query configuration and description traits. -use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex}; +use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex}; use crate::error::HandleCycleError; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; @@ -27,7 +27,7 @@ pub trait QueryConfig: Copy { fn format_value(self) -> fn(&Self::Value) -> String; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState + fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState where Qcx: 'a; @@ -57,7 +57,7 @@ pub trait QueryConfig: Copy { fn value_from_cycle_error( self, tcx: Qcx::DepContext, - cycle: &[QueryInfo], + cycle: &[QueryInfo], guar: ErrorGuaranteed, ) -> Self::Value; @@ -66,12 +66,12 @@ pub trait QueryConfig: Copy { fn depth_limit(self) -> bool; fn feedable(self) -> bool; - fn dep_kind(self) -> Qcx::DepKind; + fn dep_kind(self) -> DepKind; fn handle_cycle_error(self) -> HandleCycleError; fn hash_result(self) -> HashResult; // Just here for convenience and checking that the key matches the kind, don't override this. - fn construct_dep_node(self, tcx: Qcx::DepContext, key: &Self::Key) -> DepNode { + fn construct_dep_node(self, tcx: Qcx::DepContext, key: &Self::Key) -> DepNode { DepNode::construct(tcx, self.dep_kind(), key) } } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 6c01dc3c00d4..2e9ebde296cd 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -1,9 +1,8 @@ -use crate::dep_graph::DepKind; +use crate::dep_graph::DepContext; use crate::error::CycleStack; use crate::query::plumbing::CycleError; +use crate::query::DepKind; use crate::query::{QueryContext, QueryStackFrame}; -use core::marker::PhantomData; - use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, Level, @@ -30,48 +29,48 @@ use { /// Represents a span and a query key. #[derive(Clone, Debug)] -pub struct QueryInfo { +pub struct QueryInfo { /// The span corresponding to the reason for which this query was required. pub span: Span, - pub query: QueryStackFrame, + pub query: QueryStackFrame, } -pub type QueryMap = FxHashMap>; +pub type QueryMap = FxHashMap; /// A value uniquely identifying an active query job. #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct QueryJobId(pub NonZeroU64); impl QueryJobId { - fn query(self, map: &QueryMap) -> QueryStackFrame { + fn query(self, map: &QueryMap) -> QueryStackFrame { map.get(&self).unwrap().query.clone() } #[cfg(parallel_compiler)] - fn span(self, map: &QueryMap) -> Span { + fn span(self, map: &QueryMap) -> Span { map.get(&self).unwrap().job.span } #[cfg(parallel_compiler)] - fn parent(self, map: &QueryMap) -> Option { + fn parent(self, map: &QueryMap) -> Option { map.get(&self).unwrap().job.parent } #[cfg(parallel_compiler)] - fn latch(self, map: &QueryMap) -> Option<&QueryLatch> { + fn latch(self, map: &QueryMap) -> Option<&QueryLatch> { map.get(&self).unwrap().job.latch.as_ref() } } #[derive(Clone)] -pub struct QueryJobInfo { - pub query: QueryStackFrame, - pub job: QueryJob, +pub struct QueryJobInfo { + pub query: QueryStackFrame, + pub job: QueryJob, } /// Represents an active query job. #[derive(Clone)] -pub struct QueryJob { +pub struct QueryJob { pub id: QueryJobId, /// The span corresponding to the reason for which this query was required. @@ -82,11 +81,10 @@ pub struct QueryJob { /// The latch that is used to wait on this job. #[cfg(parallel_compiler)] - latch: Option>, - spooky: core::marker::PhantomData, + latch: Option, } -impl QueryJob { +impl QueryJob { /// Creates a new query job. #[inline] pub fn new(id: QueryJobId, span: Span, parent: Option) -> Self { @@ -96,12 +94,11 @@ impl QueryJob { parent, #[cfg(parallel_compiler)] latch: None, - spooky: PhantomData, } } #[cfg(parallel_compiler)] - pub(super) fn latch(&mut self) -> QueryLatch { + pub(super) fn latch(&mut self) -> QueryLatch { if self.latch.is_none() { self.latch = Some(QueryLatch::new()); } @@ -124,12 +121,12 @@ impl QueryJob { } impl QueryJobId { - pub(super) fn find_cycle_in_stack( + pub(super) fn find_cycle_in_stack( &self, - query_map: QueryMap, + query_map: QueryMap, current_job: &Option, span: Span, - ) -> CycleError { + ) -> CycleError { // Find the waitee amongst `current_job` parents let mut cycle = Vec::new(); let mut current_job = Option::clone(current_job); @@ -163,18 +160,18 @@ impl QueryJobId { #[cold] #[inline(never)] - pub fn try_find_layout_root( + pub fn try_find_layout_root( &self, - query_map: QueryMap, - ) -> Option<(QueryJobInfo, usize)> { + query_map: QueryMap, + layout_of_kind: DepKind, + ) -> Option<(QueryJobInfo, usize)> { let mut last_layout = None; let mut current_id = Some(*self); let mut depth = 0; while let Some(id) = current_id { let info = query_map.get(&id).unwrap(); - // FIXME: This string comparison should probably not be done. - if format!("{:?}", info.query.dep_kind) == "layout_of" { + if info.query.dep_kind == layout_of_kind { depth += 1; last_layout = Some((info.clone(), depth)); } @@ -185,15 +182,15 @@ impl QueryJobId { } #[cfg(parallel_compiler)] -struct QueryWaiter { +struct QueryWaiter { query: Option, condvar: Condvar, span: Span, - cycle: Mutex>>, + cycle: Mutex>, } #[cfg(parallel_compiler)] -impl QueryWaiter { +impl QueryWaiter { fn notify(&self, registry: &rayon_core::Registry) { rayon_core::mark_unblocked(registry); self.condvar.notify_one(); @@ -201,19 +198,19 @@ impl QueryWaiter { } #[cfg(parallel_compiler)] -struct QueryLatchInfo { +struct QueryLatchInfo { complete: bool, - waiters: Vec>>, + waiters: Vec>, } #[cfg(parallel_compiler)] #[derive(Clone)] -pub(super) struct QueryLatch { - info: Arc>>, +pub(super) struct QueryLatch { + info: Arc>, } #[cfg(parallel_compiler)] -impl QueryLatch { +impl QueryLatch { fn new() -> Self { QueryLatch { info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })), @@ -221,11 +218,7 @@ impl QueryLatch { } /// Awaits for the query job to complete. - pub(super) fn wait_on( - &self, - query: Option, - span: Span, - ) -> Result<(), CycleError> { + pub(super) fn wait_on(&self, query: Option, span: Span) -> Result<(), CycleError> { let waiter = Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() }); self.wait_on_inner(&waiter); @@ -240,7 +233,7 @@ impl QueryLatch { } /// Awaits the caller on this latch by blocking the current thread. - fn wait_on_inner(&self, waiter: &Arc>) { + fn wait_on_inner(&self, waiter: &Arc) { let mut info = self.info.lock(); if !info.complete { // We push the waiter on to the `waiters` list. It can be accessed inside @@ -274,7 +267,7 @@ impl QueryLatch { /// Removes a single waiter from the list of waiters. /// This is used to break query cycles. - fn extract_waiter(&self, waiter: usize) -> Arc> { + fn extract_waiter(&self, waiter: usize) -> Arc { let mut info = self.info.lock(); debug_assert!(!info.complete); // Remove the waiter from the list of waiters @@ -296,14 +289,9 @@ type Waiter = (QueryJobId, usize); /// required information to resume the waiter. /// If all `visit` calls returns None, this function also returns None. #[cfg(parallel_compiler)] -fn visit_waiters( - query_map: &QueryMap, - query: QueryJobId, - mut visit: F, -) -> Option> +fn visit_waiters(query_map: &QueryMap, query: QueryJobId, mut visit: F) -> Option> where F: FnMut(Span, QueryJobId) -> Option>, - D: DepKind, { // Visit the parent query which is a non-resumable waiter since it's on the same stack if let Some(parent) = query.parent(query_map) { @@ -332,8 +320,8 @@ where /// If a cycle is detected, this initial value is replaced with the span causing /// the cycle. #[cfg(parallel_compiler)] -fn cycle_check( - query_map: &QueryMap, +fn cycle_check( + query_map: &QueryMap, query: QueryJobId, span: Span, stack: &mut Vec<(Span, QueryJobId)>, @@ -373,8 +361,8 @@ fn cycle_check( /// from `query` without going through any of the queries in `visited`. /// This is achieved with a depth first search. #[cfg(parallel_compiler)] -fn connected_to_root( - query_map: &QueryMap, +fn connected_to_root( + query_map: &QueryMap, query: QueryJobId, visited: &mut FxHashSet, ) -> bool { @@ -396,10 +384,9 @@ fn connected_to_root( // Deterministically pick an query from a list #[cfg(parallel_compiler)] -fn pick_query<'a, T, F, D>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T +fn pick_query<'a, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T where F: Fn(&T) -> (Span, QueryJobId), - D: DepKind, { // Deterministically pick an entry point // FIXME: Sort this instead @@ -423,10 +410,10 @@ where /// If a cycle was not found, the starting query is removed from `jobs` and /// the function returns false. #[cfg(parallel_compiler)] -fn remove_cycle( - query_map: &QueryMap, +fn remove_cycle( + query_map: &QueryMap, jobs: &mut Vec, - wakelist: &mut Vec>>, + wakelist: &mut Vec>, ) -> bool { let mut visited = FxHashSet::default(); let mut stack = Vec::new(); @@ -528,7 +515,7 @@ fn remove_cycle( /// There may be multiple cycles involved in a deadlock, so this searches /// all active queries for cycles before finally resuming all the waiters at once. #[cfg(parallel_compiler)] -pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) { +pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) { let on_panic = defer(|| { eprintln!("deadlock handler panicked, aborting process"); process::abort(); @@ -566,9 +553,9 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Regis #[inline(never)] #[cold] -pub(crate) fn report_cycle<'a, D: DepKind>( +pub(crate) fn report_cycle<'a>( sess: &'a Session, - CycleError { usage, cycle: stack }: &CycleError, + CycleError { usage, cycle: stack }: &CycleError, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { assert!(!stack.is_empty()); @@ -655,8 +642,10 @@ pub fn print_query_stack( if let Some(ref mut file) = file { let _ = writeln!( file, - "#{} [{:?}] {}", - count_total, query_info.query.dep_kind, query_info.query.description + "#{} [{}] {}", + count_total, + qcx.dep_context().dep_kind_info(query_info.query.dep_kind).name, + query_info.query.description ); } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index f7619d75be76..05dee9f12dbd 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -28,27 +28,27 @@ use thin_vec::ThinVec; /// /// This is mostly used in case of cycles for error reporting. #[derive(Clone, Debug)] -pub struct QueryStackFrame { +pub struct QueryStackFrame { pub description: String, span: Option, pub def_id: Option, pub def_kind: Option, pub ty_adt_id: Option, - pub dep_kind: D, + pub dep_kind: DepKind, /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. #[cfg(parallel_compiler)] hash: Hash64, } -impl QueryStackFrame { +impl QueryStackFrame { #[inline] pub fn new( description: String, span: Option, def_id: Option, def_kind: Option, - dep_kind: D, + dep_kind: DepKind, ty_adt_id: Option, _hash: impl FnOnce() -> Hash64, ) -> Self { @@ -106,7 +106,7 @@ pub trait QueryContext: HasDepContext { /// Get the query information from the TLS context. fn current_query_job(self) -> Option; - fn try_collect_active_jobs(self) -> Option>; + fn try_collect_active_jobs(self) -> Option; /// Load side effects associated to the node in the previous session. fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 07db15e6d8be..f93edffca79e 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -2,8 +2,8 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams}; -use crate::dep_graph::{DepGraphData, HasDepContext}; +use crate::dep_graph::DepGraphData; +use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams}; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; #[cfg(parallel_compiler)] @@ -30,24 +30,23 @@ use thin_vec::ThinVec; use super::QueryConfig; -pub struct QueryState { - active: Sharded>>, +pub struct QueryState { + active: Sharded>, } /// Indicates the state of a query for a given key in a query map. -enum QueryResult { +enum QueryResult { /// An already executing query. The query job can be used to await for its completion. - Started(QueryJob), + Started(QueryJob), /// The query panicked. Queries trying to wait on this will raise a fatal error which will /// silently panic. Poisoned, } -impl QueryState +impl QueryState where K: Eq + Hash + Copy + Debug, - D: DepKind, { pub fn all_inactive(&self) -> bool { self.active.lock_shards().all(|shard| shard.is_empty()) @@ -56,8 +55,8 @@ where pub fn try_collect_active_jobs( &self, qcx: Qcx, - make_query: fn(Qcx, K) -> QueryStackFrame, - jobs: &mut QueryMap, + make_query: fn(Qcx, K) -> QueryStackFrame, + jobs: &mut QueryMap, ) -> Option<()> { let mut active = Vec::new(); @@ -82,25 +81,25 @@ where } } -impl Default for QueryState { - fn default() -> QueryState { +impl Default for QueryState { + fn default() -> QueryState { QueryState { active: Default::default() } } } /// A type representing the responsibility to execute the job in the `job` field. /// This will poison the relevant query if dropped. -struct JobOwner<'tcx, K, D: DepKind> +struct JobOwner<'tcx, K> where K: Eq + Hash + Copy, { - state: &'tcx QueryState, + state: &'tcx QueryState, key: K, } #[cold] #[inline(never)] -fn mk_cycle(query: Q, qcx: Qcx, cycle_error: CycleError) -> Q::Value +fn mk_cycle(query: Q, qcx: Qcx, cycle_error: CycleError) -> Q::Value where Q: QueryConfig, Qcx: QueryContext, @@ -112,7 +111,7 @@ where fn handle_cycle_error( query: Q, qcx: Qcx, - cycle_error: &CycleError, + cycle_error: &CycleError, mut error: DiagnosticBuilder<'_, ErrorGuaranteed>, ) -> Q::Value where @@ -137,7 +136,7 @@ where } } -impl<'tcx, K, D: DepKind> JobOwner<'tcx, K, D> +impl<'tcx, K> JobOwner<'tcx, K> where K: Eq + Hash + Copy, { @@ -169,10 +168,9 @@ where } } -impl<'tcx, K, D> Drop for JobOwner<'tcx, K, D> +impl<'tcx, K> Drop for JobOwner<'tcx, K> where K: Eq + Hash + Copy, - D: DepKind, { #[inline(never)] #[cold] @@ -195,10 +193,10 @@ where } #[derive(Clone)] -pub(crate) struct CycleError { +pub(crate) struct CycleError { /// The query and related span that uses the cycle. - pub usage: Option<(Span, QueryStackFrame)>, - pub cycle: Vec>, + pub usage: Option<(Span, QueryStackFrame)>, + pub cycle: Vec, } /// Checks if the query is already computed and in the cache. @@ -248,7 +246,7 @@ fn wait_for_query( qcx: Qcx, span: Span, key: Q::Key, - latch: QueryLatch, + latch: QueryLatch, current: Option, ) -> (Q::Value, Option) where @@ -296,7 +294,7 @@ fn try_execute_query( qcx: Qcx, span: Span, key: Q::Key, - dep_node: Option>, + dep_node: Option, ) -> (Q::Value, Option) where Q: QueryConfig, @@ -364,10 +362,10 @@ where fn execute_job( query: Q, qcx: Qcx, - state: &QueryState, + state: &QueryState, key: Q::Key, id: QueryJobId, - dep_node: Option>, + dep_node: Option, ) -> (Q::Value, Option) where Q: QueryConfig, @@ -474,9 +472,9 @@ where fn execute_job_incr( query: Q, qcx: Qcx, - dep_graph_data: &DepGraphData, + dep_graph_data: &DepGraphData, key: Q::Key, - mut dep_node_opt: Option>, + mut dep_node_opt: Option, job_id: QueryJobId, ) -> (Q::Value, DepNodeIndex) where @@ -540,10 +538,10 @@ where #[inline(always)] fn try_load_from_disk_and_cache_in_memory( query: Q, - dep_graph_data: &DepGraphData, + dep_graph_data: &DepGraphData, qcx: Qcx, key: &Q::Key, - dep_node: &DepNode, + dep_node: &DepNode, ) -> Option<(Q::Value, DepNodeIndex)> where Q: QueryConfig, @@ -637,7 +635,7 @@ where #[instrument(skip(tcx, dep_graph_data, result, hash_result, format_value), level = "debug")] pub(crate) fn incremental_verify_ich( tcx: Tcx, - dep_graph_data: &DepGraphData, + dep_graph_data: &DepGraphData, result: &V, prev_index: SerializedDepNodeIndex, hash_result: Option, &V) -> Fingerprint>, @@ -730,7 +728,7 @@ fn ensure_must_run( qcx: Qcx, key: &Q::Key, check_cache: bool, -) -> (bool, Option>) +) -> (bool, Option) where Q: QueryConfig, Qcx: QueryContext, @@ -821,12 +819,8 @@ where Some(result) } -pub fn force_query( - query: Q, - qcx: Qcx, - key: Q::Key, - dep_node: DepNode<::DepKind>, -) where +pub fn force_query(query: Q, qcx: Qcx, key: Q::Key, dep_node: DepNode) +where Q: QueryConfig, Qcx: QueryContext, { diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs index 07c28fdb73b2..8848fda9da3d 100644 --- a/compiler/rustc_query_system/src/values.rs +++ b/compiler/rustc_query_system/src/values.rs @@ -1,14 +1,14 @@ use rustc_span::ErrorGuaranteed; -use crate::dep_graph::{DepContext, DepKind}; +use crate::dep_graph::DepContext; use crate::query::QueryInfo; -pub trait Value: Sized { - fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self; +pub trait Value: Sized { + fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self; } -impl Value for T { - default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> T { +impl Value for T { + default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> T { tcx.sess().abort_if_errors(); // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's // non-trivial to define it earlier. diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 16de518e8e0b..728d0fc1ae76 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -8,7 +8,7 @@ use cache::ProvisionalCache; use rustc_data_structures::fx::FxHashSet; use rustc_index::Idx; use rustc_index::IndexVec; -use rustc_middle::dep_graph::DepKind; +use rustc_middle::dep_graph::dep_kinds; use rustc_middle::traits::solve::inspect::CacheHit; use rustc_middle::traits::solve::CacheData; use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult}; @@ -287,7 +287,7 @@ impl<'tcx> SearchGraph<'tcx> { // Everything that affects the `result` should be performed within this // `with_anon_task` closure. let ((final_entry, result), dep_node) = - tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || { + tcx.dep_graph.with_anon_task(tcx, dep_kinds::TraitSelect, || { // When we encounter a coinductive cycle, we have to fetch the // result of that cycle while we are still computing it. Because // of this we continuously recompute the cycle until the result diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 24d316338505..dcf41c3774fe 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -35,7 +35,8 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::traits::TraitObligation; -use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; +use rustc_middle::dep_graph::dep_kinds; +use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -1435,7 +1436,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { OP: FnOnce(&mut Self) -> R, { let (result, dep_node) = - self.tcx().dep_graph.with_anon_task(self.tcx(), DepKind::TraitSelect, || op(self)); + self.tcx().dep_graph.with_anon_task(self.tcx(), dep_kinds::TraitSelect, || op(self)); self.tcx().dep_graph.read_index(dep_node); (result, dep_node) } From dcea7709f2ce1be35ba241e923850b1099ceb906 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Tue, 19 Sep 2023 12:41:30 +0200 Subject: [PATCH 20/26] added support for GNU/Hurd --- .../rustc_data_structures/src/flock/unix.rs | 24 +- compiler/rustc_target/src/spec/hurd_base.rs | 15 + .../rustc_target/src/spec/hurd_gnu_base.rs | 5 + .../src/spec/i686_unknown_hurd_gnu.rs | 19 + compiler/rustc_target/src/spec/mod.rs | 4 + library/std/build.rs | 1 + library/std/src/os/hurd/fs.rs | 348 ++++++++++++++++++ library/std/src/os/hurd/mod.rs | 6 + library/std/src/os/hurd/raw.rs | 33 ++ library/std/src/os/mod.rs | 2 + library/std/src/os/unix/mod.rs | 2 + library/std/src/sys/unix/args.rs | 1 + library/std/src/sys/unix/env.rs | 11 + library/std/src/sys/unix/fd.rs | 18 +- library/std/src/sys/unix/fs.rs | 60 ++- library/std/src/sys/unix/kernel_copy.rs | 4 +- library/std/src/sys/unix/mod.rs | 4 + library/std/src/sys/unix/net.rs | 3 + library/std/src/sys/unix/os.rs | 15 +- library/std/src/sys/unix/pipe.rs | 1 + .../std/src/sys/unix/process/process_unix.rs | 13 + library/std/src/sys/unix/stack_overflow.rs | 2 + library/std/src/sys/unix/thread.rs | 10 +- library/std/src/sys/unix/thread_local_dtor.rs | 2 +- library/std/src/sys/unix/time.rs | 2 +- library/std/src/sys_common/net.rs | 1 + library/unwind/src/lib.rs | 4 + src/bootstrap/bootstrap.py | 4 +- src/bootstrap/lib.rs | 4 +- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 1 + src/doc/rustc/src/platform-support/hurd.md | 35 ++ tests/ui/check-cfg/values-target-json.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 2 +- tests/ui/intrinsics/intrinsic-alignment.rs | 1 + tests/ui/structs-enums/rec-align-u64.rs | 1 + 36 files changed, 626 insertions(+), 35 deletions(-) create mode 100644 compiler/rustc_target/src/spec/hurd_base.rs create mode 100644 compiler/rustc_target/src/spec/hurd_gnu_base.rs create mode 100644 compiler/rustc_target/src/spec/i686_unknown_hurd_gnu.rs create mode 100644 library/std/src/os/hurd/fs.rs create mode 100644 library/std/src/os/hurd/mod.rs create mode 100644 library/std/src/os/hurd/raw.rs create mode 100644 src/doc/rustc/src/platform-support/hurd.md diff --git a/compiler/rustc_data_structures/src/flock/unix.rs b/compiler/rustc_data_structures/src/flock/unix.rs index 4e5297d582e0..eff9e8f838fe 100644 --- a/compiler/rustc_data_structures/src/flock/unix.rs +++ b/compiler/rustc_data_structures/src/flock/unix.rs @@ -21,8 +21,16 @@ impl Lock { let lock_type = if exclusive { libc::F_WRLCK } else { libc::F_RDLCK }; let mut flock: libc::flock = unsafe { mem::zeroed() }; - flock.l_type = lock_type as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; + #[cfg(not(all(target_os = "hurd", target_arch = "x86")))] + { + flock.l_type = lock_type as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + } + #[cfg(all(target_os = "hurd", target_arch = "x86"))] + { + flock.l_type = lock_type as libc::c_int; + flock.l_whence = libc::SEEK_SET as libc::c_int; + } flock.l_start = 0; flock.l_len = 0; @@ -39,8 +47,16 @@ impl Lock { impl Drop for Lock { fn drop(&mut self) { let mut flock: libc::flock = unsafe { mem::zeroed() }; - flock.l_type = libc::F_UNLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; + #[cfg(not(all(target_os = "hurd", target_arch = "x86")))] + { + flock.l_type = libc::F_UNLCK as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + } + #[cfg(all(target_os = "hurd", target_arch = "x86"))] + { + flock.l_type = libc::F_UNLCK as libc::c_int; + flock.l_whence = libc::SEEK_SET as libc::c_int; + } flock.l_start = 0; flock.l_len = 0; diff --git a/compiler/rustc_target/src/spec/hurd_base.rs b/compiler/rustc_target/src/spec/hurd_base.rs new file mode 100644 index 000000000000..76f8223c0e4e --- /dev/null +++ b/compiler/rustc_target/src/spec/hurd_base.rs @@ -0,0 +1,15 @@ +use crate::spec::{cvs, RelroLevel, TargetOptions}; + +pub fn opts() -> TargetOptions { + TargetOptions { + os: "hurd".into(), + dynamic_linking: true, + families: cvs!["unix"], + has_rpath: true, + position_independent_executables: true, + relro_level: RelroLevel::Full, + has_thread_local: true, + crt_static_respected: true, + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/hurd_gnu_base.rs b/compiler/rustc_target/src/spec/hurd_gnu_base.rs new file mode 100644 index 000000000000..b9cf26d9380b --- /dev/null +++ b/compiler/rustc_target/src/spec/hurd_gnu_base.rs @@ -0,0 +1,5 @@ +use crate::spec::TargetOptions; + +pub fn opts() -> TargetOptions { + TargetOptions { env: "gnu".into(), ..super::hurd_base::opts() } +} diff --git a/compiler/rustc_target/src/spec/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_hurd_gnu.rs new file mode 100644 index 000000000000..29f803601381 --- /dev/null +++ b/compiler/rustc_target/src/spec/i686_unknown_hurd_gnu.rs @@ -0,0 +1,19 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; + +pub fn target() -> Target { + let mut base = super::hurd_gnu_base::opts(); + base.cpu = "pentiumpro".into(); + base.max_atomic_width = Some(64); + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); + base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + + Target { + llvm_target: "i686-unknown-hurd-gnu".into(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ + f64:32:64-f80:32-n8:16:32-S128" + .into(), + arch: "x86".into(), + options: base, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 8aa72797a0d2..60fe98e5045e 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -71,6 +71,8 @@ mod freebsd_base; mod fuchsia_base; mod haiku_base; mod hermit_base; +mod hurd_base; +mod hurd_gnu_base; mod illumos_base; mod l4re_base; mod linux_base; @@ -1367,6 +1369,8 @@ supported_targets! { ("i686-unknown-haiku", i686_unknown_haiku), ("x86_64-unknown-haiku", x86_64_unknown_haiku), + ("i686-unknown-hurd-gnu", i686_unknown_hurd_gnu), + ("aarch64-apple-darwin", aarch64_apple_darwin), ("x86_64-apple-darwin", x86_64_apple_darwin), ("x86_64h-apple-darwin", x86_64h_apple_darwin), diff --git a/library/std/build.rs b/library/std/build.rs index a81c45609ea5..e5509504b849 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -38,6 +38,7 @@ fn main() { || target.contains("vita") || target.contains("nto") || target.contains("xous") + || target.contains("hurd") // See src/bootstrap/synthetic_targets.rs || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() { diff --git a/library/std/src/os/hurd/fs.rs b/library/std/src/os/hurd/fs.rs new file mode 100644 index 000000000000..00ff1560f31d --- /dev/null +++ b/library/std/src/os/hurd/fs.rs @@ -0,0 +1,348 @@ +//! Hurd-specific extensions to primitives in the [`std::fs`] module. +//! +//! [`std::fs`]: crate::fs + +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use crate::fs::Metadata; +use crate::sys_common::AsInner; + +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: crate::fs::Metadata +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + /// Returns the device ID on which this file resides. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_dev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + /// Returns the inode number. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ino()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + /// Returns the file type and mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mode()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + /// Returns the number of hard links to file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_nlink()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + /// Returns the user ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_uid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + /// Returns the group ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_gid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + /// Returns the device ID that this file represents. Only relevant for special file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_rdev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. + /// + /// The size of a symbolic link is the length of the pathname it contains, + /// without a terminating null byte. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_size()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + /// Returns the last access time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + /// Returns the last access time of the file, in nanoseconds since [`st_atime`]. + /// + /// [`st_atime`]: Self::st_atime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + /// Returns the last modification time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`]. + /// + /// [`st_mtime`]: Self::st_mtime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + /// Returns the last status change time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`]. + /// + /// [`st_ctime`]: Self::st_ctime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + /// Returns the "preferred" block size for efficient filesystem I/O. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blksize()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + /// Returns the number of blocks allocated to the file, 512-byte units. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::hurd::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blocks()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_fsid as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_sec as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_sec as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_sec as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/library/std/src/os/hurd/mod.rs b/library/std/src/os/hurd/mod.rs new file mode 100644 index 000000000000..aee86c7f6165 --- /dev/null +++ b/library/std/src/os/hurd/mod.rs @@ -0,0 +1,6 @@ +//! Hurd-specific definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod fs; +pub mod raw; diff --git a/library/std/src/os/hurd/raw.rs b/library/std/src/os/hurd/raw.rs new file mode 100644 index 000000000000..fa266663528c --- /dev/null +++ b/library/std/src/os/hurd/raw.rs @@ -0,0 +1,33 @@ +//! Hurd-specific raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#![allow(deprecated)] + +use crate::os::raw::{c_long, c_uint, c_ulong}; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blkcnt_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blksize_t = c_long; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type dev_t = c_ulong; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type ino_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type mode_t = c_uint; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type nlink_t = c_ulong; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type off_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type time_t = c_long; + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub type pthread_t = c_long; diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index de6d784c65b1..24d16e64c863 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -117,6 +117,8 @@ pub mod haiku; pub mod hermit; #[cfg(target_os = "horizon")] pub mod horizon; +#[cfg(target_os = "hurd")] +pub mod hurd; #[cfg(target_os = "illumos")] pub mod illumos; #[cfg(target_os = "ios")] diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index 401ec1e7a013..3724e90afbd1 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -53,6 +53,8 @@ mod platform { pub use crate::os::haiku::*; #[cfg(target_os = "horizon")] pub use crate::os::horizon::*; + #[cfg(target_os = "hurd")] + pub use crate::os::hurd::*; #[cfg(target_os = "illumos")] pub use crate::os::illumos::*; #[cfg(target_os = "ios")] diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index eafd6821f540..19334e2aff29 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -71,6 +71,7 @@ impl DoubleEndedIterator for Args { target_os = "vxworks", target_os = "horizon", target_os = "nto", + target_os = "hurd", ))] mod imp { use super::Args; diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs index 929e9dae7386..c6d8578a6298 100644 --- a/library/std/src/sys/unix/env.rs +++ b/library/std/src/sys/unix/env.rs @@ -152,6 +152,17 @@ pub mod os { pub const EXE_EXTENSION: &str = "elf"; } +#[cfg(target_os = "hurd")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "hurd"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "vita")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 85e020ae4132..6c4f408426a9 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -13,14 +13,16 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; target_os = "android", target_os = "linux", target_os = "emscripten", - target_os = "l4re" + target_os = "l4re", + target_os = "hurd", ))] use libc::off64_t; #[cfg(not(any( target_os = "linux", target_os = "emscripten", target_os = "l4re", - target_os = "android" + target_os = "android", + target_os = "hurd", )))] use libc::off_t as off64_t; @@ -124,9 +126,9 @@ impl FileDesc { } pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { - #[cfg(not(any(target_os = "linux", target_os = "android")))] + #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "hurd")))] use libc::pread as pread64; - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "android", target_os = "hurd"))] use libc::pread64; unsafe { @@ -160,6 +162,7 @@ impl FileDesc { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -181,6 +184,7 @@ impl FileDesc { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "ios", target_os = "tvos", @@ -281,9 +285,9 @@ impl FileDesc { } pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { - #[cfg(not(any(target_os = "linux", target_os = "android")))] + #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "hurd")))] use libc::pwrite as pwrite64; - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "android", target_os = "hurd"))] use libc::pwrite64; unsafe { @@ -301,6 +305,7 @@ impl FileDesc { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -322,6 +327,7 @@ impl FileDesc { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "ios", target_os = "tvos", diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 61ea87a5b0ce..764e1f257901 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -39,9 +39,14 @@ use libc::{c_int, mode_t}; all(target_os = "linux", target_env = "gnu") ))] use libc::c_char; -#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] +#[cfg(any( + target_os = "linux", + target_os = "emscripten", + target_os = "android", + target_os = "hurd", +))] use libc::dirfd; -#[cfg(any(target_os = "linux", target_os = "emscripten"))] +#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd"))] use libc::fstatat64; #[cfg(any( target_os = "android", @@ -53,7 +58,7 @@ use libc::fstatat64; target_os = "vita", ))] use libc::readdir as readdir64; -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "hurd"))] use libc::readdir64; #[cfg(any(target_os = "emscripten", target_os = "l4re"))] use libc::readdir64_r; @@ -68,6 +73,7 @@ use libc::readdir64_r; target_os = "redox", target_os = "nto", target_os = "vita", + target_os = "hurd", )))] use libc::readdir_r as readdir64_r; #[cfg(target_os = "android")] @@ -79,13 +85,19 @@ use libc::{ target_os = "linux", target_os = "emscripten", target_os = "l4re", - target_os = "android" + target_os = "android", + target_os = "hurd", )))] use libc::{ dirent as dirent64, fstat as fstat64, ftruncate as ftruncate64, lseek as lseek64, lstat as lstat64, off_t as off64_t, open as open64, stat as stat64, }; -#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))] +#[cfg(any( + target_os = "linux", + target_os = "emscripten", + target_os = "l4re", + target_os = "hurd" +))] use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64}; pub use crate::sys_common::fs::try_exists; @@ -277,7 +289,8 @@ unsafe impl Sync for Dir {} target_os = "fuchsia", target_os = "redox", target_os = "nto", - target_os = "vita" + target_os = "vita", + target_os = "hurd", ))] pub struct DirEntry { dir: Arc, @@ -300,6 +313,7 @@ pub struct DirEntry { target_os = "redox", target_os = "nto", target_os = "vita", + target_os = "hurd", ))] struct dirent64_min { d_ino: u64, @@ -321,6 +335,7 @@ struct dirent64_min { target_os = "redox", target_os = "nto", target_os = "vita", + target_os = "hurd", )))] pub struct DirEntry { dir: Arc, @@ -455,7 +470,8 @@ impl FileAttr { target_os = "vxworks", target_os = "espidf", target_os = "horizon", - target_os = "vita" + target_os = "vita", + target_os = "hurd", )))] pub fn modified(&self) -> io::Result { #[cfg(target_pointer_width = "32")] @@ -473,7 +489,7 @@ impl FileAttr { Ok(SystemTime::new(self.stat.st_mtime as i64, 0)) } - #[cfg(target_os = "horizon")] + #[cfg(any(target_os = "horizon", target_os = "hurd"))] pub fn modified(&self) -> io::Result { Ok(SystemTime::from(self.stat.st_mtim)) } @@ -482,7 +498,8 @@ impl FileAttr { target_os = "vxworks", target_os = "espidf", target_os = "horizon", - target_os = "vita" + target_os = "vita", + target_os = "hurd", )))] pub fn accessed(&self) -> io::Result { #[cfg(target_pointer_width = "32")] @@ -500,7 +517,7 @@ impl FileAttr { Ok(SystemTime::new(self.stat.st_atime as i64, 0)) } - #[cfg(target_os = "horizon")] + #[cfg(any(target_os = "horizon", target_os = "hurd"))] pub fn accessed(&self) -> io::Result { Ok(SystemTime::from(self.stat.st_atim)) } @@ -656,6 +673,7 @@ impl Iterator for ReadDir { target_os = "illumos", target_os = "nto", target_os = "vita", + target_os = "hurd", ))] fn next(&mut self) -> Option> { if self.end_of_stream { @@ -756,6 +774,7 @@ impl Iterator for ReadDir { target_os = "illumos", target_os = "nto", target_os = "vita", + target_os = "hurd", )))] fn next(&mut self) -> Option> { if self.end_of_stream { @@ -809,7 +828,12 @@ impl DirEntry { } #[cfg(all( - any(target_os = "linux", target_os = "emscripten", target_os = "android"), + any( + target_os = "linux", + target_os = "emscripten", + target_os = "android", + target_os = "hurd", + ), not(miri) ))] pub fn metadata(&self) -> io::Result { @@ -833,7 +857,12 @@ impl DirEntry { } #[cfg(any( - not(any(target_os = "linux", target_os = "emscripten", target_os = "android")), + not(any( + target_os = "linux", + target_os = "emscripten", + target_os = "android", + target_os = "hurd", + )), miri ))] pub fn metadata(&self) -> io::Result { @@ -892,6 +921,7 @@ impl DirEntry { target_os = "horizon", target_os = "vita", target_os = "nto", + target_os = "hurd", ))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 @@ -949,6 +979,7 @@ impl DirEntry { target_os = "redox", target_os = "nto", target_os = "vita", + target_os = "hurd", )))] fn name_cstr(&self) -> &CStr { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } @@ -962,6 +993,7 @@ impl DirEntry { target_os = "redox", target_os = "nto", target_os = "vita", + target_os = "hurd", ))] fn name_cstr(&self) -> &CStr { &self.name @@ -1131,6 +1163,7 @@ impl File { target_os = "netbsd", target_os = "openbsd", target_os = "nto", + target_os = "hurd", ))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) @@ -1146,6 +1179,7 @@ impl File { target_os = "openbsd", target_os = "watchos", target_os = "nto", + target_os = "hurd", )))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) @@ -1456,6 +1490,7 @@ impl fmt::Debug for File { target_os = "linux", target_os = "macos", target_os = "freebsd", + target_os = "hurd", target_os = "netbsd", target_os = "openbsd", target_os = "vxworks" @@ -1477,6 +1512,7 @@ impl fmt::Debug for File { target_os = "linux", target_os = "macos", target_os = "freebsd", + target_os = "hurd", target_os = "netbsd", target_os = "openbsd", target_os = "vxworks" diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index 4d17a1b00022..18acd5ecccd5 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -59,9 +59,9 @@ use crate::ptr; use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use crate::sys::cvt; use crate::sys::weak::syscall; -#[cfg(not(all(target_os = "linux", target_env = "gnu")))] +#[cfg(not(any(all(target_os = "linux", target_env = "gnu"), target_os = "hurd")))] use libc::sendfile as sendfile64; -#[cfg(all(target_os = "linux", target_env = "gnu"))] +#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_os = "hurd"))] use libc::sendfile64; use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV}; diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 692d3ab7cc97..3edafde71e93 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -204,6 +204,10 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { } if let Some(handler) = handler { rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR); + #[cfg(target_os = "hurd")] + { + rtassert!(signal(libc::SIGLOST, handler) != libc::SIG_ERR); + } } } } diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 48f163b6db09..f450d708dae6 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -75,6 +75,7 @@ impl Socket { target_os = "dragonfly", target_os = "freebsd", target_os = "illumos", + target_os = "hurd", target_os = "linux", target_os = "netbsd", target_os = "openbsd", @@ -114,6 +115,7 @@ impl Socket { target_os = "freebsd", target_os = "illumos", target_os = "linux", + target_os = "hurd", target_os = "netbsd", target_os = "openbsd", target_os = "nto", @@ -220,6 +222,7 @@ impl Socket { target_os = "freebsd", target_os = "illumos", target_os = "linux", + target_os = "hurd", target_os = "netbsd", target_os = "openbsd", ))] { diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 57e1a36dace9..01ff375d2151 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -46,7 +46,8 @@ extern "C" { target_os = "linux", target_os = "emscripten", target_os = "fuchsia", - target_os = "l4re" + target_os = "l4re", + target_os = "hurd", ), link_name = "__errno_location" )] @@ -121,7 +122,10 @@ pub fn set_errno(e: i32) { pub fn error_string(errno: i32) -> String { extern "C" { #[cfg_attr( - all(any(target_os = "linux", target_env = "newlib"), not(target_env = "ohos")), + all( + any(target_os = "linux", target_os = "hurd", target_env = "newlib"), + not(target_env = "ohos") + ), link_name = "__xpg_strerror_r" )] fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int; @@ -359,7 +363,12 @@ pub fn current_exe() -> io::Result { } } -#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))] +#[cfg(any( + target_os = "linux", + target_os = "hurd", + target_os = "android", + target_os = "emscripten" +))] pub fn current_exe() -> io::Result { match crate::fs::read_link("/proc/self/exe") { Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!( diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs index 938a46bfdd83..1239c65a483b 100644 --- a/library/std/src/sys/unix/pipe.rs +++ b/library/std/src/sys/unix/pipe.rs @@ -21,6 +21,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { if #[cfg(any( target_os = "dragonfly", target_os = "freebsd", + target_os = "hurd", target_os = "linux", target_os = "netbsd", target_os = "openbsd", diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 75b540645019..564f8c482902 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -374,6 +374,13 @@ impl Command { return Err(io::Error::last_os_error()); } } + #[cfg(target_os = "hurd")] + { + let ret = sys::signal(libc::SIGLOST, libc::SIG_DFL); + if ret == libc::SIG_ERR { + return Err(io::Error::last_os_error()); + } + } } } @@ -620,6 +627,10 @@ impl Command { let mut default_set = MaybeUninit::::uninit(); cvt(sigemptyset(default_set.as_mut_ptr()))?; cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGPIPE))?; + #[cfg(target_os = "hurd")] + { + cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGLOST))?; + } cvt_nz(libc::posix_spawnattr_setsigdefault( attrs.0.as_mut_ptr(), default_set.as_ptr(), @@ -993,6 +1004,8 @@ fn signal_string(signal: i32) -> &'static str { target_os = "dragonfly" ))] libc::SIGINFO => " (SIGINFO)", + #[cfg(target_os = "hurd")] + libc::SIGLOST => " (SIGLOST)", _ => "", } } diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs index b59d4ba26afb..73c530786b2f 100644 --- a/library/std/src/sys/unix/stack_overflow.rs +++ b/library/std/src/sys/unix/stack_overflow.rs @@ -32,6 +32,7 @@ impl Drop for Handler { target_os = "macos", target_os = "dragonfly", target_os = "freebsd", + target_os = "hurd", target_os = "solaris", target_os = "illumos", target_os = "netbsd", @@ -193,6 +194,7 @@ mod imp { target_os = "macos", target_os = "dragonfly", target_os = "freebsd", + target_os = "hurd", target_os = "solaris", target_os = "illumos", target_os = "netbsd", diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 7c242d4d3345..3631a5bbabd9 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -216,7 +216,8 @@ impl Thread { target_os = "l4re", target_os = "emscripten", target_os = "redox", - target_os = "vxworks" + target_os = "vxworks", + target_os = "hurd", ))] pub fn set_name(_name: &CStr) { // Newlib, Emscripten, and VxWorks have no way to set a thread name. @@ -309,6 +310,7 @@ pub fn available_parallelism() -> io::Result { target_os = "android", target_os = "emscripten", target_os = "fuchsia", + target_os = "hurd", target_os = "ios", target_os = "tvos", target_os = "linux", @@ -690,6 +692,7 @@ mod cgroups { #[cfg(all( not(target_os = "linux"), not(target_os = "freebsd"), + not(target_os = "hurd"), not(target_os = "macos"), not(target_os = "netbsd"), not(target_os = "openbsd"), @@ -710,6 +713,7 @@ pub mod guard { #[cfg(any( target_os = "linux", target_os = "freebsd", + target_os = "hurd", target_os = "macos", target_os = "netbsd", target_os = "openbsd", @@ -766,6 +770,7 @@ pub mod guard { #[cfg(any( target_os = "android", target_os = "freebsd", + target_os = "hurd", target_os = "linux", target_os = "netbsd", target_os = "l4re" @@ -903,6 +908,7 @@ pub mod guard { #[cfg(any( target_os = "android", target_os = "freebsd", + target_os = "hurd", target_os = "linux", target_os = "netbsd", target_os = "l4re" @@ -934,7 +940,7 @@ pub mod guard { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackptr, &mut size), 0); let stackaddr = stackptr.addr(); - ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd")) { + ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "hurd")) { Some(stackaddr - guardsize..stackaddr) } else if cfg!(all(target_os = "linux", target_env = "musl")) { Some(stackaddr - guardsize..stackaddr) diff --git a/library/std/src/sys/unix/thread_local_dtor.rs b/library/std/src/sys/unix/thread_local_dtor.rs index 236d2f2ee292..1da41d4b4bfc 100644 --- a/library/std/src/sys/unix/thread_local_dtor.rs +++ b/library/std/src/sys/unix/thread_local_dtor.rs @@ -11,7 +11,7 @@ // Note, however, that we run on lots older linuxes, as well as cross // compiling from a newer linux to an older linux, so we also have a // fallback implementation to use as well. -#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))] +#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox", target_os = "hurd"))] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { use crate::mem; use crate::sys_common::thread_local_dtor::register_dtor_fallback; diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 17b4130c2024..4fe61b28488b 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -35,7 +35,7 @@ pub(in crate::sys::unix) struct Timespec { } impl SystemTime { - #[cfg_attr(target_os = "horizon", allow(unused))] + #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))] pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime { SystemTime { t: Timespec::new(tv_sec, tv_nsec) } } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 2976a9f578ed..4f5b17deaa2d 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -32,6 +32,7 @@ cfg_if::cfg_if! { cfg_if::cfg_if! { if #[cfg(any( target_os = "linux", target_os = "android", + target_os = "hurd", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "haiku", target_os = "nto"))] { diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 62e97c65569f..df4f286a526b 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -148,3 +148,7 @@ extern "C" {} #[cfg(target_os = "nto")] #[link(name = "gcc_s")] extern "C" {} + +#[cfg(target_os = "hurd")] +#[link(name = "gcc_s")] +extern "C" {} diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index a9aa7524e8bc..d58f0d54d3ae 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -265,7 +265,8 @@ def default_build_triple(verbose): 'FreeBSD': 'unknown-freebsd', 'Haiku': 'unknown-haiku', 'NetBSD': 'unknown-netbsd', - 'OpenBSD': 'unknown-openbsd' + 'OpenBSD': 'unknown-openbsd', + 'GNU': 'unknown-hurd', } # Consider the direct transformation first and then the special cases @@ -336,6 +337,7 @@ def default_build_triple(verbose): 'i386': 'i686', 'i486': 'i686', 'i686': 'i686', + 'i686-AT386': 'i686', 'i786': 'i686', 'loongarch64': 'loongarch64', 'm68k': 'm68k', diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 1e001fae8ab4..8b8d4b237953 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -133,7 +133,9 @@ const EXTRA_CHECK_CFGS: &[(Option, &str, Option<&[&'static str]>)] = &[ // #[cfg(bootstrap)] (Some(Mode::Std), "target_vendor", Some(&["unikraft"])), (Some(Mode::Std), "target_env", Some(&["libnx"])), - (Some(Mode::Std), "target_os", Some(&["teeos"])), + // #[cfg(bootstrap)] hurd + (Some(Mode::Std), "target_os", Some(&["teeos", "hurd"])), + (Some(Mode::Rustc), "target_os", Some(&["hurd"])), // #[cfg(bootstrap)] mips32r6, mips64r6 ( Some(Mode::Std), diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 94605e2a2170..5c6633864464 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -28,6 +28,7 @@ - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) - [\*-android and \*-androideabi](platform-support/android.md) - [\*-linux-ohos](platform-support/openharmony.md) + - [\*-hurd-gnu](platform-support/hurd.md) - [aarch64-unknown-teeos](platform-support/aarch64-unknown-teeos.md) - [\*-esp-espidf](platform-support/esp-idf.md) - [\*-unknown-fuchsia](platform-support/fuchsia.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 70b35526ee58..7c0c56035c02 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -269,6 +269,7 @@ target | std | host | notes `i686-pc-windows-msvc` | * | | 32-bit Windows XP support [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku +[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD `i686-uwp-windows-gnu` | ? | | diff --git a/src/doc/rustc/src/platform-support/hurd.md b/src/doc/rustc/src/platform-support/hurd.md new file mode 100644 index 000000000000..ddf40213ed49 --- /dev/null +++ b/src/doc/rustc/src/platform-support/hurd.md @@ -0,0 +1,35 @@ +# `i686-unknown-hurd-gnu` + +**Tier: 3** + +[GNU/Hurd] is the GNU Hurd is the GNU project's replacement for the Unix kernel. + +## Target maintainers + +- Samuel Thibault, `samuel.thibault@ens-lyon.org`, https://github.com/sthibaul/ + +## Requirements + +The target supports host tools. + +The GNU/Hurd target supports `std` and uses the standard ELF file format. + +## Building the target + +This target can be built by adding `i686-unknown-hurd-gnu` as target in the rustc list. + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will either need to build Rust with the target enabled (see +"Building the target" above), or build your own copy of `core` by using +`build-std` or similar. + +## Testing + +Tests can be run in the same way as a regular binary. + +## Cross-compilation toolchains and C code + +The target supports C code, the GNU toolchain calls the target +`i686-unknown-gnu`. diff --git a/tests/ui/check-cfg/values-target-json.stderr b/tests/ui/check-cfg/values-target-json.stderr index e773d5d83ccf..c705152d9fc6 100644 --- a/tests/ui/check-cfg/values-target-json.stderr +++ b/tests/ui/check-cfg/values-target-json.stderr @@ -6,7 +6,7 @@ LL | #[cfg(target_os = "linuz")] | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `ericos`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `ericos`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` = note: `#[warn(unexpected_cfgs)]` on by default warning: 1 warning emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 1f7758146563..b381f5a4a0a1 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -6,7 +6,7 @@ LL | #[cfg(target_os = "linuz")] | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs index b99bb39d062c..30b8a21269a9 100644 --- a/tests/ui/intrinsics/intrinsic-alignment.rs +++ b/tests/ui/intrinsics/intrinsic-alignment.rs @@ -16,6 +16,7 @@ mod rusti { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "linux", target_os = "macos", diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs index f21c9b2c808c..c3b201fb1c66 100644 --- a/tests/ui/structs-enums/rec-align-u64.rs +++ b/tests/ui/structs-enums/rec-align-u64.rs @@ -37,6 +37,7 @@ struct Outer { target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "linux", target_os = "macos", From 087a571e708560bad84b1dd8de107c8fdc2a3044 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 14 Sep 2023 22:38:07 +0000 Subject: [PATCH 21/26] Record asyncness span in HIR --- compiler/rustc_ast_lowering/src/item.rs | 2 +- .../src/diagnostics/region_name.rs | 2 +- compiler/rustc_hir/src/hir.rs | 18 +++++------ .../src/check/compare_impl_item.rs | 2 +- .../rustc_hir_analysis/src/check/entry.rs | 4 +-- .../src/collect/resolve_bound_vars.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 2 +- .../src/fn_ctxt/suggestions.rs | 4 +-- compiler/rustc_lint/src/builtin.rs | 3 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_metadata/src/rmeta/table.rs | 6 ++-- compiler/rustc_middle/src/query/erase.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 13 ++++++++ compiler/rustc_middle/src/ty/parameterized.rs | 1 + .../error_reporting/on_unimplemented.rs | 6 ++-- compiler/rustc_ty_utils/src/ty.rs | 7 ++-- src/librustdoc/clean/types.rs | 8 +++-- src/librustdoc/html/format.rs | 2 +- .../src/redundant_closure_call.rs | 7 ++-- src/tools/clippy/clippy_utils/src/lib.rs | 6 ++-- tests/ui/stats/hir-stats.stderr | 32 +++++++++---------- 22 files changed, 78 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a59c83de0f46..edc1e2f0b84d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1308,7 +1308,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync { match a { - Async::Yes { .. } => hir::IsAsync::Async, + Async::Yes { span, .. } => hir::IsAsync::Async(span), Async::No => hir::IsAsync::NotAsync, } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index b40e89e471d6..096bf826cfb3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -302,7 +302,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { if free_region.bound_region.is_named() { // A named region that is actually named. Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) }) - } else if let hir::IsAsync::Async = tcx.asyncness(self.mir_hir_id().owner) { + } else if tcx.asyncness(self.mir_hir_id().owner).is_async() { // If we spuriously thought that the region is named, we should let the // system generate a true name for error messages. Currently this can // happen if we have an elided name in an async fn for example: the diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 0c4a0e5d4a5e..3eec66611edd 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2853,13 +2853,13 @@ impl ImplicitSelfKind { #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] #[derive(HashStable_Generic)] pub enum IsAsync { - Async, + Async(Span), NotAsync, } impl IsAsync { pub fn is_async(self) -> bool { - self == IsAsync::Async + matches!(self, IsAsync::Async(_)) } } @@ -3296,7 +3296,7 @@ pub struct FnHeader { impl FnHeader { pub fn is_async(&self) -> bool { - matches!(&self.asyncness, IsAsync::Async) + matches!(&self.asyncness, IsAsync::Async(_)) } pub fn is_const(&self) -> bool { @@ -4091,10 +4091,10 @@ mod size_asserts { static_assert_size!(GenericBound<'_>, 48); static_assert_size!(Generics<'_>, 56); static_assert_size!(Impl<'_>, 80); - static_assert_size!(ImplItem<'_>, 80); - static_assert_size!(ImplItemKind<'_>, 32); - static_assert_size!(Item<'_>, 80); - static_assert_size!(ItemKind<'_>, 48); + static_assert_size!(ImplItem<'_>, 88); + static_assert_size!(ImplItemKind<'_>, 40); + static_assert_size!(Item<'_>, 88); + static_assert_size!(ItemKind<'_>, 56); static_assert_size!(Local<'_>, 64); static_assert_size!(Param<'_>, 32); static_assert_size!(Pat<'_>, 72); @@ -4105,8 +4105,8 @@ mod size_asserts { static_assert_size!(Res, 12); static_assert_size!(Stmt<'_>, 32); static_assert_size!(StmtKind<'_>, 16); - static_assert_size!(TraitItem<'_>, 80); - static_assert_size!(TraitItemKind<'_>, 40); + static_assert_size!(TraitItem<'_>, 88); + static_assert_size!(TraitItemKind<'_>, 48); static_assert_size!(Ty<'_>, 48); static_assert_size!(TyKind<'_>, 32); // tidy-alphabetical-end diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 38f19aa09adf..7be18a36d636 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -595,7 +595,7 @@ fn compare_asyncness<'tcx>( trait_m: ty::AssocItem, delay: bool, ) -> Result<(), ErrorGuaranteed> { - if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async { + if tcx.asyncness(trait_m.def_id).is_async() { match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() { ty::Alias(ty::Opaque, ..) => { // allow both `async fn foo()` and `fn foo() -> impl Future` diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index fcaefe0261b0..cede7493093b 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -112,7 +112,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } let main_asyncness = tcx.asyncness(main_def_id); - if let hir::IsAsync::Async = main_asyncness { + if main_asyncness.is_async() { let asyncness_span = main_fn_asyncness_span(tcx, main_def_id); tcx.sess.emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span }); error = true; @@ -212,7 +212,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { }); error = true; } - if let hir::IsAsync::Async = sig.header.asyncness { + if sig.header.asyncness.is_async() { let span = tcx.def_span(it.owner_id); tcx.sess.emit_err(errors::StartAsync { span: span }); error = true; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 6869c8696038..a39cfd7b6e16 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1213,7 +1213,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { && let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id)) && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id) && param.is_elided_lifetime() - && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id) + && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async() && !self.tcx.features().anonymous_lifetime_in_impl_trait { let mut diag = rustc_session::parse::feature_err( diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 89efdc269c46..8587b009f25a 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2304,7 +2304,7 @@ impl<'a> State<'a> { match header.asyncness { hir::IsAsync::NotAsync => {} - hir::IsAsync::Async => self.word_nbsp("async"), + hir::IsAsync::Async(_) => self.word_nbsp("async"), } self.print_unsafety(header.unsafety); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index d2a53ee8b5e1..41f815a812a0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -987,10 +987,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bound_vars = self.tcx.late_bound_vars(fn_id); let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars)); let ty = match self.tcx.asyncness(fn_id.owner) { - hir::IsAsync::Async => self.get_impl_future_output_ty(ty).unwrap_or_else(|| { + ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| { span_bug!(fn_decl.output.span(), "failed to get output type of async function") }), - hir::IsAsync::NotAsync => ty, + ty::Asyncness::No => ty, }; let ty = self.normalize(expr.span, ty); if self.can_coerce(found, ty) { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index de228bdb8503..d38c6b2642aa 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -41,7 +41,6 @@ use crate::{ }, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, }; -use hir::IsAsync; use rustc_ast::attr; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; @@ -1294,7 +1293,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { span: Span, def_id: LocalDefId, ) { - if fn_kind.asyncness() == IsAsync::Async + if fn_kind.asyncness().is_async() && !cx.tcx.features().async_fn_track_caller // Now, check if the function has the `#[track_caller]` attribute && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 71269779d423..f2875bb11b1a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -439,7 +439,7 @@ define_tables! { coerce_unsized_info: Table>, mir_const_qualif: Table>, rendered_const: Table>, - asyncness: Table, + asyncness: Table, fn_arg_names: Table>, generator_kind: Table>, trait_def: Table>, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 35987072ed6b..d105dab48146 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -205,9 +205,9 @@ fixed_size_enum! { } fixed_size_enum! { - hir::IsAsync { - ( NotAsync ) - ( Async ) + ty::Asyncness { + ( Yes ) + ( No ) } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index d41b38a8b4bc..8ba3764bcc31 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -265,6 +265,7 @@ trivial! { rustc_middle::ty::adjustment::CoerceUnsizedInfo, rustc_middle::ty::AssocItem, rustc_middle::ty::AssocItemContainer, + rustc_middle::ty::Asyncness, rustc_middle::ty::BoundVariableKind, rustc_middle::ty::DeducedParamAttrs, rustc_middle::ty::Destructor, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0241820ab722..07160e41c94a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -731,7 +731,7 @@ rustc_queries! { separate_provide_extern } - query asyncness(key: DefId) -> hir::IsAsync { + query asyncness(key: DefId) -> ty::Asyncness { desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } separate_provide_extern } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dbff13fdd8e9..b050208b4a6c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -280,6 +280,19 @@ impl fmt::Display for ImplPolarity { } } +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum Asyncness { + Yes, + No, +} + +impl Asyncness { + pub fn is_async(self) -> bool { + matches!(self, Asyncness::Yes) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)] pub enum Visibility { /// Visible everywhere (including in other crates). diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index f1c38984296c..f1093e88312f 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -62,6 +62,7 @@ trivially_parameterized_over_tcx! { crate::middle::resolve_bound_vars::ObjectLifetimeDefault, crate::mir::ConstQualifs, ty::AssocItemContainer, + ty::Asyncness, ty::DeducedParamAttrs, ty::Generics, ty::ImplPolarity, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 4086db2ab557..d645dc033b81 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -104,7 +104,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => { self.describe_generator(*body_id).or_else(|| { Some(match sig.header { - hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async function", + hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => { + "an async function" + } _ => "a function", }) }) @@ -118,7 +120,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .. }) => self.describe_generator(*body_id).or_else(|| { Some(match sig.header { - hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async method", + hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => "an async method", _ => "a method", }) }), diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2288d36df17b..6c23589b39ad 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -296,9 +296,12 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option, def_id: LocalDefId) -> hir::IsAsync { +fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Asyncness { let node = tcx.hir().get_by_def_id(def_id); - node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness) + node.fn_sig().map_or(ty::Asyncness::No, |sig| match sig.header.asyncness { + hir::IsAsync::Async(_) => ty::Asyncness::Yes, + hir::IsAsync::NotAsync => ty::Asyncness::No, + }) } fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ef7794cc41e2..b665f6841678 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -31,7 +31,7 @@ use rustc_resolve::rustdoc::{ use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{self, FileName, Loc}; +use rustc_span::{self, FileName, Loc, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; @@ -622,7 +622,7 @@ impl Item { fn build_fn_header( def_id: DefId, tcx: TyCtxt<'_>, - asyncness: hir::IsAsync, + asyncness: ty::Asyncness, ) -> hir::FnHeader { let sig = tcx.fn_sig(def_id).skip_binder(); let constness = @@ -631,6 +631,10 @@ impl Item { } else { hir::Constness::NotConst }; + let asyncness = match asyncness { + ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP), + ty::Asyncness::No => hir::IsAsync::NotAsync, + }; hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness } } let header = match *self.kind { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 2f611c31a074..170e559e6980 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1599,7 +1599,7 @@ impl PrintWithSpace for hir::Unsafety { impl PrintWithSpace for hir::IsAsync { fn print_with_space(&self) -> &str { match self { - hir::IsAsync::Async => "async ", + hir::IsAsync::Async(_) => "async ", hir::IsAsync::NotAsync => "", } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index fc49b58e0a77..f42836611ca5 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -10,6 +10,7 @@ use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -84,7 +85,7 @@ fn find_innermost_closure<'tcx>( cx: &LateContext<'tcx>, mut expr: &'tcx hir::Expr<'tcx>, mut steps: usize, -) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, hir::IsAsync)> { +) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, ty::Asyncness)> { let mut data = None; while let hir::ExprKind::Closure(closure) = expr.kind @@ -98,9 +99,9 @@ fn find_innermost_closure<'tcx>( { expr = body.value; data = Some((body.value, closure.fn_decl, if is_async_closure(body) { - hir::IsAsync::Async + ty::Asyncness::Yes } else { - hir::IsAsync::NotAsync + ty::Asyncness::No })); steps -= 1; } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 1e464db8087e..be1c46319c2b 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -90,7 +90,7 @@ use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr, - ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, + ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, }; @@ -1958,8 +1958,8 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, /// Checks if the given function kind is an async function. pub fn is_async_fn(kind: FnKind<'_>) -> bool { match kind { - FnKind::ItemFn(_, _, header) => header.asyncness == IsAsync::Async, - FnKind::Method(_, sig) => sig.header.asyncness == IsAsync::Async, + FnKind::ItemFn(_, _, header) => header.asyncness .is_async(), + FnKind::Method(_, sig) => sig.header.asyncness.is_async(), FnKind::Closure => false, } } diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index d723ff538a88..813e65e45a25 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -146,33 +146,33 @@ hir-stats - Trait 192 ( 2.1%) 4 hir-stats WherePredicate 192 ( 2.1%) 3 64 hir-stats - BoundPredicate 192 ( 2.1%) 3 hir-stats Block 288 ( 3.2%) 6 48 -hir-stats Pat 360 ( 4.0%) 5 72 +hir-stats Pat 360 ( 3.9%) 5 72 hir-stats - Wild 72 ( 0.8%) 1 hir-stats - Struct 72 ( 0.8%) 1 hir-stats - Binding 216 ( 2.4%) 3 hir-stats GenericParam 400 ( 4.4%) 5 80 -hir-stats Generics 560 ( 6.2%) 10 56 -hir-stats Ty 720 ( 8.0%) 15 48 +hir-stats Generics 560 ( 6.1%) 10 56 +hir-stats Ty 720 ( 7.9%) 15 48 hir-stats - Ptr 48 ( 0.5%) 1 hir-stats - Ref 48 ( 0.5%) 1 -hir-stats - Path 624 ( 6.9%) 13 -hir-stats Expr 768 ( 8.5%) 12 64 +hir-stats - Path 624 ( 6.8%) 13 +hir-stats Expr 768 ( 8.4%) 12 64 hir-stats - Path 64 ( 0.7%) 1 hir-stats - Struct 64 ( 0.7%) 1 hir-stats - Match 64 ( 0.7%) 1 hir-stats - InlineAsm 64 ( 0.7%) 1 hir-stats - Lit 128 ( 1.4%) 2 hir-stats - Block 384 ( 4.2%) 6 -hir-stats Item 880 ( 9.7%) 11 80 -hir-stats - Trait 80 ( 0.9%) 1 -hir-stats - Enum 80 ( 0.9%) 1 -hir-stats - ExternCrate 80 ( 0.9%) 1 -hir-stats - ForeignMod 80 ( 0.9%) 1 -hir-stats - Impl 80 ( 0.9%) 1 -hir-stats - Fn 160 ( 1.8%) 2 -hir-stats - Use 320 ( 3.5%) 4 -hir-stats Path 1_240 (13.7%) 31 40 -hir-stats PathSegment 1_920 (21.2%) 40 48 +hir-stats Item 968 (10.6%) 11 88 +hir-stats - Trait 88 ( 1.0%) 1 +hir-stats - Enum 88 ( 1.0%) 1 +hir-stats - ExternCrate 88 ( 1.0%) 1 +hir-stats - ForeignMod 88 ( 1.0%) 1 +hir-stats - Impl 88 ( 1.0%) 1 +hir-stats - Fn 176 ( 1.9%) 2 +hir-stats - Use 352 ( 3.9%) 4 +hir-stats Path 1_240 (13.6%) 31 40 +hir-stats PathSegment 1_920 (21.0%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 9_048 +hir-stats Total 9_136 hir-stats From 9072415252d6dde7f23acc21a6781f27c703ac9d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 15 Sep 2023 05:00:39 +0000 Subject: [PATCH 22/26] Suggest desugaring to RPITIT when AFIT is required to be an auto trait --- .../src/traits/error_reporting/mod.rs | 1 + .../src/traits/error_reporting/suggestions.rs | 136 ++++++++++++++++++ .../in-trait/auxiliary/foreign-async-fn.rs | 7 + .../in-trait/missing-send-bound.stderr | 5 + .../in-trait/send-on-async-fn-in-trait.fixed | 20 +++ .../in-trait/send-on-async-fn-in-trait.rs | 20 +++ .../in-trait/send-on-async-fn-in-trait.stderr | 43 ++++++ .../send-on-foreign-async-fn-in-trait.rs | 15 ++ .../send-on-foreign-async-fn-in-trait.stderr | 23 +++ 9 files changed, 270 insertions(+) create mode 100644 tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs create mode 100644 tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed create mode 100644 tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs create mode 100644 tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr create mode 100644 tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs create mode 100644 tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr 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 7d754cbafa34..d3e0d3b8b181 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -987,6 +987,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause); + self.suggest_desugaring_async_fn_in_trait(&mut err, trait_ref); // Return early if the trait is Debug or Display and the invocation // originates within a standard library macro, because the output 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 a08ebe5a9ea8..17e0e4fcb484 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -414,6 +414,12 @@ pub trait TypeErrCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, cause: &ObligationCause<'tcx>, ); + + fn suggest_desugaring_async_fn_in_trait( + &self, + err: &mut Diagnostic, + trait_ref: ty::PolyTraitRef<'tcx>, + ); } fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) { @@ -4100,6 +4106,136 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }); } } + + fn suggest_desugaring_async_fn_in_trait( + &self, + err: &mut Diagnostic, + trait_ref: ty::PolyTraitRef<'tcx>, + ) { + // Don't suggest if RTN is active -- we should prefer a where-clause bound instead. + if self.tcx.features().return_type_notation { + return; + } + + let trait_def_id = trait_ref.def_id(); + + // Only suggest specifying auto traits + if !self.tcx.trait_is_auto(trait_def_id) { + return; + } + + // Look for an RPITIT + let ty::Alias(ty::Projection, alias_ty) = trait_ref.self_ty().skip_binder().kind() else { + return; + }; + let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) = + self.tcx.opt_rpitit_info(alias_ty.def_id) + else { + return; + }; + + let auto_trait = self.tcx.def_path_str(trait_def_id); + // ... which is a local function + let Some(fn_def_id) = fn_def_id.as_local() else { + // If it's not local, we can at least mention that the method is async, if it is. + if self.tcx.asyncness(fn_def_id).is_async() { + err.span_note( + self.tcx.def_span(fn_def_id), + format!( + "`{}::{}` is an `async fn` in trait, which does not \ + automatically imply that its future is `{auto_trait}`", + alias_ty.trait_ref(self.tcx), + self.tcx.item_name(fn_def_id) + ), + ); + } + return; + }; + let Some(hir::Node::TraitItem(item)) = self.tcx.hir().find_by_def_id(fn_def_id) else { + return; + }; + + // ... whose signature is `async` (i.e. this is an AFIT) + let (sig, body) = item.expect_fn(); + let hir::IsAsync::Async(async_span) = sig.header.asyncness else { + return; + }; + let Ok(async_span) = + self.tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace()) + else { + return; + }; + let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) = + sig.decl.output + else { + // This should never happen, but let's not ICE. + return; + }; + + // Check that this is *not* a nested `impl Future` RPIT in an async fn + // (i.e. `async fn foo() -> impl Future`) + if def.owner_id.to_def_id() != opaque_def_id { + return; + } + + let future = self.tcx.hir().item(*def).expect_opaque_ty(); + let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else { + // `async fn` should always lower to a lang item bound... but don't ICE. + return; + }; + let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) = + generics.bindings.get(0).map(|binding| binding.kind) + else { + // Also should never happen. + return; + }; + + let function_name = self.tcx.def_path_str(fn_def_id); + + let mut sugg = if future_output_ty.span.is_empty() { + vec![ + (async_span, String::new()), + ( + future_output_ty.span, + format!(" -> impl std::future::Future + {auto_trait}"), + ), + ] + } else { + vec![ + ( + future_output_ty.span.shrink_to_lo(), + "impl std::future::Future + {auto_trait}")), + (async_span, String::new()), + ] + }; + + // If there's a body, we also need to wrap it in `async {}` + if let hir::TraitFn::Provided(body) = body { + let body = self.tcx.hir().body(*body); + let body_span = body.value.span; + let body_span_without_braces = + body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1)); + if body_span_without_braces.is_empty() { + sugg.push((body_span_without_braces, " async {} ".to_owned())); + } else { + sugg.extend([ + (body_span_without_braces.shrink_to_lo(), "async {".to_owned()), + (body_span_without_braces.shrink_to_hi(), "} ".to_owned()), + ]); + } + } + + err.multipart_suggestion( + format!( + "`{auto_trait}` can be made part of the associated future's \ + guarantees for all implementations of `{function_name}`" + ), + sugg, + Applicability::MachineApplicable, + ); + } } /// Add a hint to add a missing borrow or remove an unnecessary one. diff --git a/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs b/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs new file mode 100644 index 000000000000..bba886f175ee --- /dev/null +++ b/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs @@ -0,0 +1,7 @@ +// edition:2021 + +#![feature(async_fn_in_trait)] + +pub trait Foo { + async fn test(); +} diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.stderr index 18185b75554a..7e59d94d456d 100644 --- a/tests/ui/async-await/in-trait/missing-send-bound.stderr +++ b/tests/ui/async-await/in-trait/missing-send-bound.stderr @@ -15,6 +15,11 @@ note: required by a bound in `assert_is_send` | LL | fn assert_is_send(_: impl Send) {} | ^^^^ required by this bound in `assert_is_send` +help: `Send` can be made part of the associated future's guarantees for all implementations of `Foo::bar` + | +LL - async fn bar(); +LL + fn bar() -> impl std::future::Future + Send; + | error: aborting due to previous error diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed new file mode 100644 index 000000000000..33c005874397 --- /dev/null +++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed @@ -0,0 +1,20 @@ +// run-rustfix +// edition: 2021 + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] +#![allow(unused)] + +trait Foo { + fn test() -> impl std::future::Future + Send { async {} } + fn test2() -> impl std::future::Future + Send {async { 1 + 2 } } +} + +fn bar() { + fn needs_send(_: impl Send) {} + needs_send(T::test()); + //~^ ERROR `impl Future` cannot be sent between threads safely + needs_send(T::test2()); + //~^ ERROR `impl Future` cannot be sent between threads safely +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs new file mode 100644 index 000000000000..96b623d6988f --- /dev/null +++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs @@ -0,0 +1,20 @@ +// run-rustfix +// edition: 2021 + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] +#![allow(unused)] + +trait Foo { + async fn test() -> () {} + async fn test2() -> i32 { 1 + 2 } +} + +fn bar() { + fn needs_send(_: impl Send) {} + needs_send(T::test()); + //~^ ERROR `impl Future` cannot be sent between threads safely + needs_send(T::test2()); + //~^ ERROR `impl Future` cannot be sent between threads safely +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr new file mode 100644 index 000000000000..4319a14118b9 --- /dev/null +++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr @@ -0,0 +1,43 @@ +error[E0277]: `impl Future` cannot be sent between threads safely + --> $DIR/send-on-async-fn-in-trait.rs:14:16 + | +LL | needs_send(T::test()); + | ---------- ^^^^^^^^^ `impl Future` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Send` is not implemented for `impl Future` +note: required by a bound in `needs_send` + --> $DIR/send-on-async-fn-in-trait.rs:13:27 + | +LL | fn needs_send(_: impl Send) {} + | ^^^^ required by this bound in `needs_send` +help: `Send` can be made part of the associated future's guarantees for all implementations of `Foo::test` + | +LL - async fn test() -> () {} +LL + fn test() -> impl std::future::Future + Send { async {} } + | + +error[E0277]: `impl Future` cannot be sent between threads safely + --> $DIR/send-on-async-fn-in-trait.rs:16:16 + | +LL | needs_send(T::test2()); + | ---------- ^^^^^^^^^^ `impl Future` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Send` is not implemented for `impl Future` +note: required by a bound in `needs_send` + --> $DIR/send-on-async-fn-in-trait.rs:13:27 + | +LL | fn needs_send(_: impl Send) {} + | ^^^^ required by this bound in `needs_send` +help: `Send` can be made part of the associated future's guarantees for all implementations of `Foo::test2` + | +LL - async fn test2() -> i32 { 1 + 2 } +LL + fn test2() -> impl std::future::Future + Send {async { 1 + 2 } } + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs new file mode 100644 index 000000000000..83b69d72a960 --- /dev/null +++ b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs @@ -0,0 +1,15 @@ +// aux-build:foreign-async-fn.rs +// edition:2021 + +#![feature(async_fn_in_trait)] + +extern crate foreign_async_fn; +use foreign_async_fn::Foo; + +fn bar() { + fn needs_send(_: impl Send) {} + needs_send(T::test()); + //~^ ERROR `impl Future` cannot be sent between threads safely +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr new file mode 100644 index 000000000000..f337a04ba194 --- /dev/null +++ b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr @@ -0,0 +1,23 @@ +error[E0277]: `impl Future` cannot be sent between threads safely + --> $DIR/send-on-foreign-async-fn-in-trait.rs:11:16 + | +LL | needs_send(T::test()); + | ---------- ^^^^^^^^^ `impl Future` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Send` is not implemented for `impl Future` +note: `::test` is an `async fn` in trait, which does not automatically imply that its future is `Send` + --> $DIR/auxiliary/foreign-async-fn.rs:6:5 + | +LL | async fn test(); + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `needs_send` + --> $DIR/send-on-foreign-async-fn-in-trait.rs:10:27 + | +LL | fn needs_send(_: impl Send) {} + | ^^^^ required by this bound in `needs_send` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From d5ec9af09da9f6d96b350ee53fffdad58721d32e Mon Sep 17 00:00:00 2001 From: Arthur Lafrance Date: Thu, 21 Sep 2023 20:42:21 -0700 Subject: [PATCH 23/26] Add test to guard against VecDeque optimization regression --- tests/codegen/vecdeque-nonempty-get-no-panic.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/codegen/vecdeque-nonempty-get-no-panic.rs diff --git a/tests/codegen/vecdeque-nonempty-get-no-panic.rs b/tests/codegen/vecdeque-nonempty-get-no-panic.rs new file mode 100644 index 000000000000..c2877d2d0ca9 --- /dev/null +++ b/tests/codegen/vecdeque-nonempty-get-no-panic.rs @@ -0,0 +1,17 @@ +// Guards against regression for optimization discussed in issue #80836 + +// compile-flags: -O +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] + +use std::collections::VecDeque; + +// CHECK-LABEL: @front +// CHECK: ret void +#[no_mangle] +pub fn front(v: VecDeque) { + if !v.is_empty() { + v.get(0).unwrap(); + } +} From 5211d045c9aa105cd241106183366da5e6d6416c Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Fri, 22 Sep 2023 05:29:34 +0000 Subject: [PATCH 24/26] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index f6db58695fbc..b01db9e388a5 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -4fda889bf8735755573b27e6116ce025f3ded5f9 +b7573187180a6ad13ba557f85b7e19a51f8fdaf1 From e6a4a1b12e0d8df98d80c1f4f4c3b09b9b994257 Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Fri, 22 Sep 2023 05:40:22 +0000 Subject: [PATCH 25/26] fmt --- src/tools/miri/src/helpers.rs | 4 ++-- src/tools/miri/src/operator.rs | 14 +++++++++----- src/tools/miri/src/shims/x86/sse2.rs | 22 ++++------------------ 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 537c767065d9..badd2629388c 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1033,7 +1033,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) { // Floating point value is NaN (flagged with INVALID_OP) or outside the range // of values of the integer type (flagged with OVERFLOW or UNDERFLOW). - return None + return None; } else { // Floating point value can be represented by the integer type after rounding. // The INEXACT flag is ignored on purpose to allow rounding. @@ -1051,7 +1051,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) { // Floating point value is NaN (flagged with INVALID_OP) or outside the range // of values of the integer type (flagged with OVERFLOW or UNDERFLOW). - return None + return None; } else { // Floating point value can be represented by the integer type after rounding. // The INEXACT flag is ignored on purpose to allow rounding. diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 27fe7374ea5d..1faf8f9fc122 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -65,12 +65,16 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { right.to_scalar().to_target_usize(self)?, self.machine.layouts.usize, ); - let (result, overflowing) = - self.overflowing_binary_op(bin_op, &left, &right)?; + let (result, overflowing) = self.overflowing_binary_op(bin_op, &left, &right)?; // Construct a new pointer with the provenance of `ptr` (the LHS). - let result_ptr = - Pointer::new(ptr.provenance, Size::from_bytes(result.to_scalar().to_target_usize(self)?)); - (ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, self), left.layout), overflowing) + let result_ptr = Pointer::new( + ptr.provenance, + Size::from_bytes(result.to_scalar().to_target_usize(self)?), + ); + ( + ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, self), left.layout), + overflowing, + ) } _ => span_bug!(self.cur_span(), "Invalid operator on pointers: {:?}", bin_op), diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 6144e07130f9..855ebbe70726 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -61,11 +61,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let right = this.int_to_int_or_float(&right, twice_wide)?; // Calculate left + right + 1 - let added = this.wrapping_binary_op( - mir::BinOp::Add, - &left, - &right, - )?; + let added = this.wrapping_binary_op(mir::BinOp::Add, &left, &right)?; let added = this.wrapping_binary_op( mir::BinOp::Add, &added, @@ -80,10 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { )?; // Narrow back to the original type - let res = this.int_to_int_or_float( - ÷d, - dest.layout, - )?; + let res = this.int_to_int_or_float(÷d, dest.layout)?; this.write_immediate(*res, &dest)?; } } @@ -110,11 +103,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let right = this.int_to_int_or_float(&right, twice_wide)?; // Multiply - let multiplied = this.wrapping_binary_op( - mir::BinOp::Mul, - &left, - &right, - )?; + let multiplied = this.wrapping_binary_op(mir::BinOp::Mul, &left, &right)?; // Keep the high half let high = this.wrapping_binary_op( mir::BinOp::Shr, @@ -123,10 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { )?; // Narrow back to the original type - let res = this.int_to_int_or_float( - &high, - dest.layout, - )?; + let res = this.int_to_int_or_float(&high, dest.layout)?; this.write_immediate(*res, &dest)?; } } From 896065f902602e99c6996cee9cee99ab7c00dcaa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Sep 2023 10:35:58 +0200 Subject: [PATCH 26/26] clippy --- src/tools/miri/src/shims/intrinsics/simd.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index 49ba7e5556e6..de0c58de44fd 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -458,7 +458,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { dest.layout.ty ) })? - .into() } (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if unsafe_cast => { let f = op.to_scalar().to_f64()?; @@ -469,7 +468,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { dest.layout.ty ) })? - .into() } // Ptr-to-ptr cast (ty::RawPtr(..), ty::RawPtr(..)) if ptr_cast =>