diff --git a/Cargo.lock b/Cargo.lock index 9ea22911d5157..2d3a50ba48148 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3539,6 +3539,7 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", + "rustc_data_structures", "rustc_errors", "rustc_feature", "rustc_hir", @@ -3703,7 +3704,6 @@ dependencies = [ "rustc_ast", "rustc_data_structures", "rustc_errors", - "rustc_fluent_macro", "rustc_hir", "rustc_index", "rustc_infer", @@ -4281,7 +4281,6 @@ dependencies = [ "rustc_ast", "rustc_data_structures", "rustc_errors", - "rustc_fluent_macro", "rustc_hir", "rustc_index", "rustc_infer", diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index b497c6beeb984..cde8b8f9fe2e9 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -827,7 +827,10 @@ impl<'hir> LoweringContext<'_, 'hir> { hir_id, def_id: self.local_def_id(v.id), data: self.lower_variant_data(hir_id, item_kind, &v.data), - disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)), + disr_expr: v + .disr_expr + .as_ref() + .map(|e| self.lower_anon_const_to_anon_const(e, e.value.span)), ident: self.lower_ident(v.ident), span: self.lower_span(v.span), } @@ -917,7 +920,10 @@ impl<'hir> LoweringContext<'_, 'hir> { None => Ident::new(sym::integer(index), self.lower_span(f.span)), }, vis_span: self.lower_span(f.vis.span), - default: f.default.as_ref().map(|v| self.lower_anon_const_to_anon_const(v)), + default: f + .default + .as_ref() + .map(|v| self.lower_anon_const_to_anon_const(v, v.value.span)), ty, safety: self.lower_safety(f.safety, hir::Safety::Safe), } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e4698ce8d6db4..6dded9936fbac 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2425,15 +2425,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| { - let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind { - let def_id = self.local_def_id(anon_const.id); - let def_kind = self.tcx.def_kind(def_id); - assert_eq!(DefKind::AnonConst, def_kind); - self.lower_anon_const_to_const_arg(anon_const) - } else { - self.lower_expr_to_const_arg_direct(arg) - }; - + let const_arg = self.lower_expr_to_const_arg_direct(arg); &*self.arena.alloc(const_arg) })); @@ -2445,16 +2437,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } ExprKind::Tup(exprs) => { let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| { - let expr = if let ExprKind::ConstBlock(anon_const) = &expr.kind { - let def_id = self.local_def_id(anon_const.id); - let def_kind = self.tcx.def_kind(def_id); - assert_eq!(DefKind::AnonConst, def_kind); - - self.lower_anon_const_to_const_arg(anon_const) - } else { - self.lower_expr_to_const_arg_direct(&expr) - }; - + let expr = self.lower_expr_to_const_arg_direct(&expr); &*self.arena.alloc(expr) })); @@ -2494,16 +2477,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // then go unused as the `Target::ExprField` is not actually // corresponding to `Node::ExprField`. self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField); - - let expr = if let ExprKind::ConstBlock(anon_const) = &f.expr.kind { - let def_id = self.local_def_id(anon_const.id); - let def_kind = self.tcx.def_kind(def_id); - assert_eq!(DefKind::AnonConst, def_kind); - - self.lower_anon_const_to_const_arg(anon_const) - } else { - self.lower_expr_to_const_arg_direct(&f.expr) - }; + let expr = self.lower_expr_to_const_arg_direct(&f.expr); &*self.arena.alloc(hir::ConstArgExprField { hir_id, @@ -2521,13 +2495,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } ExprKind::Array(elements) => { let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| { - let const_arg = if let ExprKind::ConstBlock(anon_const) = &element.kind { - let def_id = self.local_def_id(anon_const.id); - assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id)); - self.lower_anon_const_to_const_arg(anon_const) - } else { - self.lower_expr_to_const_arg_direct(element) - }; + let const_arg = self.lower_expr_to_const_arg_direct(element); &*self.arena.alloc(const_arg) })); let array_expr = self.arena.alloc(hir::ConstArgArrayExpr { @@ -2557,6 +2525,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | ExprKind::Call(..) | ExprKind::Tup(..) | ExprKind::Array(..) + | ExprKind::ConstBlock(..) ) { return self.lower_expr_to_const_arg_direct(expr); @@ -2586,6 +2555,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span, } } + ExprKind::ConstBlock(anon_const) => { + let def_id = self.local_def_id(anon_const.id); + assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id)); + self.lower_anon_const_to_const_arg(anon_const, span) + } _ => overly_complex_const(self), } } @@ -2596,11 +2570,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, anon: &AnonConst, ) -> &'hir hir::ConstArg<'hir> { - self.arena.alloc(self.lower_anon_const_to_const_arg(anon)) + self.arena.alloc(self.lower_anon_const_to_const_arg(anon, anon.value.span)) } #[instrument(level = "debug", skip(self))] - fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { + fn lower_anon_const_to_const_arg( + &mut self, + anon: &AnonConst, + span: Span, + ) -> hir::ConstArg<'hir> { let tcx = self.tcx; // We cannot change parsing depending on feature gates available, @@ -2611,7 +2589,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if tcx.features().min_generic_const_args() { return match anon.mgca_disambiguation { MgcaDisambiguation::AnonConst => { - let lowered_anon = self.lower_anon_const_to_anon_const(anon); + let lowered_anon = self.lower_anon_const_to_anon_const(anon, span); ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon), @@ -2657,7 +2635,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; } - let lowered_anon = self.lower_anon_const_to_anon_const(anon); + let lowered_anon = self.lower_anon_const_to_anon_const(anon, anon.value.span); ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon), @@ -2667,7 +2645,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// See [`hir::ConstArg`] for when to use this function vs /// [`Self::lower_anon_const_to_const_arg`]. - fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst { + fn lower_anon_const_to_anon_const( + &mut self, + c: &AnonConst, + span: Span, + ) -> &'hir hir::AnonConst { self.arena.alloc(self.with_new_scopes(c.value.span, |this| { let def_id = this.local_def_id(c.id); let hir_id = this.lower_node_id(c.id); @@ -2675,7 +2657,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { def_id, hir_id, body: this.lower_const_body(c.value.span, Some(&c.value)), - span: this.lower_span(c.value.span), + span: this.lower_span(span), } })) } diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index 411f3f5ccbd14..0a11a2da0dcf8 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -8,6 +8,7 @@ edition = "2024" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_hir = { path = "../rustc_hir" } diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index 4005ad2cba111..b6cb5b4504ee1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -1,22 +1,35 @@ use rustc_ast::token::Token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrStyle, NodeId, token}; +use rustc_data_structures::fx::FxHashMap; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::CfgEntry; use rustc_hir::{AttrPath, Target}; use rustc_parse::exp; use rustc_parse::parser::{Parser, Recovery}; use rustc_session::Session; -use rustc_span::{ErrorGuaranteed, Span, sym}; +use rustc_session::lint::BuiltinLintDiag; +use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES; +use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; use crate::parser::MetaItemOrLitParser; use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry}; +#[derive(Clone)] pub enum CfgSelectPredicate { Cfg(CfgEntry), Wildcard(Token), } +impl CfgSelectPredicate { + fn span(&self) -> Span { + match self { + CfgSelectPredicate::Cfg(cfg_entry) => cfg_entry.span(), + CfgSelectPredicate::Wildcard(token) => token.span, + } + } +} + #[derive(Default)] pub struct CfgSelectBranches { /// All the conditional branches. @@ -115,5 +128,102 @@ pub fn parse_cfg_select( } } + if let Some(features) = features + && features.enabled(sym::cfg_select) + { + let it = branches + .reachable + .iter() + .map(|(entry, _, _)| CfgSelectPredicate::Cfg(entry.clone())) + .chain(branches.wildcard.as_ref().map(|(t, _, _)| CfgSelectPredicate::Wildcard(*t))) + .chain( + branches.unreachable.iter().map(|(entry, _, _)| CfgSelectPredicate::clone(entry)), + ); + + lint_unreachable(p, it, lint_node_id); + } + Ok(branches) } + +fn lint_unreachable( + p: &mut Parser<'_>, + predicates: impl Iterator, + lint_node_id: NodeId, +) { + // Symbols that have a known value. + let mut known = FxHashMap::::default(); + let mut wildcard_span = None; + let mut it = predicates; + + let branch_is_unreachable = |predicate: CfgSelectPredicate, wildcard_span| { + let span = predicate.span(); + p.psess.buffer_lint( + UNREACHABLE_CFG_SELECT_PREDICATES, + span, + lint_node_id, + BuiltinLintDiag::UnreachableCfg { span, wildcard_span }, + ); + }; + + for predicate in &mut it { + let CfgSelectPredicate::Cfg(ref cfg_entry) = predicate else { + wildcard_span = Some(predicate.span()); + break; + }; + + match cfg_entry { + CfgEntry::Bool(true, _) => { + wildcard_span = Some(predicate.span()); + break; + } + CfgEntry::Bool(false, _) => continue, + CfgEntry::NameValue { name, value, .. } => match value { + None => { + // `name` will be false in all subsequent branches. + let current = known.insert(*name, false); + + match current { + None => continue, + Some(false) => { + branch_is_unreachable(predicate, None); + break; + } + Some(true) => { + // this branch will be taken, so all subsequent branches are unreachable. + break; + } + } + } + Some(_) => { /* for now we don't bother solving these */ } + }, + CfgEntry::Not(inner, _) => match &**inner { + CfgEntry::NameValue { name, value: None, .. } => { + // `name` will be true in all subsequent branches. + let current = known.insert(*name, true); + + match current { + None => continue, + Some(true) => { + branch_is_unreachable(predicate, None); + break; + } + Some(false) => { + // this branch will be taken, so all subsequent branches are unreachable. + break; + } + } + } + _ => { /* for now we don't bother solving these */ } + }, + CfgEntry::All(_, _) | CfgEntry::Any(_, _) => { + /* for now we don't bother solving these */ + } + CfgEntry::Version(..) => { /* don't bother solving these */ } + } + } + + for predicate in it { + branch_is_unreachable(predicate, wildcard_span) + } +} diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index f11190b281053..35098722a910e 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -1,14 +1,12 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::{Expr, ast}; use rustc_attr_parsing as attr; -use rustc_attr_parsing::{ - CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select, -}; +use rustc_attr_parsing::{CfgSelectBranches, EvalConfigResult, parse_cfg_select}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult}; use rustc_span::{Ident, Span, sym}; use smallvec::SmallVec; -use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable}; +use crate::errors::CfgSelectNoMatches; /// This intermediate structure is used to emit parse errors for the branches that are not chosen. /// The `MacResult` instance below parses all branches, emitting any errors it encounters, but only @@ -75,18 +73,6 @@ pub(super) fn expand_cfg_select<'cx>( ecx.current_expansion.lint_node_id, ) { Ok(mut branches) => { - if let Some((underscore, _, _)) = branches.wildcard { - // Warn for every unreachable predicate. We store the fully parsed branch for rustfmt. - for (predicate, _, _) in &branches.unreachable { - let span = match predicate { - CfgSelectPredicate::Wildcard(underscore) => underscore.span, - CfgSelectPredicate::Cfg(cfg) => cfg.span(), - }; - let err = CfgSelectUnreachable { span, wildcard_span: underscore.span }; - ecx.dcx().emit_warn(err); - } - } - if let Some((selected_tts, selected_span)) = branches.pop_first_match(|cfg| { matches!(attr::eval_config_entry(&ecx.sess, cfg), EvalConfigResult::True) }) { diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index d3f7e1c5d8e36..43bade3c43ac1 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1086,17 +1086,6 @@ pub(crate) struct CfgSelectNoMatches { pub span: Span, } -#[derive(Diagnostic)] -#[diag("unreachable predicate")] -pub(crate) struct CfgSelectUnreachable { - #[primary_span] - #[label("this predicate is never reached")] - pub span: Span, - - #[label("always matches")] - pub wildcard_span: Span, -} - #[derive(Diagnostic)] #[diag("`#[eii_declaration(...)]` is only valid on macros")] pub(crate) struct EiiExternTargetExpectedMacro { diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index 51dcee8d88227..aa013cf61f483 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -11,7 +11,6 @@ rustc_apfloat = "0.2.0" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } -rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl deleted file mode 100644 index 4aa0a0b2a96fc..0000000000000 --- a/compiler/rustc_const_eval/messages.ftl +++ /dev/null @@ -1,507 +0,0 @@ -const_eval_address_space_full = - there are no more free addresses in the address space - -const_eval_alignment_check_failed = - {$msg -> - [AccessedPtr] accessing memory - *[other] accessing memory based on pointer - } with alignment {$has}, but alignment {$required} is required - -const_eval_already_reported = - an error has already been reported elsewhere (this should not usually be printed) -const_eval_assume_false = - `assume` called with `false` - -const_eval_bad_pointer_op = {$operation -> - [MemoryAccess] memory access failed - [InboundsPointerArithmetic] in-bounds pointer arithmetic failed - *[Dereferenceable] pointer not dereferenceable -} -const_eval_bad_pointer_op_attempting = {const_eval_bad_pointer_op}: {$operation -> - [MemoryAccess] attempting to access {$inbounds_size -> - [1] 1 byte - *[x] {$inbounds_size} bytes - } - [InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size -> - [1] 1 byte - *[x] {$inbounds_size} bytes - } - *[Dereferenceable] pointer must {$inbounds_size -> - [0] point to some allocation - [1] be dereferenceable for 1 byte - *[x] be dereferenceable for {$inbounds_size} bytes - } - } - -const_eval_bounds_check_failed = - indexing out of bounds: the len is {$len} but the index is {$index} -const_eval_call_nonzero_intrinsic = - `{$name}` called on 0 - -const_eval_closure_call = - closures need an RFC before allowed to be called in {const_eval_const_context}s -const_eval_closure_fndef_not_const = - function defined here, but it is not `const` - -const_eval_consider_dereferencing = - consider dereferencing here - -const_eval_const_accesses_mut_global = - constant accesses mutable global memory - -const_eval_const_context = {$kind -> - [const] constant - [static] static - [const_fn] constant function - *[other] {""} -} - -const_eval_const_heap_ptr_in_final = encountered `const_allocate` pointer in final value that was not made global - .note = use `const_make_global` to turn allocated pointers into immutable globals before returning - -const_eval_const_make_global_ptr_already_made_global = attempting to call `const_make_global` twice on the same allocation {$alloc} - -const_eval_const_make_global_ptr_is_non_heap = pointer passed to `const_make_global` does not point to a heap allocation: {$ptr} - -const_eval_const_make_global_with_dangling_ptr = pointer passed to `const_make_global` is dangling: {$ptr} - -const_eval_const_make_global_with_offset = making {$ptr} global which does not point to the beginning of an object - -const_eval_copy_nonoverlapping_overlapping = - `copy_nonoverlapping` called on overlapping ranges - -const_eval_dangling_int_pointer = - {const_eval_bad_pointer_op_attempting}, but got {$pointer} which is a dangling pointer (it has no provenance) -const_eval_dangling_null_pointer = - {const_eval_bad_pointer_op_attempting}, but got null pointer - -const_eval_dangling_ptr_in_final = encountered dangling pointer in final value of {const_eval_intern_kind} -const_eval_dead_local = - accessing a dead local variable -const_eval_dealloc_immutable = - deallocating immutable allocation {$alloc} - -const_eval_dealloc_incorrect_layout = - incorrect layout on deallocation: {$alloc} has size {$size} and alignment {$align}, but gave size {$size_found} and alignment {$align_found} - -const_eval_dealloc_kind_mismatch = - deallocating {$alloc}, which is {$alloc_kind} memory, using {$kind} deallocation operation - -const_eval_deref_function_pointer = - accessing {$allocation} which contains a function -const_eval_deref_typeid_pointer = - accessing {$allocation} which contains a `TypeId` -const_eval_deref_vtable_pointer = - accessing {$allocation} which contains a vtable -const_eval_division_by_zero = - dividing by zero -const_eval_division_overflow = - overflow in signed division (dividing MIN by -1) - -const_eval_dyn_call_not_a_method = - `dyn` call trying to call something that is not a method - -const_eval_error = evaluation of `{$instance}` failed {$num_frames -> - [0] here - *[other] inside this call -} - -const_eval_exact_div_has_remainder = - exact_div: {$a} cannot be divided by {$b} without remainder - -const_eval_extern_static = - cannot access extern static `{$did}` -const_eval_extern_type_field = `extern type` field does not have a known offset - -const_eval_fn_ptr_call = - function pointers need an RFC before allowed to be called in {const_eval_const_context}s -const_eval_frame_note = {$times -> - [0] {const_eval_frame_note_inner} - *[other] [... {$times} additional calls {const_eval_frame_note_inner} ...] -} - -const_eval_frame_note_inner = inside {$where_ -> - [closure] closure - [instance] `{$instance}` - *[other] {""} -} - -const_eval_frame_note_last = the failure occurred here - -const_eval_incompatible_arg_types = - calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty} - -const_eval_incompatible_calling_conventions = - calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}" - -const_eval_incompatible_return_types = - calling a function with return type {$callee_ty} passing return place of type {$caller_ty} - -const_eval_interior_mutable_borrow_escaping = - interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed - .label = this borrow of an interior mutable value refers to such a temporary - .note = temporaries in constants and statics can have their lifetime extended until the end of the program - .note2 = to avoid accidentally creating global mutable state, such temporaries must be immutable - .help = if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` - -const_eval_intern_kind = {$kind -> - [static] static - [static_mut] mutable static - [const] constant - [promoted] promoted - *[other] {""} -} - -const_eval_interrupted = compilation was interrupted - -const_eval_invalid_align_details = - invalid align passed to `{$name}`: {$align} is {$err_kind -> - [not_power_of_two] not a power of 2 - [too_large] too large - *[other] {""} - } - -const_eval_invalid_bool = - interpreting an invalid 8-bit value as a bool: 0x{$value} -const_eval_invalid_char = - interpreting an invalid 32-bit value as a char: 0x{$value} -const_eval_invalid_dealloc = - deallocating {$alloc_id}, which is {$kind -> - [fn] a function - [vtable] a vtable - [static_mem] static memory - *[other] {""} - } - -const_eval_invalid_function_pointer = - using {$pointer} as function pointer but it does not point to a function -const_eval_invalid_meta = - invalid metadata in wide pointer: total size is bigger than largest supported object -const_eval_invalid_meta_slice = - invalid metadata in wide pointer: slice is bigger than largest supported object - -const_eval_invalid_niched_enum_variant_written = - trying to set discriminant of a {$ty} to the niched variant, but the value does not match - -const_eval_invalid_str = - this string is not valid UTF-8: {$err} -const_eval_invalid_tag = - enum value has invalid tag: {$tag} -const_eval_invalid_transmute = - transmuting from {$src_bytes}-byte type to {$dest_bytes}-byte type: `{$src}` -> `{$dest}` - -const_eval_invalid_uninit_bytes = - reading memory at {$alloc}{$access}, but memory is uninitialized at {$uninit}, and this operation requires initialized memory -const_eval_invalid_uninit_bytes_unknown = - using uninitialized data, but this operation requires initialized memory - -const_eval_invalid_vtable_pointer = - using {$pointer} as vtable pointer but it does not point to a vtable - -const_eval_invalid_vtable_trait = - using vtable for `{$vtable_dyn_type}` but `{$expected_dyn_type}` was expected - -const_eval_lazy_lock = - consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -const_eval_live_drop = - destructor of `{$dropped_ty}` cannot be evaluated at compile-time - .label = the destructor for this type cannot be evaluated in {const_eval_const_context}s - .dropped_at_label = value is dropped here - -const_eval_long_running = - constant evaluation is taking a long time - .note = this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. - If your compilation actually takes a long time, you can safely allow the lint. - .label = the const evaluator is currently interpreting this expression - .help = the constant being evaluated - -const_eval_memory_exhausted = - tried to allocate more memory than available to compiler - -const_eval_modified_global = - modifying a static's initial value from another static's initializer - -const_eval_mutable_borrow_escaping = - mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed - .label = this mutable borrow refers to such a temporary - .note = temporaries in constants and statics can have their lifetime extended until the end of the program - .note2 = to avoid accidentally creating global mutable state, such temporaries must be immutable - .help = if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` - -const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} - -const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead - -const_eval_non_const_await = - cannot convert `{$ty}` into a future in {const_eval_const_context}s - -const_eval_non_const_closure = - cannot call {$non_or_conditionally}-const closure in {const_eval_const_context}s - -const_eval_non_const_deref_coercion = - cannot perform {$non_or_conditionally}-const deref coercion on `{$ty}` in {const_eval_const_context}s - .note = attempting to deref into `{$target_ty}` - .target_note = deref defined here - -const_eval_non_const_fmt_macro_call = - cannot call {$non_or_conditionally}-const formatting macro in {const_eval_const_context}s - -const_eval_non_const_fn_call = - cannot call {$non_or_conditionally}-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s - -const_eval_non_const_for_loop_into_iter = - cannot use `for` loop on `{$ty}` in {const_eval_const_context}s - -const_eval_non_const_impl = - impl defined here, but it is not `const` - -const_eval_non_const_intrinsic = - cannot call non-const intrinsic `{$name}` in {const_eval_const_context}s - -const_eval_non_const_match_eq = cannot match on `{$ty}` in {const_eval_const_context}s - .note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es - -const_eval_non_const_operator = - cannot call {$non_or_conditionally}-const operator in {const_eval_const_context}s - -const_eval_non_const_question_branch = - `?` is not allowed on `{$ty}` in {const_eval_const_context}s -const_eval_non_const_question_from_residual = - `?` is not allowed on `{$ty}` in {const_eval_const_context}s - -const_eval_non_const_try_block_from_output = - `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s - -const_eval_not_enough_caller_args = - calling a function with fewer arguments than it requires - -const_eval_offset_from_different_allocations = - `{$name}` called on two different pointers that are not both derived from the same allocation -const_eval_offset_from_out_of_bounds = - `{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation -const_eval_offset_from_overflow = - `{$name}` called when first pointer is too far ahead of second -const_eval_offset_from_underflow = - `{$name}` called when first pointer is too far before second -const_eval_offset_from_unsigned_overflow = - `ptr_offset_from_unsigned` called when first pointer has smaller {$is_addr -> - [true] address - *[false] offset - } than second: {$a_offset} < {$b_offset} - -const_eval_overflow_arith = - arithmetic overflow in `{$intrinsic}` -const_eval_overflow_shift = - overflowing shift by {$shift_amount} in `{$intrinsic}` - -const_eval_panic = evaluation panicked: {$msg} - -const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str` - -const_eval_partial_pointer_in_final = encountered partial pointer in final value of {const_eval_intern_kind} - .note = while pointers can be broken apart into individual bytes during const-evaluation, only complete pointers (with all their bytes in the right order) are supported in the final value - -const_eval_partial_pointer_read = - unable to read parts of a pointer from memory at {$ptr} -const_eval_pointer_arithmetic_overflow = - overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` - -const_eval_pointer_out_of_bounds = - {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$ptr_offset_is_neg -> - [true] points to before the beginning of the allocation - *[false] {$inbounds_size_is_neg -> - [false] {$alloc_size_minus_ptr_offset -> - [0] is at or beyond the end of the allocation of size {$alloc_size -> - [1] 1 byte - *[x] {$alloc_size} bytes - } - [1] is only 1 byte from the end of the allocation - *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation - } - *[true] {$ptr_offset_abs -> - [0] is at the beginning of the allocation - *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation - } - } - } - -const_eval_pointer_use_after_free = - {const_eval_bad_pointer_op}: {$alloc_id} has been freed, so this pointer is dangling -const_eval_ptr_as_bytes_1 = - this code performed an operation that depends on the underlying bytes representing a pointer -const_eval_ptr_as_bytes_2 = - the absolute address of a pointer is not known at compile-time, so such operations are not supported - -const_eval_range = in the range {$lo}..={$hi} -const_eval_range_lower = greater or equal to {$lo} -const_eval_range_singular = equal to {$lo} -const_eval_range_upper = less or equal to {$hi} -const_eval_range_wrapping = less or equal to {$hi}, or greater or equal to {$lo} -const_eval_raw_bytes = the raw bytes of the constant (size: {$size}, align: {$align}) {"{"}{$bytes}{"}"} - -const_eval_raw_ptr_comparison = - pointers cannot be reliably compared during const eval - .note = see issue #53020 for more information - -const_eval_raw_ptr_to_int = - pointers cannot be cast to integers during const eval - .note = at compile-time, pointers do not have an integer value - .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior - -const_eval_read_pointer_as_int = - unable to turn pointer into integer -const_eval_realloc_or_alloc_with_offset = - {$kind -> - [dealloc] deallocating - [realloc] reallocating - *[other] {""} - } {$ptr} which does not point to the beginning of an object - -const_eval_recursive_static = encountered static that tried to access itself during initialization - -const_eval_remainder_by_zero = - calculating the remainder with a divisor of zero -const_eval_remainder_overflow = - overflow in signed remainder (dividing MIN by -1) -const_eval_scalar_size_mismatch = - scalar size mismatch: expected {$target_size} bytes but got {$data_size} bytes instead -const_eval_size_overflow = - overflow computing total size of `{$name}` - -const_eval_stack_frame_limit_reached = - reached the configured maximum number of stack frames - -const_eval_thread_local_access = - thread-local statics cannot be accessed at compile-time - -const_eval_thread_local_static = - cannot access thread local static `{$did}` -const_eval_too_generic = - encountered overly generic constant -const_eval_too_many_caller_args = - calling a function with more arguments than it expected - -const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {const_eval_const_context}s - -const_eval_unallowed_heap_allocations = - allocations are not allowed in {const_eval_const_context}s - .label = allocation not allowed in {const_eval_const_context}s - .teach_note = - The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created. - -const_eval_unallowed_inline_asm = - inline assembly is not allowed in {const_eval_const_context}s - -const_eval_unallowed_op_in_const_context = - {$msg} - -const_eval_uninhabited_enum_variant_read = - read discriminant of an uninhabited enum variant -const_eval_uninhabited_enum_variant_written = - writing discriminant of an uninhabited enum variant - -const_eval_unmarked_const_item_exposed = `{$def_path}` cannot be (indirectly) exposed to stable - .help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` -const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable - .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval) - -const_eval_unreachable = entering unreachable code -const_eval_unreachable_unwind = - unwinding past a stack frame that does not allow unwinding - -const_eval_unsized_local = unsized locals are not supported -const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn -const_eval_unstable_const_trait = `{$def_path}` is not yet stable as a const trait -const_eval_unstable_in_stable_exposed = - const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]` - .is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features - .unstable_sugg = if the {$is_function_call2 -> - [true] caller - *[false] function - } is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` - -const_eval_unstable_intrinsic = `{$name}` is not yet stable as a const intrinsic -const_eval_unstable_intrinsic_suggestion = add `#![feature({$feature})]` to the crate attributes to enable - -const_eval_unterminated_c_string = - reading a null-terminated string starting at {$pointer} with no null found before end of allocation - -const_eval_unwind_past_top = - unwinding past the topmost frame of the stack - -## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`. -## (We'd love to sort this differently to make that more clear but tidy won't let us...) -const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty} - -const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance) -const_eval_validation_dangling_box_out_of_bounds = {$front_matter}: encountered a dangling box (going beyond the bounds of its allocation) -const_eval_validation_dangling_box_use_after_free = {$front_matter}: encountered a dangling box (use-after-free) -const_eval_validation_dangling_ref_no_provenance = {$front_matter}: encountered a dangling reference ({$pointer} has no provenance) -const_eval_validation_dangling_ref_out_of_bounds = {$front_matter}: encountered a dangling reference (going beyond the bounds of its allocation) -const_eval_validation_dangling_ref_use_after_free = {$front_matter}: encountered a dangling reference (use-after-free) - -const_eval_validation_expected_bool = expected a boolean -const_eval_validation_expected_box = expected a box -const_eval_validation_expected_char = expected a unicode scalar value -const_eval_validation_expected_enum_tag = expected a valid enum tag -const_eval_validation_expected_float = expected a floating point number -const_eval_validation_expected_fn_ptr = expected a function pointer -const_eval_validation_expected_init_scalar = expected initialized scalar value -const_eval_validation_expected_int = expected an integer -const_eval_validation_expected_raw_ptr = expected a raw pointer -const_eval_validation_expected_ref = expected a reference -const_eval_validation_expected_str = expected a string - -const_eval_validation_failure = - it is undefined behavior to use this value - -const_eval_validation_failure_note = - the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - -const_eval_validation_front_matter_invalid_value = constructing invalid value -const_eval_validation_front_matter_invalid_value_with_path = constructing invalid value at {$path} - -const_eval_validation_invalid_bool = {$front_matter}: encountered {$value}, but expected a boolean -const_eval_validation_invalid_box_meta = {$front_matter}: encountered invalid box metadata: total size is bigger than largest supported object -const_eval_validation_invalid_box_slice_meta = {$front_matter}: encountered invalid box metadata: slice is bigger than largest supported object -const_eval_validation_invalid_char = {$front_matter}: encountered {$value}, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) - -const_eval_validation_invalid_enum_tag = {$front_matter}: encountered {$value}, but expected a valid enum tag -const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, but expected a function pointer -const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object -const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object -const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer -const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}` -const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory -const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!` -const_eval_validation_nonnull_ptr_out_of_range = {$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero -const_eval_validation_null_box = {$front_matter}: encountered a {$maybe -> - [true] maybe-null - *[false] null - } box -const_eval_validation_null_fn_ptr = {$front_matter}: encountered a {$maybe -> - [true] maybe-null - *[false] null - } function pointer -const_eval_validation_null_ref = {$front_matter}: encountered a {$maybe -> - [true] maybe-null - *[false] null - } reference -const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range} -const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers -const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected} -const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer with unknown absolute address, but expected something that is definitely {$in_range} -const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty} -const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes}) -const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes}) -const_eval_validation_uninhabited_enum_variant = {$front_matter}: encountered an uninhabited enum variant -const_eval_validation_uninhabited_val = {$front_matter}: encountered a value of uninhabited type `{$ty}` -const_eval_validation_uninit = {$front_matter}: encountered uninitialized memory, but {$expected} -const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in read-only memory - -const_eval_write_through_immutable_pointer = - writing through a pointer that was derived from a shared (immutable) reference - -const_eval_write_to_read_only = - writing to {$allocation} which is read-only diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index a9366bf29fbef..ecf52e4aa6054 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -2,7 +2,7 @@ use hir::{ConstContext, LangItem}; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, MultiSpan}; +use rustc_errors::{Applicability, Diag, MultiSpan, inline_fluent}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; @@ -23,7 +23,7 @@ use rustc_trait_selection::traits::SelectionContext; use tracing::debug; use super::ConstCx; -use crate::{errors, fluent_generated}; +use crate::errors; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Status { @@ -181,7 +181,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ); if let ConstContext::Static(_) = ccx.const_kind() { - err.note(fluent_generated::const_eval_lazy_lock); + err.note(inline_fluent!( + "consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`" + )); } err diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 69a8f163ca93c..e87d2cbb20de4 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -43,21 +43,41 @@ pub enum ConstEvalErrKind { impl MachineStopType for ConstEvalErrKind { fn diagnostic_message(&self) -> DiagMessage { use ConstEvalErrKind::*; + use rustc_errors::inline_fluent; - use crate::fluent_generated::*; match self { - ConstAccessesMutGlobal => const_eval_const_accesses_mut_global, - ModifiedGlobal => const_eval_modified_global, - Panic { .. } => const_eval_panic, - RecursiveStatic => const_eval_recursive_static, + ConstAccessesMutGlobal => "constant accesses mutable global memory".into(), + ModifiedGlobal => { + "modifying a static's initial value from another static's initializer".into() + } + Panic { .. } => inline_fluent!("evaluation panicked: {$msg}"), + RecursiveStatic => { + "encountered static that tried to access itself during initialization".into() + } AssertFailure(x) => x.diagnostic_message(), - WriteThroughImmutablePointer => const_eval_write_through_immutable_pointer, + WriteThroughImmutablePointer => { + inline_fluent!( + "writing through a pointer that was derived from a shared (immutable) reference" + ) + } ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => { - const_eval_const_make_global_ptr_already_made_global + inline_fluent!( + "attempting to call `const_make_global` twice on the same allocation {$alloc}" + ) + } + ConstMakeGlobalPtrIsNonHeap(_) => { + inline_fluent!( + "pointer passed to `const_make_global` does not point to a heap allocation: {$ptr}" + ) + } + ConstMakeGlobalWithDanglingPtr(_) => { + inline_fluent!("pointer passed to `const_make_global` is dangling: {$ptr}") + } + ConstMakeGlobalWithOffset(_) => { + inline_fluent!( + "making {$ptr} global which does not point to the beginning of an object" + ) } - ConstMakeGlobalPtrIsNonHeap(_) => const_eval_const_make_global_ptr_is_non_heap, - ConstMakeGlobalWithDanglingPtr(_) => const_eval_const_make_global_with_dangling_ptr, - ConstMakeGlobalWithOffset(_) => const_eval_const_make_global_with_offset, } } fn add_args(self: Box, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) { diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 5383ab3547af2..25da902987912 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -2,7 +2,7 @@ use std::sync::atomic::Ordering::Relaxed; use either::{Left, Right}; use rustc_abi::{self as abi, BackendRepr}; -use rustc_errors::E0080; +use rustc_errors::{E0080, inline_fluent}; use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo}; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; @@ -467,7 +467,15 @@ fn report_eval_error<'tcx>( let num_frames = frames.len(); // FIXME(oli-obk): figure out how to use structured diagnostics again. diag.code(E0080); - diag.span_label(span, crate::fluent_generated::const_eval_error); + diag.span_label( + span, + inline_fluent!( + "evaluation of `{$instance}` failed {$num_frames -> + [0] here + *[other] inside this call +}" + ), + ); for frame in frames { diag.subdiagnostic(frame); } @@ -506,8 +514,8 @@ fn report_validation_error<'tcx>( move |diag, span, frames| { // FIXME(oli-obk): figure out how to use structured diagnostics again. diag.code(E0080); - diag.span_label(span, crate::fluent_generated::const_eval_validation_failure); - diag.note(crate::fluent_generated::const_eval_validation_failure_note); + diag.span_label(span, "it is undefined behavior to use this value"); + diag.note("the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior."); for frame in frames { diag.subdiagnostic(frame); } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 719187b990122..da4f97db1c59c 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -5,6 +5,7 @@ use std::hash::Hash; use rustc_abi::{Align, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; +use rustc_errors::inline_fluent; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; @@ -19,7 +20,6 @@ use tracing::debug; use super::error::*; use crate::errors::{LongRunning, LongRunningWarn}; -use crate::fluent_generated as fluent; use crate::interpret::{ self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, RangeSet, Scalar, @@ -489,7 +489,13 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { let align = match Align::from_bytes(align) { Ok(a) => a, Err(err) => throw_ub_custom!( - fluent::const_eval_invalid_align_details, + inline_fluent!( + "invalid align passed to `{$name}`: {$align} is {$err_kind -> + [not_power_of_two] not a power of 2 + [too_large] too large + *[other] {\"\"} +}" + ), name = "const_allocate", err_kind = err.diag_ident(), align = err.align() @@ -513,7 +519,13 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { let align = match Align::from_bytes(align) { Ok(a) => a, Err(err) => throw_ub_custom!( - fluent::const_eval_invalid_align_details, + inline_fluent!( + "invalid align passed to `{$name}`: {$align} is {$err_kind -> + [not_power_of_two] not a power of 2 + [too_large] too large + *[other] {\"\"} +}" + ), name = "const_deallocate", err_kind = err.diag_ident(), align = err.align() diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 50f5448ec20ad..39f98b8449203 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -5,7 +5,8 @@ use either::Either; use rustc_abi::WrappingRange; use rustc_errors::codes::*; use rustc_errors::{ - Diag, DiagArgValue, DiagMessage, Diagnostic, EmissionGuarantee, Level, MultiSpan, Subdiagnostic, + Diag, DiagArgValue, DiagMessage, Diagnostic, EmissionGuarantee, Level, MultiSpan, + Subdiagnostic, inline_fluent, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -17,11 +18,18 @@ use rustc_middle::mir::interpret::{ use rustc_middle::ty::{self, Mutability, Ty}; use rustc_span::{Span, Symbol}; -use crate::fluent_generated as fluent; use crate::interpret::InternKind; #[derive(Diagnostic)] -#[diag(const_eval_dangling_ptr_in_final)] +#[diag( + r#"encountered dangling pointer in final value of {$kind -> + [static] static + [static_mut] mutable static + [const] constant + [promoted] promoted + *[other] {""} +}"# +)] pub(crate) struct DanglingPtrInFinal { #[primary_span] pub span: Span, @@ -29,14 +37,24 @@ pub(crate) struct DanglingPtrInFinal { } #[derive(Diagnostic)] -#[diag(const_eval_nested_static_in_thread_local)] +#[diag( + "#[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead" +)] pub(crate) struct NestedStaticInThreadLocal { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(const_eval_mutable_ptr_in_final)] +#[diag( + r#"encountered mutable pointer in final value of {$kind -> + [static] static + [static_mut] mutable static + [const] constant + [promoted] promoted + *[other] {""} +}"# +)] pub(crate) struct MutablePtrInFinal { #[primary_span] pub span: Span, @@ -44,16 +62,28 @@ pub(crate) struct MutablePtrInFinal { } #[derive(Diagnostic)] -#[diag(const_eval_const_heap_ptr_in_final)] -#[note] +#[diag("encountered `const_allocate` pointer in final value that was not made global")] +#[note( + "use `const_make_global` to turn allocated pointers into immutable globals before returning" +)] pub(crate) struct ConstHeapPtrInFinal { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(const_eval_partial_pointer_in_final)] -#[note] +#[diag( + r#"encountered partial pointer in final value of {$kind -> + [static] static + [static_mut] mutable static + [const] constant + [promoted] promoted + *[other] {""} +}"# +)] +#[note( + "while pointers can be broken apart into individual bytes during const-evaluation, only complete pointers (with all their bytes in the right order) are supported in the final value" +)] pub(crate) struct PartialPtrInFinal { #[primary_span] pub span: Span, @@ -61,17 +91,24 @@ pub(crate) struct PartialPtrInFinal { } #[derive(Diagnostic)] -#[diag(const_eval_unstable_in_stable_exposed)] +#[diag( + "const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]`" +)] pub(crate) struct UnstableInStableExposed { pub gate: String, #[primary_span] pub span: Span, - #[help(const_eval_is_function_call)] + #[help( + "mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features" + )] pub is_function_call: bool, /// Need to duplicate the field so that fluent also provides it as a variable... pub is_function_call2: bool, #[suggestion( - const_eval_unstable_sugg, + "if the {$is_function_call2 -> + [true] caller + *[false] function +} is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]`", code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n", applicability = "has-placeholders" )] @@ -79,38 +116,47 @@ pub(crate) struct UnstableInStableExposed { } #[derive(Diagnostic)] -#[diag(const_eval_thread_local_access, code = E0625)] +#[diag("thread-local statics cannot be accessed at compile-time", code = E0625)] pub(crate) struct ThreadLocalAccessErr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(const_eval_raw_ptr_to_int)] -#[note] -#[note(const_eval_note2)] +#[diag("pointers cannot be cast to integers during const eval")] +#[note("at compile-time, pointers do not have an integer value")] +#[note( + "avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior" +)] pub(crate) struct RawPtrToIntErr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(const_eval_raw_ptr_comparison)] -#[note] +#[diag("pointers cannot be reliably compared during const eval")] +#[note("see issue #53020 for more information")] pub(crate) struct RawPtrComparisonErr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(const_eval_panic_non_str)] +#[diag("argument to `panic!()` in a const context must have type `&str`")] pub(crate) struct PanicNonStrErr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_fn_pointer_call)] +#[diag( + r#"function pointer calls are not allowed in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"# +)] pub(crate) struct UnallowedFnPointerCall { #[primary_span] pub span: Span, @@ -118,7 +164,7 @@ pub(crate) struct UnallowedFnPointerCall { } #[derive(Diagnostic)] -#[diag(const_eval_unstable_const_fn)] +#[diag("`{$def_path}` is not yet stable as a const fn")] pub(crate) struct UnstableConstFn { #[primary_span] pub span: Span, @@ -126,7 +172,7 @@ pub(crate) struct UnstableConstFn { } #[derive(Diagnostic)] -#[diag(const_eval_unstable_const_trait)] +#[diag("`{$def_path}` is not yet stable as a const trait")] pub(crate) struct UnstableConstTrait { #[primary_span] pub span: Span, @@ -134,14 +180,14 @@ pub(crate) struct UnstableConstTrait { } #[derive(Diagnostic)] -#[diag(const_eval_unstable_intrinsic)] +#[diag("`{$name}` is not yet stable as a const intrinsic")] pub(crate) struct UnstableIntrinsic { #[primary_span] pub span: Span, pub name: Symbol, pub feature: Symbol, #[suggestion( - const_eval_unstable_intrinsic_suggestion, + "add `#![feature({$feature})]` to the crate attributes to enable", code = "#![feature({feature})]\n", applicability = "machine-applicable" )] @@ -149,8 +195,10 @@ pub(crate) struct UnstableIntrinsic { } #[derive(Diagnostic)] -#[diag(const_eval_unmarked_const_item_exposed)] -#[help] +#[diag("`{$def_path}` cannot be (indirectly) exposed to stable")] +#[help( + "either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`" +)] pub(crate) struct UnmarkedConstItemExposed { #[primary_span] pub span: Span, @@ -158,8 +206,10 @@ pub(crate) struct UnmarkedConstItemExposed { } #[derive(Diagnostic)] -#[diag(const_eval_unmarked_intrinsic_exposed)] -#[help] +#[diag("intrinsic `{$def_path}` cannot be (indirectly) exposed to stable")] +#[help( + "mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval)" +)] pub(crate) struct UnmarkedIntrinsicExposed { #[primary_span] pub span: Span, @@ -167,19 +217,31 @@ pub(crate) struct UnmarkedIntrinsicExposed { } #[derive(Diagnostic)] -#[diag(const_eval_mutable_borrow_escaping, code = E0764)] -#[note] -#[note(const_eval_note2)] -#[help] +#[diag("mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed", code = E0764)] +#[note( + "temporaries in constants and statics can have their lifetime extended until the end of the program" +)] +#[note("to avoid accidentally creating global mutable state, such temporaries must be immutable")] +#[help( + "if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`" +)] pub(crate) struct MutableBorrowEscaping { #[primary_span] - #[label] + #[label("this mutable borrow refers to such a temporary")] pub span: Span, pub kind: ConstContext, } #[derive(Diagnostic)] -#[diag(const_eval_non_const_fmt_macro_call, code = E0015)] +#[diag( + r#"cannot call {$non_or_conditionally}-const formatting macro in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, + code = E0015, +)] pub(crate) struct NonConstFmtMacroCall { #[primary_span] pub span: Span, @@ -188,7 +250,12 @@ pub(crate) struct NonConstFmtMacroCall { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_fn_call, code = E0015)] +#[diag(r#"cannot call {$non_or_conditionally}-const {$def_descr} `{$def_path_str}` in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, code = E0015)] pub(crate) struct NonConstFnCall { #[primary_span] pub span: Span, @@ -199,7 +266,14 @@ pub(crate) struct NonConstFnCall { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_intrinsic)] +#[diag( + r#"cannot call non-const intrinsic `{$name}` in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"# +)] pub(crate) struct NonConstIntrinsic { #[primary_span] pub span: Span, @@ -208,7 +282,7 @@ pub(crate) struct NonConstIntrinsic { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_op_in_const_context)] +#[diag("{$msg}")] pub(crate) struct UnallowedOpInConstContext { #[primary_span] pub span: Span, @@ -216,18 +290,37 @@ pub(crate) struct UnallowedOpInConstContext { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_heap_allocations, code = E0010)] +#[diag(r#"allocations are not allowed in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, code = E0010)] pub(crate) struct UnallowedHeapAllocations { #[primary_span] - #[label] + #[label( + r#"allocation not allowed in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"# + )] pub span: Span, pub kind: ConstContext, - #[note(const_eval_teach_note)] + #[note( + "The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created." + )] pub teach: bool, } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_inline_asm, code = E0015)] +#[diag(r#"inline assembly is not allowed in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, code = E0015)] pub(crate) struct UnallowedInlineAsm { #[primary_span] pub span: Span, @@ -235,39 +328,46 @@ pub(crate) struct UnallowedInlineAsm { } #[derive(Diagnostic)] -#[diag(const_eval_interior_mutable_borrow_escaping, code = E0492)] -#[note] -#[note(const_eval_note2)] -#[help] +#[diag("interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed", code = E0492)] +#[note( + "temporaries in constants and statics can have their lifetime extended until the end of the program" +)] +#[note("to avoid accidentally creating global mutable state, such temporaries must be immutable")] +#[help( + "if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`" +)] pub(crate) struct InteriorMutableBorrowEscaping { #[primary_span] - #[label] + #[label("this borrow of an interior mutable value refers to such a temporary")] pub span: Span, pub kind: ConstContext, } #[derive(LintDiagnostic)] -#[diag(const_eval_long_running)] -#[note] +#[diag("constant evaluation is taking a long time")] +#[note( + "this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. + If your compilation actually takes a long time, you can safely allow the lint." +)] pub struct LongRunning { - #[help] + #[help("the constant being evaluated")] pub item_span: Span, } #[derive(Diagnostic)] -#[diag(const_eval_long_running)] +#[diag("constant evaluation is taking a long time")] pub struct LongRunningWarn { #[primary_span] - #[label] + #[label("the const evaluator is currently interpreting this expression")] pub span: Span, - #[help] + #[help("the constant being evaluated")] pub item_span: Span, // Used for evading `-Z deduplicate-diagnostics`. pub force_duplicate: usize, } #[derive(Subdiagnostic)] -#[note(const_eval_non_const_impl)] +#[note("impl defined here, but it is not `const`")] pub(crate) struct NonConstImplNote { #[primary_span] pub span: Span, @@ -289,9 +389,21 @@ impl Subdiagnostic for FrameNote { diag.arg("instance", self.instance); let mut span: MultiSpan = self.span.into(); if self.has_label && !self.span.is_dummy() { - span.push_span_label(self.span, fluent::const_eval_frame_note_last); + span.push_span_label(self.span, inline_fluent!("the failure occurred here")); } - let msg = diag.eagerly_translate(fluent::const_eval_frame_note); + let msg = diag.eagerly_translate(inline_fluent!( + r#"{$times -> + [0] {const_eval_frame_note_inner} + *[other] [... {$times} additional calls {const_eval_frame_note_inner} ...] +} + +const_eval_frame_note_inner = inside {$where_ -> + [closure] closure + [instance] `{$instance}` + *[other] {""} +} +"# + )); diag.remove_arg("times"); diag.remove_arg("where_"); diag.remove_arg("instance"); @@ -300,7 +412,7 @@ impl Subdiagnostic for FrameNote { } #[derive(Subdiagnostic)] -#[note(const_eval_raw_bytes)] +#[note(r#"the raw bytes of the constant (size: {$size}, align: {$align}) {"{"}{$bytes}{"}"}"#)] pub struct RawBytesNote { pub size: u64, pub align: u64, @@ -310,8 +422,15 @@ pub struct RawBytesNote { // FIXME(fee1-dead) do not use stringly typed `ConstContext` #[derive(Diagnostic)] -#[diag(const_eval_non_const_match_eq, code = E0015)] -#[note] +#[diag( + r#"cannot match on `{$ty}` in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"# +)] +#[note("`{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es")] pub struct NonConstMatchEq<'tcx> { #[primary_span] pub span: Span, @@ -321,7 +440,12 @@ pub struct NonConstMatchEq<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_for_loop_into_iter, code = E0015)] +#[diag(r#"cannot use `for` loop on `{$ty}` in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, code = E0015)] pub struct NonConstForLoopIntoIter<'tcx> { #[primary_span] pub span: Span, @@ -331,7 +455,12 @@ pub struct NonConstForLoopIntoIter<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_question_branch, code = E0015)] +#[diag(r#"`?` is not allowed on `{$ty}` in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, code = E0015)] pub struct NonConstQuestionBranch<'tcx> { #[primary_span] pub span: Span, @@ -341,7 +470,12 @@ pub struct NonConstQuestionBranch<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_question_from_residual, code = E0015)] +#[diag(r#"`?` is not allowed on `{$ty}` in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, code = E0015)] pub struct NonConstQuestionFromResidual<'tcx> { #[primary_span] pub span: Span, @@ -351,7 +485,12 @@ pub struct NonConstQuestionFromResidual<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_try_block_from_output, code = E0015)] +#[diag(r#"`try` block cannot convert `{$ty}` to the result in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, code = E0015)] pub struct NonConstTryBlockFromOutput<'tcx> { #[primary_span] pub span: Span, @@ -361,7 +500,12 @@ pub struct NonConstTryBlockFromOutput<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_await, code = E0015)] +#[diag(r#"cannot convert `{$ty}` into a future in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, code = E0015)] pub struct NonConstAwait<'tcx> { #[primary_span] pub span: Span, @@ -371,7 +515,12 @@ pub struct NonConstAwait<'tcx> { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_closure, code = E0015)] +#[diag(r#"cannot call {$non_or_conditionally}-const closure in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, code = E0015)] pub struct NonConstClosure { #[primary_span] pub span: Span, @@ -383,19 +532,33 @@ pub struct NonConstClosure { #[derive(Subdiagnostic)] pub enum NonConstClosureNote { - #[note(const_eval_closure_fndef_not_const)] + #[note("function defined here, but it is not `const`")] FnDef { #[primary_span] span: Span, }, - #[note(const_eval_fn_ptr_call)] + #[note( + r#"function pointers need an RFC before allowed to be called in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"# + )] FnPtr, - #[note(const_eval_closure_call)] + #[note( + r#"closures need an RFC before allowed to be called in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"# + )] Closure, } #[derive(Subdiagnostic)] -#[multipart_suggestion(const_eval_consider_dereferencing, applicability = "machine-applicable")] +#[multipart_suggestion("consider dereferencing here", applicability = "machine-applicable")] pub struct ConsiderDereferencing { pub deref: String, #[suggestion_part(code = "{deref}")] @@ -405,7 +568,12 @@ pub struct ConsiderDereferencing { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_operator, code = E0015)] +#[diag(r#"cannot call {$non_or_conditionally}-const operator in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, code = E0015)] pub struct NonConstOperator { #[primary_span] pub span: Span, @@ -416,28 +584,40 @@ pub struct NonConstOperator { } #[derive(Diagnostic)] -#[diag(const_eval_non_const_deref_coercion, code = E0015)] -#[note] +#[diag(r#"cannot perform {$non_or_conditionally}-const deref coercion on `{$ty}` in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"#, code = E0015)] +#[note("attempting to deref into `{$target_ty}`")] pub struct NonConstDerefCoercion<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, pub target_ty: Ty<'tcx>, - #[note(const_eval_target_note)] + #[note("deref defined here")] pub deref_target: Option, pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_live_drop, code = E0493)] +#[diag("destructor of `{$dropped_ty}` cannot be evaluated at compile-time", code = E0493)] pub struct LiveDrop<'tcx> { #[primary_span] - #[label] + #[label( + r#"the destructor for this type cannot be evaluated in {$kind -> + [const] constant + [static] static + [const_fn] constant function + *[other] {""} +}s"# + )] pub span: Span, pub kind: ConstContext, pub dropped_ty: Ty<'tcx>, - #[label(const_eval_dropped_at_label)] + #[label("value is dropped here")] pub dropped_at: Span, } @@ -466,51 +646,128 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { fn diagnostic_message(&self) -> DiagMessage { use UndefinedBehaviorInfo::*; - use crate::fluent_generated::*; match self { Ub(msg) => msg.clone().into(), Custom(x) => (x.msg)(), ValidationError(e) => e.diagnostic_message(), - Unreachable => const_eval_unreachable, - BoundsCheckFailed { .. } => const_eval_bounds_check_failed, - DivisionByZero => const_eval_division_by_zero, - RemainderByZero => const_eval_remainder_by_zero, - DivisionOverflow => const_eval_division_overflow, - RemainderOverflow => const_eval_remainder_overflow, - PointerArithOverflow => const_eval_pointer_arithmetic_overflow, - ArithOverflow { .. } => const_eval_overflow_arith, - ShiftOverflow { .. } => const_eval_overflow_shift, - InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice, - InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta, - UnterminatedCString(_) => const_eval_unterminated_c_string, - PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free, - PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds, - DanglingIntPointer { addr: 0, .. } => const_eval_dangling_null_pointer, - DanglingIntPointer { .. } => const_eval_dangling_int_pointer, - AlignmentCheckFailed { .. } => const_eval_alignment_check_failed, - WriteToReadOnly(_) => const_eval_write_to_read_only, - DerefFunctionPointer(_) => const_eval_deref_function_pointer, - DerefVTablePointer(_) => const_eval_deref_vtable_pointer, - DerefTypeIdPointer(_) => const_eval_deref_typeid_pointer, - InvalidBool(_) => const_eval_invalid_bool, - InvalidChar(_) => const_eval_invalid_char, - InvalidTag(_) => const_eval_invalid_tag, - InvalidFunctionPointer(_) => const_eval_invalid_function_pointer, - InvalidVTablePointer(_) => const_eval_invalid_vtable_pointer, - InvalidVTableTrait { .. } => const_eval_invalid_vtable_trait, - InvalidStr(_) => const_eval_invalid_str, - InvalidUninitBytes(None) => const_eval_invalid_uninit_bytes_unknown, - InvalidUninitBytes(Some(_)) => const_eval_invalid_uninit_bytes, - DeadLocal => const_eval_dead_local, - ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch, - UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written, - UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read, + Unreachable => "entering unreachable code".into(), + BoundsCheckFailed { .. } => inline_fluent!("indexing out of bounds: the len is {$len} but the index is {$index}"), + DivisionByZero => "dividing by zero".into(), + RemainderByZero => "calculating the remainder with a divisor of zero".into(), + DivisionOverflow => "overflow in signed division (dividing MIN by -1)".into(), + RemainderOverflow => "overflow in signed remainder (dividing MIN by -1)".into(), + PointerArithOverflow => "overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`".into(), + ArithOverflow { .. } => inline_fluent!("arithmetic overflow in `{$intrinsic}`"), + ShiftOverflow { .. } => inline_fluent!("overflowing shift by {$shift_amount} in `{$intrinsic}`"), + InvalidMeta(InvalidMetaKind::SliceTooBig) => "invalid metadata in wide pointer: slice is bigger than largest supported object".into(), + InvalidMeta(InvalidMetaKind::TooBig) => "invalid metadata in wide pointer: total size is bigger than largest supported object".into(), + UnterminatedCString(_) => "reading a null-terminated string starting at {$pointer} with no null found before end of allocation".into(), + PointerUseAfterFree(_, _) => inline_fluent!("{$operation -> + [MemoryAccess] memory access failed + [InboundsPointerArithmetic] in-bounds pointer arithmetic failed + *[Dereferenceable] pointer not dereferenceable +}: {$alloc_id} has been freed, so this pointer is dangling"), + PointerOutOfBounds { .. } => inline_fluent!("{$operation -> + [MemoryAccess] memory access failed + [InboundsPointerArithmetic] in-bounds pointer arithmetic failed + *[Dereferenceable] pointer not dereferenceable +}: {$operation -> + [MemoryAccess] attempting to access {$inbounds_size -> + [1] 1 byte + *[x] {$inbounds_size} bytes + } + [InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size -> + [1] 1 byte + *[x] {$inbounds_size} bytes + } + *[Dereferenceable] pointer must {$inbounds_size -> + [0] point to some allocation + [1] be dereferenceable for 1 byte + *[x] be dereferenceable for {$inbounds_size} bytes + } +}, but got {$pointer} which {$ptr_offset_is_neg -> + [true] points to before the beginning of the allocation + *[false] {$inbounds_size_is_neg -> + [false] {$alloc_size_minus_ptr_offset -> + [0] is at or beyond the end of the allocation of size {$alloc_size -> + [1] 1 byte + *[x] {$alloc_size} bytes + } + [1] is only 1 byte from the end of the allocation + *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation + } + *[true] {$ptr_offset_abs -> + [0] is at the beginning of the allocation + *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation + } + } +} +"), + DanglingIntPointer { addr: 0, .. } => inline_fluent!("{$operation -> + [MemoryAccess] memory access failed + [InboundsPointerArithmetic] in-bounds pointer arithmetic failed + *[Dereferenceable] pointer not dereferenceable +}: {$operation -> + [MemoryAccess] attempting to access {$inbounds_size -> + [1] 1 byte + *[x] {$inbounds_size} bytes + } + [InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size -> + [1] 1 byte + *[x] {$inbounds_size} bytes + } + *[Dereferenceable] pointer must {$inbounds_size -> + [0] point to some allocation + [1] be dereferenceable for 1 byte + *[x] be dereferenceable for {$inbounds_size} bytes + } +}, but got null pointer"), + DanglingIntPointer { .. } => inline_fluent!("{$operation -> + [MemoryAccess] memory access failed + [InboundsPointerArithmetic] in-bounds pointer arithmetic failed + *[Dereferenceable] pointer not dereferenceable +}: {$operation -> + [MemoryAccess] attempting to access {$inbounds_size -> + [1] 1 byte + *[x] {$inbounds_size} bytes + } + [InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size -> + [1] 1 byte + *[x] {$inbounds_size} bytes + } + *[Dereferenceable] pointer must {$inbounds_size -> + [0] point to some allocation + [1] be dereferenceable for 1 byte + *[x] be dereferenceable for {$inbounds_size} bytes + } +}, but got {$pointer} which is a dangling pointer (it has no provenance)"), + AlignmentCheckFailed { .. } => inline_fluent!("{$msg -> + [AccessedPtr] accessing memory + *[other] accessing memory based on pointer +} with alignment {$has}, but alignment {$required} is required"), + WriteToReadOnly(_) => inline_fluent!("writing to {$allocation} which is read-only"), + DerefFunctionPointer(_) => inline_fluent!("accessing {$allocation} which contains a function"), + DerefVTablePointer(_) => inline_fluent!("accessing {$allocation} which contains a vtable"), + DerefTypeIdPointer(_) => inline_fluent!("accessing {$allocation} which contains a `TypeId`"), + InvalidBool(_) => inline_fluent!("interpreting an invalid 8-bit value as a bool: 0x{$value}"), + InvalidChar(_) => inline_fluent!("interpreting an invalid 32-bit value as a char: 0x{$value}"), + InvalidTag(_) => inline_fluent!("enum value has invalid tag: {$tag}"), + InvalidFunctionPointer(_) => inline_fluent!("using {$pointer} as function pointer but it does not point to a function"), + InvalidVTablePointer(_) => inline_fluent!("using {$pointer} as vtable pointer but it does not point to a vtable"), + InvalidVTableTrait { .. } => inline_fluent!("using vtable for `{$vtable_dyn_type}` but `{$expected_dyn_type}` was expected"), + InvalidStr(_) => inline_fluent!("this string is not valid UTF-8: {$err}"), + InvalidUninitBytes(None) => "using uninitialized data, but this operation requires initialized memory".into(), + InvalidUninitBytes(Some(_)) => inline_fluent!("reading memory at {$alloc}{$access}, but memory is uninitialized at {$uninit}, and this operation requires initialized memory"), + DeadLocal => "accessing a dead local variable".into(), + ScalarSizeMismatch(_) => inline_fluent!("scalar size mismatch: expected {$target_size} bytes but got {$data_size} bytes instead"), + UninhabitedEnumVariantWritten(_) => "writing discriminant of an uninhabited enum variant".into(), + UninhabitedEnumVariantRead(_) => "read discriminant of an uninhabited enum variant".into(), InvalidNichedEnumVariantWritten { .. } => { - const_eval_invalid_niched_enum_variant_written + inline_fluent!("trying to set discriminant of a {$ty} to the niched variant, but the value does not match") } - AbiMismatchArgument { .. } => const_eval_incompatible_arg_types, - AbiMismatchReturn { .. } => const_eval_incompatible_return_types, + AbiMismatchArgument { .. } => inline_fluent!("calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty}"), + AbiMismatchReturn { .. } => inline_fluent!("calling a function with return type {$callee_ty} passing return place of type {$caller_ty}"), } } @@ -653,92 +910,189 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { fn diagnostic_message(&self) -> DiagMessage { use rustc_middle::mir::interpret::ValidationErrorKind::*; - use crate::fluent_generated::*; match self.kind { PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => { - const_eval_validation_box_to_uninhabited + inline_fluent!( + "{$front_matter}: encountered a box pointing to uninhabited type {$ty}" + ) } PtrToUninhabited { ptr_kind: PointerKind::Ref(_), .. } => { - const_eval_validation_ref_to_uninhabited - } - - PointerAsInt { .. } => const_eval_validation_pointer_as_int, - PartialPointer => const_eval_validation_partial_pointer, - MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable, - NullFnPtr { .. } => const_eval_validation_null_fn_ptr, - NeverVal => const_eval_validation_never_val, - NonnullPtrMaybeNull { .. } => const_eval_validation_nonnull_ptr_out_of_range, - PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range, - OutOfRange { .. } => const_eval_validation_out_of_range, - UnsafeCellInImmutable => const_eval_validation_unsafe_cell, - UninhabitedVal { .. } => const_eval_validation_uninhabited_val, - InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag, - UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant, - Uninit { .. } => const_eval_validation_uninit, - InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr, - InvalidMetaWrongTrait { .. } => const_eval_validation_invalid_vtable_trait, + inline_fluent!( + "{$front_matter}: encountered a reference pointing to uninhabited type {$ty}" + ) + } + + PointerAsInt { .. } => { + inline_fluent!("{$front_matter}: encountered a pointer, but {$expected}") + } + PartialPointer => inline_fluent!( + "{$front_matter}: encountered a partial pointer or a mix of pointers" + ), + MutableRefToImmutable => { + inline_fluent!( + "{$front_matter}: encountered mutable reference or box pointing to read-only memory" + ) + } + NullFnPtr { .. } => { + inline_fluent!( + "{$front_matter}: encountered a {$maybe -> + [true] maybe-null + *[false] null +} function pointer" + ) + } + NeverVal => { + inline_fluent!("{$front_matter}: encountered a value of the never type `!`") + } + NonnullPtrMaybeNull { .. } => { + inline_fluent!( + "{$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero" + ) + } + PtrOutOfRange { .. } => { + inline_fluent!( + "{$front_matter}: encountered a pointer with unknown absolute address, but expected something that is definitely {$in_range}" + ) + } + OutOfRange { .. } => { + inline_fluent!( + "{$front_matter}: encountered {$value}, but expected something {$in_range}" + ) + } + UnsafeCellInImmutable => { + inline_fluent!("{$front_matter}: encountered `UnsafeCell` in read-only memory") + } + UninhabitedVal { .. } => { + inline_fluent!("{$front_matter}: encountered a value of uninhabited type `{$ty}`") + } + InvalidEnumTag { .. } => { + inline_fluent!( + "{$front_matter}: encountered {$value}, but expected a valid enum tag" + ) + } + UninhabitedEnumVariant => { + inline_fluent!("{$front_matter}: encountered an uninhabited enum variant") + } + Uninit { .. } => { + inline_fluent!("{$front_matter}: encountered uninitialized memory, but {$expected}") + } + InvalidVTablePtr { .. } => { + inline_fluent!( + "{$front_matter}: encountered {$value}, but expected a vtable pointer" + ) + } + InvalidMetaWrongTrait { .. } => { + inline_fluent!( + "{$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}`" + ) + } InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => { - const_eval_validation_invalid_box_slice_meta + inline_fluent!( + "{$front_matter}: encountered invalid box metadata: slice is bigger than largest supported object" + ) } InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref(_) } => { - const_eval_validation_invalid_ref_slice_meta + inline_fluent!( + "{$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object" + ) } InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => { - const_eval_validation_invalid_box_meta + inline_fluent!( + "{$front_matter}: encountered invalid box metadata: total size is bigger than largest supported object" + ) } InvalidMetaTooLarge { ptr_kind: PointerKind::Ref(_) } => { - const_eval_validation_invalid_ref_meta + inline_fluent!( + "{$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object" + ) } UnalignedPtr { ptr_kind: PointerKind::Ref(_), .. } => { - const_eval_validation_unaligned_ref + inline_fluent!( + "{$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes})" + ) + } + UnalignedPtr { ptr_kind: PointerKind::Box, .. } => { + inline_fluent!( + "{$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes})" + ) } - UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box, - NullPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_null_box, - NullPtr { ptr_kind: PointerKind::Ref(_), .. } => const_eval_validation_null_ref, + NullPtr { ptr_kind: PointerKind::Box, .. } => { + inline_fluent!( + "{$front_matter}: encountered a {$maybe -> + [true] maybe-null + *[false] null +} box" + ) + } + NullPtr { ptr_kind: PointerKind::Ref(_), .. } => { + inline_fluent!( + "{$front_matter}: encountered a {$maybe -> + [true] maybe-null + *[false] null +} reference" + ) + } DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => { - const_eval_validation_dangling_box_no_provenance + inline_fluent!( + "{$front_matter}: encountered a dangling box ({$pointer} has no provenance)" + ) } DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref(_), .. } => { - const_eval_validation_dangling_ref_no_provenance + inline_fluent!( + "{$front_matter}: encountered a dangling reference ({$pointer} has no provenance)" + ) } DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => { - const_eval_validation_dangling_box_out_of_bounds + inline_fluent!( + "{$front_matter}: encountered a dangling box (going beyond the bounds of its allocation)" + ) } DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref(_) } => { - const_eval_validation_dangling_ref_out_of_bounds + inline_fluent!( + "{$front_matter}: encountered a dangling reference (going beyond the bounds of its allocation)" + ) } DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => { - const_eval_validation_dangling_box_use_after_free + inline_fluent!("{$front_matter}: encountered a dangling box (use-after-free)") } DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(_) } => { - const_eval_validation_dangling_ref_use_after_free + inline_fluent!("{$front_matter}: encountered a dangling reference (use-after-free)") + } + InvalidBool { .. } => { + inline_fluent!("{$front_matter}: encountered {$value}, but expected a boolean") + } + InvalidChar { .. } => { + inline_fluent!( + "{$front_matter}: encountered {$value}, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)" + ) + } + InvalidFnPtr { .. } => { + inline_fluent!( + "{$front_matter}: encountered {$value}, but expected a function pointer" + ) } - InvalidBool { .. } => const_eval_validation_invalid_bool, - InvalidChar { .. } => const_eval_validation_invalid_char, - InvalidFnPtr { .. } => const_eval_validation_invalid_fn_ptr, } } fn add_args(self, err: &mut Diag<'_, G>) { + use rustc_errors::inline_fluent; use rustc_middle::mir::interpret::ValidationErrorKind::*; - use crate::fluent_generated as fluent; - if let PointerAsInt { .. } | PartialPointer = self.kind { - err.help(fluent::const_eval_ptr_as_bytes_1); - err.help(fluent::const_eval_ptr_as_bytes_2); + err.help(inline_fluent!("this code performed an operation that depends on the underlying bytes representing a pointer")); + err.help(inline_fluent!("the absolute address of a pointer is not known at compile-time, so such operations are not supported")); } let message = if let Some(path) = self.path { err.dcx.eagerly_translate_to_string( - fluent::const_eval_validation_front_matter_invalid_value_with_path, + inline_fluent!("constructing invalid value at {$path}"), [("path".into(), DiagArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)), ) } else { err.dcx.eagerly_translate_to_string( - fluent::const_eval_validation_front_matter_invalid_value, + inline_fluent!("constructing invalid value"), [].into_iter(), ) }; @@ -753,17 +1107,17 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { let WrappingRange { start: lo, end: hi } = r; assert!(hi <= max_hi); let msg = if lo > hi { - fluent::const_eval_range_wrapping + inline_fluent!("less or equal to {$hi}, or greater or equal to {$lo}") } else if lo == hi { - fluent::const_eval_range_singular + inline_fluent!("equal to {$lo}") } else if lo == 0 { assert!(hi < max_hi, "should not be printing if the range covers everything"); - fluent::const_eval_range_upper + inline_fluent!("less or equal to {$hi}") } else if hi == max_hi { assert!(lo > 0, "should not be printing if the range covers everything"); - fluent::const_eval_range_lower + inline_fluent!("greater or equal to {$lo}") } else { - fluent::const_eval_range + inline_fluent!("in the range {$lo}..={$hi}") }; let args = [ @@ -781,17 +1135,17 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { } PointerAsInt { expected } | Uninit { expected } => { let msg = match expected { - ExpectedKind::Reference => fluent::const_eval_validation_expected_ref, - ExpectedKind::Box => fluent::const_eval_validation_expected_box, - ExpectedKind::RawPtr => fluent::const_eval_validation_expected_raw_ptr, - ExpectedKind::InitScalar => fluent::const_eval_validation_expected_init_scalar, - ExpectedKind::Bool => fluent::const_eval_validation_expected_bool, - ExpectedKind::Char => fluent::const_eval_validation_expected_char, - ExpectedKind::Float => fluent::const_eval_validation_expected_float, - ExpectedKind::Int => fluent::const_eval_validation_expected_int, - ExpectedKind::FnPtr => fluent::const_eval_validation_expected_fn_ptr, - ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag, - ExpectedKind::Str => fluent::const_eval_validation_expected_str, + ExpectedKind::Reference => inline_fluent!("expected a reference"), + ExpectedKind::Box => inline_fluent!("expected a box"), + ExpectedKind::RawPtr => inline_fluent!("expected a raw pointer"), + ExpectedKind::InitScalar => inline_fluent!("expected initialized scalar value"), + ExpectedKind::Bool => inline_fluent!("expected a boolean"), + ExpectedKind::Char => inline_fluent!("expected a unicode scalar value"), + ExpectedKind::Float => inline_fluent!("expected a floating point number"), + ExpectedKind::Int => inline_fluent!("expected an integer"), + ExpectedKind::FnPtr => inline_fluent!("expected a function pointer"), + ExpectedKind::EnumTag => inline_fluent!("expected a valid enum tag"), + ExpectedKind::Str => inline_fluent!("expected a string"), }; let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter()); err.arg("expected", msg); @@ -838,25 +1192,32 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { impl ReportErrorExt for UnsupportedOpInfo { fn diagnostic_message(&self) -> DiagMessage { - use crate::fluent_generated::*; match self { UnsupportedOpInfo::Unsupported(s) => s.clone().into(), - UnsupportedOpInfo::ExternTypeField => const_eval_extern_type_field, - UnsupportedOpInfo::UnsizedLocal => const_eval_unsized_local, - UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_read, - UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int, - UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static, - UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static, + UnsupportedOpInfo::ExternTypeField => { + "`extern type` field does not have a known offset".into() + } + UnsupportedOpInfo::UnsizedLocal => "unsized locals are not supported".into(), + UnsupportedOpInfo::ReadPartialPointer(_) => { + inline_fluent!("unable to read parts of a pointer from memory at {$ptr}") + } + UnsupportedOpInfo::ReadPointerAsInt(_) => "unable to turn pointer into integer".into(), + UnsupportedOpInfo::ThreadLocalStatic(_) => { + inline_fluent!("cannot access thread local static `{$did}`") + } + UnsupportedOpInfo::ExternStatic(_) => { + inline_fluent!("cannot access extern static `{$did}`") + } } + .into() } fn add_args(self, diag: &mut Diag<'_, G>) { use UnsupportedOpInfo::*; - use crate::fluent_generated::*; if let ReadPointerAsInt(_) | ReadPartialPointer(_) = self { - diag.help(const_eval_ptr_as_bytes_1); - diag.help(const_eval_ptr_as_bytes_2); + diag.help("this code performed an operation that depends on the underlying bytes representing a pointer"); + diag.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported"); } match self { // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to @@ -901,10 +1262,12 @@ impl<'tcx> ReportErrorExt for InterpErrorKind<'tcx> { impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { fn diagnostic_message(&self) -> DiagMessage { - use crate::fluent_generated::*; match self { - InvalidProgramInfo::TooGeneric => const_eval_too_generic, - InvalidProgramInfo::AlreadyReported(_) => const_eval_already_reported, + InvalidProgramInfo::TooGeneric => "encountered overly generic constant".into(), + InvalidProgramInfo::AlreadyReported(_) => { + "an error has already been reported elsewhere (this should not usually be printed)" + .into() + } InvalidProgramInfo::Layout(e) => e.diagnostic_message(), } } @@ -926,13 +1289,19 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { impl ReportErrorExt for ResourceExhaustionInfo { fn diagnostic_message(&self) -> DiagMessage { - use crate::fluent_generated::*; match self { - ResourceExhaustionInfo::StackFrameLimitReached => const_eval_stack_frame_limit_reached, - ResourceExhaustionInfo::MemoryExhausted => const_eval_memory_exhausted, - ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full, - ResourceExhaustionInfo::Interrupted => const_eval_interrupted, + ResourceExhaustionInfo::StackFrameLimitReached => { + "reached the configured maximum number of stack frames" + } + ResourceExhaustionInfo::MemoryExhausted => { + "tried to allocate more memory than available to compiler" + } + ResourceExhaustionInfo::AddressSpaceFull => { + "there are no more free addresses in the address space" + } + ResourceExhaustionInfo::Interrupted => "compilation was interrupted", } + .into() } fn add_args(self, _: &mut Diag<'_, G>) {} } diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 9c8ca44c5e8f0..c7ddcaa731579 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -1,10 +1,12 @@ //! Manages calling a concrete function (with known MIR body) with argument passing, //! and returning the return value to the caller. + use std::borrow::Cow; use either::{Left, Right}; use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx}; use rustc_data_structures::assert_matches; +use rustc_errors::inline_fluent; use rustc_hir::def_id::DefId; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef}; @@ -19,8 +21,8 @@ use super::{ Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, StackPopInfo, interp_ok, throw_ub, throw_ub_custom, throw_unsup_format, }; +use crate::enter_trace_span; use crate::interpret::EnteredTraceSpan; -use crate::{enter_trace_span, fluent_generated as fluent}; /// An argument passed to a function. #[derive(Clone, Debug)] @@ -292,7 +294,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // Find next caller arg. let Some((caller_arg, caller_abi)) = caller_args.next() else { - throw_ub_custom!(fluent::const_eval_not_enough_caller_args); + throw_ub_custom!(inline_fluent!( + "calling a function with fewer arguments than it requires" + )); }; assert_eq!(caller_arg.layout().layout, caller_abi.layout.layout); // Sadly we cannot assert that `caller_arg.layout().ty` and `caller_abi.layout.ty` are @@ -359,7 +363,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if caller_fn_abi.conv != callee_fn_abi.conv { throw_ub_custom!( - fluent::const_eval_incompatible_calling_conventions, + rustc_errors::inline_fluent!( + "calling a function with calling convention \"{$callee_conv}\" using calling convention \"{$caller_conv}\"" + ), callee_conv = format!("{}", callee_fn_abi.conv), caller_conv = format!("{}", caller_fn_abi.conv), ) @@ -490,7 +496,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { "mismatch between callee ABI and callee body arguments" ); if caller_args.next().is_some() { - throw_ub_custom!(fluent::const_eval_too_many_caller_args); + throw_ub_custom!(inline_fluent!( + "calling a function with more arguments than it expected" + )); } // Don't forget to check the return type! if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? { @@ -690,7 +698,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let vtable_entries = self.vtable_entries(receiver_trait.principal(), dyn_ty); let Some(ty::VtblEntry::Method(fn_inst)) = vtable_entries.get(idx).copied() else { // FIXME(fee1-dead) these could be variants of the UB info enum instead of this - throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method); + throw_ub_custom!(inline_fluent!( + "`dyn` call trying to call something that is not a method" + )); }; trace!("Virtual call dispatches to {fn_inst:#?}"); // We can also do the lookup based on `def_id` and `dyn_ty`, and check that that @@ -887,7 +897,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } ); if unwinding && self.frame_idx() == 0 { - throw_ub_custom!(fluent::const_eval_unwind_past_top); + throw_ub_custom!(inline_fluent!("unwinding past the topmost frame of the stack")); } // Get out the return value. Must happen *before* the frame is popped as we have to get the diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 43de2e7f078a8..44ca20ab4c035 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -2,6 +2,7 @@ use rustc_abi::{FieldIdx, Integer}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::{Float, FloatConvert}; use rustc_data_structures::assert_matches; +use rustc_errors::inline_fluent; use rustc_middle::mir::CastKind; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::ty::adjustment::PointerCoercion; @@ -15,8 +16,8 @@ use super::{ FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, interp_ok, throw_ub, throw_ub_custom, }; +use crate::enter_trace_span; use crate::interpret::Writeable; -use crate::{enter_trace_span, fluent_generated as fluent}; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn cast( @@ -138,7 +139,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely... if src.layout.size != dest.layout.size { throw_ub_custom!( - fluent::const_eval_invalid_transmute, + inline_fluent!( + "transmuting from {$src_bytes}-byte type to {$dest_bytes}-byte type: `{$src}` -> `{$dest}`" + ), src_bytes = src.layout.size.bytes(), dest_bytes = dest.layout.size.bytes(), src = src.layout.ty, diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index b72a50a0bfce6..8c9a79abe48d2 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1,7 +1,7 @@ use either::{Left, Right}; use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout}; use rustc_data_structures::debug_assert_matches; -use rustc_errors::DiagCtxtHandle; +use rustc_errors::{DiagCtxtHandle, inline_fluent}; use rustc_hir::def_id::DefId; use rustc_hir::limit::Limit; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; @@ -23,7 +23,7 @@ use super::{ MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance, err_inval, interp_ok, throw_inval, throw_ub, throw_ub_custom, }; -use crate::{ReportErrorExt, enter_trace_span, fluent_generated as fluent, util}; +use crate::{ReportErrorExt, enter_trace_span, util}; pub struct InterpCx<'tcx, M: Machine<'tcx>> { /// Stores the `Machine` instance. @@ -555,7 +555,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }), mir::UnwindAction::Continue => Right(self.frame_mut().body.span), mir::UnwindAction::Unreachable => { - throw_ub_custom!(fluent::const_eval_unreachable_unwind); + throw_ub_custom!(inline_fluent!( + "unwinding past a stack frame that does not allow unwinding" + )); } mir::UnwindAction::Terminate(reason) => { self.frame_mut().loc = Right(self.frame_mut().body.span); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index e526f6120689a..2ea5e4a25c116 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -7,6 +7,7 @@ mod simd; use rustc_abi::{FIRST_VARIANT, FieldIdx, HasDataLayout, Size, VariantIdx}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_data_structures::assert_matches; +use rustc_errors::inline_fluent; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint}; @@ -25,7 +26,6 @@ use super::{ PointerArithmetic, Provenance, Scalar, err_ub_custom, err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format, }; -use crate::fluent_generated as fluent; use crate::interpret::Writeable; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -438,7 +438,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => { // Not into the same allocation -- this is UB. throw_ub_custom!( - fluent::const_eval_offset_from_different_allocations, + inline_fluent!( + "`{$name}` called on two different pointers that are not both derived from the same allocation" + ), name = intrinsic_name, ); } @@ -459,7 +461,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // a < b if intrinsic_name == sym::ptr_offset_from_unsigned { throw_ub_custom!( - fluent::const_eval_offset_from_unsigned_overflow, + inline_fluent!("`ptr_offset_from_unsigned` called when first pointer has smaller {$is_addr -> + [true] address + *[false] offset +} than second: {$a_offset} < {$b_offset}"), a_offset = a_offset, b_offset = b_offset, is_addr = is_addr, @@ -471,7 +476,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let dist = val.to_target_isize(self)?; if dist >= 0 || i128::from(dist) == self.pointer_size().signed_int_min() { throw_ub_custom!( - fluent::const_eval_offset_from_underflow, + inline_fluent!( + "`{$name}` called when first pointer is too far before second" + ), name = intrinsic_name, ); } @@ -483,7 +490,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // because they were more than isize::MAX apart. if dist < 0 { throw_ub_custom!( - fluent::const_eval_offset_from_overflow, + inline_fluent!( + "`{$name}` called when first pointer is too far ahead of second" + ), name = intrinsic_name, ); } @@ -502,12 +511,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { && a_alloc_id == b_alloc_id { err_ub_custom!( - fluent::const_eval_offset_from_out_of_bounds, + inline_fluent!("`{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation"), name = intrinsic_name, ) } else { err_ub_custom!( - fluent::const_eval_offset_from_different_allocations, + inline_fluent!("`{$name}` called on two different pointers that are not both derived from the same allocation"), name = intrinsic_name, ) } @@ -522,7 +531,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .map_err_kind(|_| { // Make the error more specific. err_ub_custom!( - fluent::const_eval_offset_from_different_allocations, + inline_fluent!("`{$name}` called on two different pointers that are not both derived from the same allocation"), name = intrinsic_name, ) })?; @@ -752,7 +761,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let op = self.eval_operand(op, None)?; let cond = self.read_scalar(&op)?.to_bool()?; if !cond { - throw_ub_custom!(fluent::const_eval_assume_false); + throw_ub_custom!(inline_fluent!("`assume` called with `false`")); } interp_ok(()) } @@ -782,7 +791,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let bits_out = match name { sym::ctpop => u128::from(bits.count_ones()), sym::ctlz_nonzero | sym::cttz_nonzero if bits == 0 => { - throw_ub_custom!(fluent::const_eval_call_nonzero_intrinsic, name = name,); + throw_ub_custom!(inline_fluent!("`{$name}` called on 0"), name = name,); } sym::ctlz | sym::ctlz_nonzero => u128::from(bits.leading_zeros()) - extra, sym::cttz | sym::cttz_nonzero => u128::from((bits << extra).trailing_zeros()) - extra, @@ -815,7 +824,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // sign does not matter for 0 test, so `to_bits` is fine if rem.to_scalar().to_bits(a.layout.size)? != 0 { throw_ub_custom!( - fluent::const_eval_exact_div_has_remainder, + inline_fluent!("exact_div: {$a} cannot be divided by {$b} without remainder"), a = format!("{a}"), b = format!("{b}") ) @@ -900,7 +909,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let size = self.compute_size_in_bytes(size, count).ok_or_else(|| { err_ub_custom!( - fluent::const_eval_size_overflow, + inline_fluent!("overflow computing total size of `{$name}`"), name = if nonoverlapping { "copy_nonoverlapping" } else { "copy" } ) })?; @@ -963,9 +972,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), // but no actual allocation can be big enough for the difference to be noticeable. - let len = self - .compute_size_in_bytes(layout.size, count) - .ok_or_else(|| err_ub_custom!(fluent::const_eval_size_overflow, name = name))?; + let len = self.compute_size_in_bytes(layout.size, count).ok_or_else(|| { + err_ub_custom!( + inline_fluent!("overflow computing total size of `{$name}`"), + name = name + ) + })?; let bytes = std::iter::repeat_n(byte, len.bytes_usize()); self.write_bytes_ptr(dst, bytes) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index a6c8b28cce9f4..28dae2ef3b8b7 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -15,6 +15,7 @@ use rustc_abi::{Align, HasDataLayout, Size}; use rustc_ast::Mutability; use rustc_data_structures::assert_matches; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_errors::inline_fluent; use rustc_middle::mir::display_allocation; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, throw_ub_format}; @@ -27,7 +28,6 @@ use super::{ err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; use crate::const_eval::ConstEvalErrKind; -use crate::fluent_generated as fluent; #[derive(Debug, PartialEq, Copy, Clone)] pub enum MemoryKind { @@ -291,7 +291,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr, 0)?; if offset.bytes() != 0 { throw_ub_custom!( - fluent::const_eval_realloc_or_alloc_with_offset, + inline_fluent!( + "{$kind -> + [dealloc] deallocating + [realloc] reallocating + *[other] {\"\"} +} {$ptr} which does not point to the beginning of an object" + ), ptr = format!("{ptr:?}"), kind = "realloc" ); @@ -371,7 +377,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if offset.bytes() != 0 { throw_ub_custom!( - fluent::const_eval_realloc_or_alloc_with_offset, + inline_fluent!( + "{$kind -> + [dealloc] deallocating + [realloc] reallocating + *[other] {\"\"} +} {$ptr} which does not point to the beginning of an object" + ), ptr = format!("{ptr:?}"), kind = "dealloc", ); @@ -382,28 +394,56 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return Err(match self.tcx.try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Function { .. }) => { err_ub_custom!( - fluent::const_eval_invalid_dealloc, + inline_fluent!( + "deallocating {$alloc_id}, which is {$kind -> + [fn] a function + [vtable] a vtable + [static_mem] static memory + *[other] {\"\"} +}" + ), alloc_id = alloc_id, kind = "fn", ) } Some(GlobalAlloc::VTable(..)) => { err_ub_custom!( - fluent::const_eval_invalid_dealloc, + inline_fluent!( + "deallocating {$alloc_id}, which is {$kind -> + [fn] a function + [vtable] a vtable + [static_mem] static memory + *[other] {\"\"} +}" + ), alloc_id = alloc_id, kind = "vtable", ) } Some(GlobalAlloc::TypeId { .. }) => { err_ub_custom!( - fluent::const_eval_invalid_dealloc, + inline_fluent!( + "deallocating {$alloc_id}, which is {$kind -> + [fn] a function + [vtable] a vtable + [static_mem] static memory + *[other] {\"\"} +}" + ), alloc_id = alloc_id, kind = "typeid", ) } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { err_ub_custom!( - fluent::const_eval_invalid_dealloc, + inline_fluent!( + "deallocating {$alloc_id}, which is {$kind -> + [fn] a function + [vtable] a vtable + [static_mem] static memory + *[other] {\"\"} +}" + ), alloc_id = alloc_id, kind = "static_mem" ) @@ -414,11 +454,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; if alloc.mutability.is_not() { - throw_ub_custom!(fluent::const_eval_dealloc_immutable, alloc = alloc_id,); + throw_ub_custom!( + inline_fluent!("deallocating immutable allocation {$alloc}"), + alloc = alloc_id, + ); } if alloc_kind != kind { throw_ub_custom!( - fluent::const_eval_dealloc_kind_mismatch, + inline_fluent!( + "deallocating {$alloc}, which is {$alloc_kind} memory, using {$kind} deallocation operation" + ), alloc = alloc_id, alloc_kind = format!("{alloc_kind}"), kind = format!("{kind}"), @@ -427,7 +472,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some((size, align)) = old_size_and_align { if size != alloc.size() || align != alloc.align { throw_ub_custom!( - fluent::const_eval_dealloc_incorrect_layout, + inline_fluent!( + "incorrect layout on deallocation: {$alloc} has size {$size} and alignment {$align}, but gave size {$size_found} and alignment {$align_found}" + ), alloc = alloc_id, size = alloc.size().bytes(), align = alloc.align.bytes(), @@ -1546,7 +1593,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if (src_offset <= dest_offset && src_offset + size > dest_offset) || (dest_offset <= src_offset && dest_offset + size > src_offset) { - throw_ub_custom!(fluent::const_eval_copy_nonoverlapping_overlapping); + throw_ub_custom!(inline_fluent!( + "`copy_nonoverlapping` called on overlapping ranges" + )); } } } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 1266e15c682fd..cccebded4b0b8 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -26,8 +26,6 @@ use rustc_middle::util::Providers; pub use self::errors::ReportErrorExt; -rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - pub fn provide(providers: &mut Providers) { const_eval::provide(&mut providers.queries); providers.queries.tag_for_variant = const_eval::tag_for_variant_provider; diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 4bbcf7373589c..3685d4ee7ebb8 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -113,9 +113,7 @@ pub fn default_translator() -> Translator { pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ // tidy-alphabetical-start - rustc_const_eval::DEFAULT_LOCALE_RESOURCE, rustc_lint::DEFAULT_LOCALE_RESOURCE, - rustc_mir_build::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE, // tidy-alphabetical-end ]; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c99af9658cdef..6bdf9f04405f4 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -392,6 +392,8 @@ declare_features! ( (unstable, cfg_sanitize, "1.41.0", Some(39699)), /// Allows `cfg(sanitizer_cfi_generalize_pointers)` and `cfg(sanitizer_cfi_normalize_integers)`. (unstable, cfg_sanitizer_cfi, "1.77.0", Some(89653)), + /// Provides a native way to easily manage multiple conditional flags without having to rewrite each clause multiple times. + (unstable, cfg_select, "CURRENT_RUSTC_VERSION", Some(115585)), /// Allows `cfg(target(abi = "..."))`. (unstable, cfg_target_compact, "1.63.0", Some(96901)), /// Allows `cfg(target_has_atomic_load_store = "...")`. diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 2f5b7ed26952a..ff771532ae496 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -998,6 +998,13 @@ lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::` +lint_unreachable_cfg_select_predicate = unreachable configuration predicate + .label = this configuration predicate is never reached + +lint_unreachable_cfg_select_predicate_wildcard = unreachable configuration predicate + .label = always matches + .label2 = this configuration predicate is never reached + lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe .label = usage of unsafe attribute lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index c0ab0d1f00409..7681eedc75ed0 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -293,6 +293,14 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } + BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => match wildcard_span { + Some(wildcard_span) => { + lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span } + .decorate_lint(diag) + } + None => lints::UnreachableCfgSelectPredicate { span }.decorate_lint(diag), + }, + BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 80b32645a8953..ea31a6373cbc7 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -297,6 +297,9 @@ fn register_builtins(store: &mut LintStore) { UNUSED_ASSIGNMENTS, DEAD_CODE, UNUSED_MUT, + // FIXME: add this lint when it becomes stable, + // see https://github.com/rust-lang/rust/issues/115585. + // UNREACHABLE_CFG_SELECT_PREDICATES, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, UNUSED_MUST_USE, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1a87cc013e799..bdc171f11e3b3 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3340,3 +3340,20 @@ pub(crate) struct UnknownCrateTypesSuggestion { pub span: Span, pub snippet: Symbol, } + +#[derive(LintDiagnostic)] +#[diag(lint_unreachable_cfg_select_predicate)] +pub(crate) struct UnreachableCfgSelectPredicate { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unreachable_cfg_select_predicate_wildcard)] +pub(crate) struct UnreachableCfgSelectPredicateWildcard { + #[label(lint_label2)] + pub span: Span, + + #[label] + pub wildcard_span: Span, +} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f4e6e93356c75..488e3a70b6695 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -123,6 +123,7 @@ declare_lint_pass! { UNKNOWN_LINTS, UNNAMEABLE_TEST_ITEMS, UNNAMEABLE_TYPES, + UNREACHABLE_CFG_SELECT_PREDICATES, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, UNSAFE_ATTR_OUTSIDE_UNSAFE, @@ -855,6 +856,34 @@ declare_lint! { "detects unreachable patterns" } +declare_lint! { + /// The `unreachable_cfg_select_predicates` lint detects unreachable configuration + /// predicates in the `cfg_select!` macro. + /// + /// ### Example + /// + /// ```rust + /// #![feature(cfg_select)] + /// cfg_select! { + /// _ => (), + /// windows => (), + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This usually indicates a mistake in how the predicates are specified or + /// ordered. In this example, the `_` predicate will always match, so the + /// `windows` is impossible to reach. Remember, arms match in order, you + /// probably wanted to put the `windows` case above the `_` case. + pub UNREACHABLE_CFG_SELECT_PREDICATES, + Warn, + "detects unreachable configuration predicates in the cfg_select macro", + @feature_gate = cfg_select; +} + declare_lint! { /// The `overlapping_range_endpoints` lint detects `match` arms that have [range patterns] that /// overlap on their endpoints. diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index b3e5b93cf2fc7..0c454ec60f4a6 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -748,6 +748,10 @@ pub enum BuiltinLintDiag { }, UnusedVisibility(Span), AttributeLint(AttributeLintKind), + UnreachableCfg { + span: Span, + wildcard_span: Option, + }, } #[derive(Debug, HashStable_Generic)] diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index f756f0a19ee9b..f05183d7c0681 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -12,7 +12,6 @@ rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } -rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl deleted file mode 100644 index 8b0c38dd3b536..0000000000000 --- a/compiler/rustc_mir_build/messages.ftl +++ /dev/null @@ -1,513 +0,0 @@ -mir_build_adt_defined_here = `{$ty}` defined here - -mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable - -mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable - -mir_build_bindings_with_variant_name = - pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}` - .suggestion = to match on the variant, qualify the path - -mir_build_borrow = value is borrowed by `{$name}` here - -mir_build_borrow_of_layout_constrained_field_requires_unsafe = - borrow of layout constrained field with interior mutability is unsafe and requires unsafe block - .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values - .label = borrow of layout constrained field with interior mutability - -mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block - .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values - .label = borrow of layout constrained field with interior mutability - -mir_build_borrow_of_moved_value = borrow of moved value - .label = value moved into `{$name}` here - .occurs_because_label = move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait - .value_borrowed_label = value borrowed here after move - .suggestion = borrow this binding in the pattern to avoid moving the value - -mir_build_call_to_deprecated_safe_fn_requires_unsafe = - call to deprecated safe function `{$function}` is unsafe and requires unsafe block - .note = consult the function's documentation for information on how to avoid undefined behavior - .label = call to unsafe function - .suggestion = you can wrap the call in an `unsafe` block if you can guarantee {$guarantee} - -mir_build_call_to_fn_with_requires_unsafe = - call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block - .help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> - [1] feature - *[count] features - }: {$missing_target_features} - .note = the {$build_target_features} target {$build_target_features_count -> - [1] feature - *[count] features - } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> - [1] it - *[count] them - } in `#[target_feature]` - .label = call to function with `#[target_feature]` - -mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block - .help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> - [1] feature - *[count] features - }: {$missing_target_features} - .note = the {$build_target_features} target {$build_target_features_count -> - [1] feature - *[count] features - } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> - [1] it - *[count] them - } in `#[target_feature]` - .label = call to function with `#[target_feature]` - -mir_build_call_to_unsafe_fn_requires_unsafe = - call to unsafe function `{$function}` is unsafe and requires unsafe block - .note = consult the function's documentation for information on how to avoid undefined behavior - .label = call to unsafe function - -mir_build_call_to_unsafe_fn_requires_unsafe_nameless = - call to unsafe function is unsafe and requires unsafe block - .note = consult the function's documentation for information on how to avoid undefined behavior - .label = call to unsafe function - -mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed = - call to unsafe function is unsafe and requires unsafe function or block - .note = consult the function's documentation for information on how to avoid undefined behavior - .label = call to unsafe function - -mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - call to unsafe function `{$function}` is unsafe and requires unsafe function or block - .note = consult the function's documentation for information on how to avoid undefined behavior - .label = call to unsafe function - -mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable - -mir_build_const_continue_bad_const = could not determine the target branch for this `#[const_continue]` - .label = this value is too generic - -mir_build_const_continue_missing_label_or_value = a `#[const_continue]` must break to a label with a value - -mir_build_const_continue_not_const = could not determine the target branch for this `#[const_continue]` - .help = try extracting the expression into a `const` item - -mir_build_const_continue_not_const_const_block = `const` blocks may use generics, and are not evaluated early enough -mir_build_const_continue_not_const_const_other = this value must be a literal or a monomorphic const -mir_build_const_continue_not_const_constant_parameter = constant parameters may use generics, and are not evaluated early enough - -mir_build_const_continue_unknown_jump_target = the target of this `#[const_continue]` is not statically known - .label = this value must be a literal or a monomorphic const - -mir_build_const_defined_here = constant defined here - -mir_build_const_param_in_pattern = constant parameters cannot be referenced in patterns - .label = can't be used in patterns -mir_build_const_param_in_pattern_def = constant defined here - -mir_build_const_pattern_depends_on_generic_parameter = constant pattern cannot depend on generic parameters - .label = `const` depends on a generic parameter - -mir_build_could_not_eval_const_pattern = could not evaluate constant pattern - .label = could not evaluate constant - -mir_build_deref_raw_pointer_requires_unsafe = - dereference of raw pointer is unsafe and requires unsafe block - .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - .label = dereference of raw pointer - -mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - dereference of raw pointer is unsafe and requires unsafe function or block - .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - .label = dereference of raw pointer - -mir_build_extern_static_requires_unsafe = - use of extern static is unsafe and requires unsafe block - .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior - .label = use of extern static - -mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - use of extern static is unsafe and requires unsafe function or block - .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior - .label = use of extern static - -mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant - -mir_build_initializing_type_with_requires_unsafe = - initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block - .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior - .label = initializing type with `rustc_layout_scalar_valid_range` attr - -mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block - .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior - .label = initializing type with `rustc_layout_scalar_valid_range` attr - -mir_build_initializing_type_with_unsafe_field_requires_unsafe = - initializing type with an unsafe field is unsafe and requires unsafe block - .note = unsafe fields may carry library invariants - .label = initialization of struct with unsafe field - -mir_build_initializing_type_with_unsafe_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - initializing type with an unsafe field is unsafe and requires unsafe block - .note = unsafe fields may carry library invariants - .label = initialization of struct with unsafe field - -mir_build_inline_assembly_requires_unsafe = - use of inline assembly is unsafe and requires unsafe block - .note = inline assembly is entirely unchecked and can cause undefined behavior - .label = use of inline assembly - -mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - use of inline assembly is unsafe and requires unsafe function or block - .note = inline assembly is entirely unchecked and can cause undefined behavior - .label = use of inline assembly - -mir_build_interpreted_as_const = introduce a variable instead - -mir_build_invalid_pattern = {$prefix} `{$non_sm_ty}` cannot be used in patterns - .label = {$prefix} can't be used in patterns - -mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count -> - [one] pattern - *[other] patterns - } - .note = {$count -> - [one] this pattern - *[other] these patterns - } will always match, so the `if let` is useless - .help = consider replacing the `if let` with a `let` - -mir_build_irrefutable_let_patterns_if_let_guard = irrefutable `if let` guard {$count -> - [one] pattern - *[other] patterns - } - .note = {$count -> - [one] this pattern - *[other] these patterns - } will always match, so the guard is useless - .help = consider removing the guard and adding a `let` inside the match arm - -mir_build_irrefutable_let_patterns_let_else = irrefutable `let...else` {$count -> - [one] pattern - *[other] patterns - } - .note = {$count -> - [one] this pattern - *[other] these patterns - } will always match, so the `else` clause is useless - .help = consider removing the `else` clause - -mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count -> - [one] pattern - *[other] patterns - } - .note = {$count -> - [one] this pattern - *[other] these patterns - } will always match, so the loop will never exit - .help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it - -mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count -> - [one] pattern - *[other] patterns - } in let chain - .note = {$count -> - [one] this pattern - *[other] these patterns - } will always match - .help = consider moving {$count -> - [one] it - *[other] them - } outside of the construct - -mir_build_literal_in_range_out_of_bounds = - literal out of range for `{$ty}` - .label = this value does not fit into the type `{$ty}` whose range is `{$min}..={$max}` - -mir_build_loop_match_arm_with_guard = - match arms that are part of a `#[loop_match]` cannot have guards - -mir_build_loop_match_bad_rhs = - this expression must be a single `match` wrapped in a labeled block - -mir_build_loop_match_bad_statements = - statements are not allowed in this position within a `#[loop_match]` - -mir_build_loop_match_invalid_match = - invalid match on `#[loop_match]` state - .note = a local variable must be the scrutinee within a `#[loop_match]` - -mir_build_loop_match_invalid_update = - invalid update of the `#[loop_match]` state - .label = the assignment must update this variable - -mir_build_loop_match_missing_assignment = - expected a single assignment expression - -mir_build_loop_match_unsupported_type = - this `#[loop_match]` state value has type `{$ty}`, which is not supported - .note = only integers, floats, bool, char, and enums without fields are supported - -mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper = - lower bound for range pattern must be less than or equal to upper bound - .label = lower bound larger than upper bound - .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. - -mir_build_lower_range_bound_must_be_less_than_upper = lower bound for range pattern must be less than upper bound - -mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html - -mir_build_moved = value is moved into `{$name}` here - -mir_build_moved_while_borrowed = cannot move out of value because it is borrowed - -mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time - -mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here - -mir_build_mutable_static_requires_unsafe = - use of mutable static is unsafe and requires unsafe block - .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior - .label = use of mutable static - -mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - use of mutable static is unsafe and requires unsafe function or block - .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior - .label = use of mutable static - -mir_build_mutation_of_layout_constrained_field_requires_unsafe = - mutation of layout constrained field is unsafe and requires unsafe block - .note = mutating layout constrained fields cannot statically be checked for valid values - .label = mutation of layout constrained field - -mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - mutation of layout constrained field is unsafe and requires unsafe function or block - .note = mutating layout constrained fields cannot statically be checked for valid values - .label = mutation of layout constrained field - -mir_build_nan_pattern = cannot use NaN in patterns - .label = evaluates to `NaN`, which is not allowed in patterns - .note = NaNs compare inequal to everything, even themselves, so this pattern would never match - .help = try using the `is_nan` method instead - -mir_build_non_const_path = runtime values cannot be referenced in patterns - .label = references a runtime value - -mir_build_non_empty_never_pattern = - mismatched types - .label = a never pattern must be used on an uninhabited type - .note = the matched value is of type `{$ty}` - -mir_build_non_exhaustive_match_all_arms_guarded = - match arms with guards don't count towards exhaustivity - -mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty - .def_note = `{$peeled_ty}` defined here - .type_note = the matched value is of type `{$ty}` - .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive - .reference_note = references are always considered inhabited - .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown - .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern - -mir_build_non_partial_eq_match = constant of non-structural type `{$ty}` in a pattern - .label = constant of non-structural type - -mir_build_pattern_not_covered = refutable pattern in {$origin} - .pattern_ty = the matched value is of type `{$pattern_ty}` - -mir_build_pointer_pattern = function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon - .label = can't be used in patterns - .note = see https://github.com/rust-lang/rust/issues/70861 for details - -mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future - -mir_build_static_in_pattern = statics cannot be referenced in patterns - .label = can't be used in patterns -mir_build_static_in_pattern_def = `static` defined here - -mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits - - -mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count -> - [one] variant that isn't - *[other] variants that aren't - } matched - -mir_build_suggest_let_else = you might want to use `let...else` to handle the {$count -> - [one] variant that isn't - *[other] variants that aren't - } matched - -mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count -> - [one] pattern - *[other] patterns - } in let chain - .note = {$count -> - [one] this pattern - *[other] these patterns - } will always match - .help = consider moving {$count -> - [one] it - *[other] them - } into the body - -mir_build_type_not_structural = constant of non-structural type `{$ty}` in a pattern - .label = constant of non-structural type -mir_build_type_not_structural_def = `{$ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns -mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -mir_build_type_not_structural_tip = - the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details - -mir_build_union_field_requires_unsafe = - access to union field is unsafe and requires unsafe block - .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior - .label = access to union field - -mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - access to union field is unsafe and requires unsafe function or block - .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior - .label = access to union field - -mir_build_union_pattern = cannot use unions in constant patterns - .label = can't use a `union` here - -mir_build_unreachable_due_to_uninhabited = unreachable {$descr} - .label = unreachable {$descr} - .label_orig = any code following this expression is unreachable - .note = this expression has type `{$ty}`, which is uninhabited - -mir_build_unreachable_making_this_unreachable = collectively making this unreachable - -mir_build_unreachable_making_this_unreachable_n_more = ...and {$covered_by_many_n_more_count} other patterns collectively make this unreachable - -mir_build_unreachable_matches_same_values = matches some of the same values - -mir_build_unreachable_pattern = unreachable pattern - .label = no value can reach this - .unreachable_matches_no_values = matches no values because `{$matches_no_values_ty}` is uninhabited - .unreachable_uninhabited_note = to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types - .unreachable_covered_by_catchall = matches any value - .unreachable_covered_by_one = matches all the relevant values - .unreachable_covered_by_many = multiple earlier patterns match some of the same values - .unreachable_pattern_const_reexport_accessible = there is a constant of the same name imported in another scope, which could have been used to pattern match against its value instead of introducing a new catch-all binding, but it needs to be imported in the pattern's scope - .unreachable_pattern_wanted_const = you might have meant to pattern match against the value of {$is_typo -> - [true] similarly named constant - *[false] constant - } `{$const_name}` instead of introducing a new catch-all binding - .unreachable_pattern_const_inaccessible = there is a constant of the same name, which could have been used to pattern match against its value instead of introducing a new catch-all binding, but it is not accessible from this scope - .unreachable_pattern_let_binding = there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings - .suggestion = remove the match arm - -mir_build_unsafe_binder_cast_requires_unsafe = - unsafe binder cast is unsafe and requires unsafe block - .label = unsafe binder cast - .note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime - information that may be required to uphold safety guarantees of a type - -mir_build_unsafe_binder_cast_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - unsafe binder cast is unsafe and requires unsafe block or unsafe fn - .label = unsafe binder cast - .note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime - information that may be required to uphold safety guarantees of a type - -mir_build_unsafe_field_requires_unsafe = - use of unsafe field is unsafe and requires unsafe block - .note = unsafe fields may carry library invariants - .label = use of unsafe field - -mir_build_unsafe_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = - use of unsafe field is unsafe and requires unsafe block - .note = unsafe fields may carry library invariants - .label = use of unsafe field - -mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default -mir_build_unsafe_not_inherited = items do not inherit unsafety from separate enclosing items - -mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe = - borrow of layout constrained field with interior mutability is unsafe and requires unsafe block - .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values - .label = borrow of layout constrained field with interior mutability - -mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe = - call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block - .help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> - [1] feature - *[count] features - }: {$missing_target_features} - .note = the {$build_target_features} target {$build_target_features_count -> - [1] feature - *[count] features - } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> - [1] it - *[count] them - } in `#[target_feature]` - .label = call to function with `#[target_feature]` - -mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe = - call to unsafe function `{$function}` is unsafe and requires unsafe block - .note = consult the function's documentation for information on how to avoid undefined behavior - .label = call to unsafe function - -mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless = - call to unsafe function is unsafe and requires unsafe block - .note = consult the function's documentation for information on how to avoid undefined behavior - .label = call to unsafe function - -mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe = - dereference of raw pointer is unsafe and requires unsafe block - .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - .label = dereference of raw pointer - -mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe = - use of extern static is unsafe and requires unsafe block - .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior - .label = use of extern static - -mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe = - initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block - .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior - .label = initializing type with `rustc_layout_scalar_valid_range` attr - -mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_unsafe_field_requires_unsafe = - initializing type with an unsafe field is unsafe and requires unsafe block - .note = unsafe fields may carry library invariants - .label = initialization of struct with unsafe field - -mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe = - use of inline assembly is unsafe and requires unsafe block - .note = inline assembly is entirely unchecked and can cause undefined behavior - .label = use of inline assembly - -mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe = - use of mutable static is unsafe and requires unsafe block - .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior - .label = use of mutable static - -mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe = - mutation of layout constrained field is unsafe and requires unsafe block - .note = mutating layout constrained fields cannot statically be checked for valid values - .label = mutation of layout constrained field - -mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe = - access to union field is unsafe and requires unsafe block - .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior - .label = access to union field - -mir_build_unsafe_op_in_unsafe_fn_unsafe_field_requires_unsafe = - use of unsafe field is unsafe and requires unsafe block - .note = unsafe fields may carry library invariants - .label = use of unsafe field - -mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns - -mir_build_unused_unsafe = unnecessary `unsafe` block - .label = unnecessary `unsafe` block - -mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block - -mir_build_upper_range_bound_cannot_be_min = exclusive upper bound for a range bound cannot be the minimum - -mir_build_variant_defined_here = not covered - -mir_build_wrap_suggestion = consider wrapping the function body in an unsafe block diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 64e2bb3207c87..f51e130ea47a5 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,7 +1,7 @@ use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, - MultiSpan, Subdiagnostic, + MultiSpan, Subdiagnostic, inline_fluent, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -9,12 +9,10 @@ use rustc_pattern_analysis::errors::Uncovered; use rustc_pattern_analysis::rustc::RustcPatCtxt; use rustc_span::{Ident, Span, Symbol}; -use crate::fluent_generated as fluent; - #[derive(LintDiagnostic)] -#[diag(mir_build_call_to_deprecated_safe_fn_requires_unsafe)] +#[diag("call to deprecated safe function `{$function}` is unsafe and requires unsafe block")] pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe { - #[label] + #[label("call to unsafe function")] pub(crate) span: Span, pub(crate) function: String, pub(crate) guarantee: String, @@ -23,7 +21,10 @@ pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe { } #[derive(Subdiagnostic)] -#[multipart_suggestion(mir_build_suggestion, applicability = "machine-applicable")] +#[multipart_suggestion( + "you can wrap the call in an `unsafe` block if you can guarantee that the environment access only happens in single-threaded code", + applicability = "machine-applicable" +)] pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafeSub { pub(crate) start_of_line_suggestion: String, #[suggestion_part(code = "{start_of_line_suggestion}")] @@ -35,10 +36,10 @@ pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafeSub { } #[derive(LintDiagnostic)] -#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe, code = E0133)] -#[note] +#[diag("call to unsafe function `{$function}` is unsafe and requires unsafe block", code = E0133)] +#[note("consult the function's documentation for information on how to avoid undefined behavior")] pub(crate) struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe { - #[label] + #[label("call to unsafe function")] pub(crate) span: Span, pub(crate) function: String, #[subdiagnostic] @@ -46,90 +47,100 @@ pub(crate) struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe { } #[derive(LintDiagnostic)] -#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless, code = E0133)] -#[note] +#[diag("call to unsafe function is unsafe and requires unsafe block", code = E0133)] +#[note("consult the function's documentation for information on how to avoid undefined behavior")] pub(crate) struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { - #[label] + #[label("call to unsafe function")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(LintDiagnostic)] -#[diag(mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe, code = E0133)] -#[note] +#[diag("use of inline assembly is unsafe and requires unsafe block", code = E0133)] +#[note("inline assembly is entirely unchecked and can cause undefined behavior")] pub(crate) struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { - #[label] + #[label("use of inline assembly")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(LintDiagnostic)] -#[diag(mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe, code = E0133)] -#[note] +#[diag("initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block", code = E0133)] +#[note( + "initializing a layout restricted type's field with a value outside the valid range is undefined behavior" +)] pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { - #[label] + #[label("initializing type with `rustc_layout_scalar_valid_range` attr")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(LintDiagnostic)] -#[diag(mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_unsafe_field_requires_unsafe, code = E0133)] -#[note] +#[diag("initializing type with an unsafe field is unsafe and requires unsafe block", code = E0133)] +#[note("unsafe fields may carry library invariants")] pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithUnsafeFieldRequiresUnsafe { - #[label] + #[label("initialization of struct with unsafe field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(LintDiagnostic)] -#[diag(mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe, code = E0133)] -#[note] +#[diag("use of mutable static is unsafe and requires unsafe block", code = E0133)] +#[note( + "mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior" +)] pub(crate) struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { - #[label] + #[label("use of mutable static")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(LintDiagnostic)] -#[diag(mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe, code = E0133)] -#[note] +#[diag("use of extern static is unsafe and requires unsafe block", code = E0133)] +#[note( + "extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior" +)] pub(crate) struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { - #[label] + #[label("use of extern static")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(LintDiagnostic)] -#[diag(mir_build_unsafe_op_in_unsafe_fn_unsafe_field_requires_unsafe, code = E0133)] -#[note] +#[diag("use of unsafe field is unsafe and requires unsafe block", code = E0133)] +#[note("unsafe fields may carry library invariants")] pub(crate) struct UnsafeOpInUnsafeFnUseOfUnsafeFieldRequiresUnsafe { - #[label] + #[label("use of unsafe field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(LintDiagnostic)] -#[diag(mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe, code = E0133)] -#[note] +#[diag("dereference of raw pointer is unsafe and requires unsafe block", code = E0133)] +#[note( + "raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior" +)] pub(crate) struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { - #[label] + #[label("dereference of raw pointer")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(LintDiagnostic)] -#[diag(mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe, code = E0133)] -#[note] +#[diag("access to union field is unsafe and requires unsafe block", code = E0133)] +#[note( + "the field may not be properly initialized: using uninitialized data will cause undefined behavior" +)] pub(crate) struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { - #[label] + #[label("access to union field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, @@ -137,12 +148,12 @@ pub(crate) struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { #[derive(LintDiagnostic)] #[diag( - mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe, + "mutation of layout constrained field is unsafe and requires unsafe block", code = E0133 )] -#[note] +#[note("mutating layout constrained fields cannot statically be checked for valid values")] pub(crate) struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { - #[label] + #[label("mutation of layout constrained field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, @@ -150,11 +161,11 @@ pub(crate) struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsa #[derive(LintDiagnostic)] #[diag( - mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe, + "borrow of layout constrained field with interior mutability is unsafe and requires unsafe block", code = E0133, )] pub(crate) struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { - #[label] + #[label("borrow of layout constrained field with interior mutability")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, @@ -162,26 +173,37 @@ pub(crate) struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe #[derive(LintDiagnostic)] #[diag( - mir_build_unsafe_binder_cast_requires_unsafe, + "unsafe binder cast is unsafe and requires unsafe block information that may be required to uphold safety guarantees of a type", code = E0133, )] pub(crate) struct UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe { - #[label] + #[label("unsafe binder cast")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(LintDiagnostic)] -#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe, code = E0133)] -#[help] +#[diag("call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block", code = E0133)] +#[help( + "in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> + [1] feature + *[count] features + }: {$missing_target_features}" +)] pub(crate) struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { - #[label] + #[label("call to function with `#[target_feature]`")] pub(crate) span: Span, pub(crate) function: String, pub(crate) missing_target_features: DiagArgValue, pub(crate) missing_target_features_count: usize, - #[note] + #[note("the {$build_target_features} target {$build_target_features_count -> + [1] feature + *[count] features + } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> + [1] it +*[count] them +} in `#[target_feature]`")] pub(crate) note: bool, pub(crate) build_target_features: DiagArgValue, pub(crate) build_target_features_count: usize, @@ -190,11 +212,11 @@ pub(crate) struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_call_to_unsafe_fn_requires_unsafe, code = E0133)] -#[note] +#[diag("call to unsafe function `{$function}` is unsafe and requires unsafe block", code = E0133)] +#[note("consult the function's documentation for information on how to avoid undefined behavior")] pub(crate) struct CallToUnsafeFunctionRequiresUnsafe { #[primary_span] - #[label] + #[label("call to unsafe function")] pub(crate) span: Span, pub(crate) function: String, #[subdiagnostic] @@ -202,22 +224,22 @@ pub(crate) struct CallToUnsafeFunctionRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_nameless, code = E0133)] -#[note] +#[diag("call to unsafe function is unsafe and requires unsafe block", code = E0133)] +#[note("consult the function's documentation for information on how to avoid undefined behavior")] pub(crate) struct CallToUnsafeFunctionRequiresUnsafeNameless { #[primary_span] - #[label] + #[label("call to unsafe function")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] -#[note] +#[diag("call to unsafe function `{$function}` is unsafe and requires unsafe function or block", code = E0133)] +#[note("consult the function's documentation for information on how to avoid undefined behavior")] pub(crate) struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("call to unsafe function")] pub(crate) span: Span, pub(crate) function: String, #[subdiagnostic] @@ -226,57 +248,59 @@ pub(crate) struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[derive(Diagnostic)] #[diag( - mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed, + "call to unsafe function is unsafe and requires unsafe function or block", code = E0133 )] -#[note] +#[note("consult the function's documentation for information on how to avoid undefined behavior")] pub(crate) struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("call to unsafe function")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_inline_assembly_requires_unsafe, code = E0133)] -#[note] +#[diag("use of inline assembly is unsafe and requires unsafe block", code = E0133)] +#[note("inline assembly is entirely unchecked and can cause undefined behavior")] pub(crate) struct UseOfInlineAssemblyRequiresUnsafe { #[primary_span] - #[label] + #[label("use of inline assembly")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] -#[note] +#[diag("use of inline assembly is unsafe and requires unsafe function or block", code = E0133)] +#[note("inline assembly is entirely unchecked and can cause undefined behavior")] pub(crate) struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("use of inline assembly")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_initializing_type_with_requires_unsafe, code = E0133)] -#[note] +#[diag("initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block", code = E0133)] +#[note( + "initializing a layout restricted type's field with a value outside the valid range is undefined behavior" +)] pub(crate) struct InitializingTypeWithRequiresUnsafe { #[primary_span] - #[label] + #[label("initializing type with `rustc_layout_scalar_valid_range` attr")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_initializing_type_with_unsafe_field_requires_unsafe, code = E0133)] -#[note] +#[diag("initializing type with an unsafe field is unsafe and requires unsafe block", code = E0133)] +#[note("unsafe fields may carry library invariants")] pub(crate) struct InitializingTypeWithUnsafeFieldRequiresUnsafe { #[primary_span] - #[label] + #[label("initialization of struct with unsafe field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, @@ -284,13 +308,15 @@ pub(crate) struct InitializingTypeWithUnsafeFieldRequiresUnsafe { #[derive(Diagnostic)] #[diag( - mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + "initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block", code = E0133 )] -#[note] +#[note( + "initializing a layout restricted type's field with a value outside the valid range is undefined behavior" +)] pub(crate) struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("initializing type with `rustc_layout_scalar_valid_range` attr")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, @@ -298,134 +324,150 @@ pub(crate) struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[derive(Diagnostic)] #[diag( - mir_build_initializing_type_with_unsafe_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + "initializing type with an unsafe field is unsafe and requires unsafe block", code = E0133 )] -#[note] +#[note("unsafe fields may carry library invariants")] pub(crate) struct InitializingTypeWithUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("initialization of struct with unsafe field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_mutable_static_requires_unsafe, code = E0133)] -#[note] +#[diag("use of mutable static is unsafe and requires unsafe block", code = E0133)] +#[note( + "mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior" +)] pub(crate) struct UseOfMutableStaticRequiresUnsafe { #[primary_span] - #[label] + #[label("use of mutable static")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] -#[note] +#[diag("use of mutable static is unsafe and requires unsafe function or block", code = E0133)] +#[note( + "mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior" +)] pub(crate) struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("use of mutable static")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_extern_static_requires_unsafe, code = E0133)] -#[note] +#[diag("use of extern static is unsafe and requires unsafe block", code = E0133)] +#[note( + "extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior" +)] pub(crate) struct UseOfExternStaticRequiresUnsafe { #[primary_span] - #[label] + #[label("use of extern static")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] -#[note] +#[diag("use of extern static is unsafe and requires unsafe function or block", code = E0133)] +#[note( + "extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior" +)] pub(crate) struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("use of extern static")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_unsafe_field_requires_unsafe, code = E0133)] -#[note] +#[diag("use of unsafe field is unsafe and requires unsafe block", code = E0133)] +#[note("unsafe fields may carry library invariants")] pub(crate) struct UseOfUnsafeFieldRequiresUnsafe { #[primary_span] - #[label] + #[label("use of unsafe field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_unsafe_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] -#[note] +#[diag("use of unsafe field is unsafe and requires unsafe block", code = E0133)] +#[note("unsafe fields may carry library invariants")] pub(crate) struct UseOfUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("use of unsafe field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_deref_raw_pointer_requires_unsafe, code = E0133)] -#[note] +#[diag("dereference of raw pointer is unsafe and requires unsafe block", code = E0133)] +#[note( + "raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior" +)] pub(crate) struct DerefOfRawPointerRequiresUnsafe { #[primary_span] - #[label] + #[label("dereference of raw pointer")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] -#[note] +#[diag("dereference of raw pointer is unsafe and requires unsafe function or block", code = E0133)] +#[note( + "raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior" +)] pub(crate) struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("dereference of raw pointer")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_union_field_requires_unsafe, code = E0133)] -#[note] +#[diag("access to union field is unsafe and requires unsafe block", code = E0133)] +#[note( + "the field may not be properly initialized: using uninitialized data will cause undefined behavior" +)] pub(crate) struct AccessToUnionFieldRequiresUnsafe { #[primary_span] - #[label] + #[label("access to union field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] -#[note] +#[diag("access to union field is unsafe and requires unsafe function or block", code = E0133)] +#[note( + "the field may not be properly initialized: using uninitialized data will cause undefined behavior" +)] pub(crate) struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("access to union field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_mutation_of_layout_constrained_field_requires_unsafe, code = E0133)] -#[note] +#[diag("mutation of layout constrained field is unsafe and requires unsafe block", code = E0133)] +#[note("mutating layout constrained fields cannot statically be checked for valid values")] pub(crate) struct MutationOfLayoutConstrainedFieldRequiresUnsafe { #[primary_span] - #[label] + #[label("mutation of layout constrained field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, @@ -433,24 +475,26 @@ pub(crate) struct MutationOfLayoutConstrainedFieldRequiresUnsafe { #[derive(Diagnostic)] #[diag( - mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + "mutation of layout constrained field is unsafe and requires unsafe function or block", code = E0133 )] -#[note] +#[note("mutating layout constrained fields cannot statically be checked for valid values")] pub(crate) struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("mutation of layout constrained field")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_borrow_of_layout_constrained_field_requires_unsafe, code = E0133)] -#[note] +#[diag("borrow of layout constrained field with interior mutability is unsafe and requires unsafe block", code = E0133)] +#[note( + "references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values" +)] pub(crate) struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { #[primary_span] - #[label] + #[label("borrow of layout constrained field with interior mutability")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, @@ -458,29 +502,42 @@ pub(crate) struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { #[derive(Diagnostic)] #[diag( - mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + "borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block", code = E0133 )] -#[note] +#[note( + "references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values" +)] pub(crate) struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("borrow of layout constrained field with interior mutability")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] -#[diag(mir_build_call_to_fn_with_requires_unsafe, code = E0133)] -#[help] +#[diag("call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block", code = E0133)] +#[help( + "in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> + [1] feature + *[count] features +}: {$missing_target_features}" +)] pub(crate) struct CallToFunctionWithRequiresUnsafe { #[primary_span] - #[label] + #[label("call to function with `#[target_feature]`")] pub(crate) span: Span, pub(crate) function: String, pub(crate) missing_target_features: DiagArgValue, pub(crate) missing_target_features_count: usize, - #[note] + #[note("the {$build_target_features} target {$build_target_features_count -> + [1] feature + *[count] features +} being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> + [1] it + *[count] them +} in `#[target_feature]`")] pub(crate) note: bool, pub(crate) build_target_features: DiagArgValue, pub(crate) build_target_features_count: usize, @@ -489,16 +546,30 @@ pub(crate) struct CallToFunctionWithRequiresUnsafe { } #[derive(Diagnostic)] -#[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] -#[help] +#[diag( + "call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block", + code = E0133, +)] +#[help( + "in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> + [1] feature + *[count] features +}: {$missing_target_features}" +)] pub(crate) struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("call to function with `#[target_feature]`")] pub(crate) span: Span, pub(crate) function: String, pub(crate) missing_target_features: DiagArgValue, pub(crate) missing_target_features_count: usize, - #[note] + #[note("the {$build_target_features} target {$build_target_features_count -> + [1] feature + *[count] features + } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> + [1] it + *[count] them + } in `#[target_feature]`")] pub(crate) note: bool, pub(crate) build_target_features: DiagArgValue, pub(crate) build_target_features_count: usize, @@ -508,12 +579,12 @@ pub(crate) struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[derive(Diagnostic)] #[diag( - mir_build_unsafe_binder_cast_requires_unsafe, + "unsafe binder cast is unsafe and requires unsafe block information that may be required to uphold safety guarantees of a type", code = E0133, )] pub(crate) struct UnsafeBinderCastRequiresUnsafe { #[primary_span] - #[label] + #[label("unsafe binder cast")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, @@ -521,19 +592,19 @@ pub(crate) struct UnsafeBinderCastRequiresUnsafe { #[derive(Diagnostic)] #[diag( - mir_build_unsafe_binder_cast_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + "unsafe binder cast is unsafe and requires unsafe block or unsafe fn information that may be required to uphold safety guarantees of a type", code = E0133, )] pub(crate) struct UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] - #[label] + #[label("unsafe binder cast")] pub(crate) span: Span, #[subdiagnostic] pub(crate) unsafe_not_inherited_note: Option, } #[derive(Subdiagnostic)] -#[label(mir_build_unsafe_not_inherited)] +#[label("items do not inherit unsafety from separate enclosing items")] pub(crate) struct UnsafeNotInheritedNote { #[primary_span] pub(crate) span: Span, @@ -546,11 +617,16 @@ pub(crate) struct UnsafeNotInheritedLintNote { impl Subdiagnostic for UnsafeNotInheritedLintNote { fn add_to_diag(self, diag: &mut Diag<'_, G>) { - diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body); + diag.span_note( + self.signature_span, + inline_fluent!( + "an unsafe function restricts its caller, but its body is safe by default" + ), + ); let body_start = self.body_span.shrink_to_lo(); let body_end = self.body_span.shrink_to_hi(); diag.tool_only_multipart_suggestion( - fluent::mir_build_wrap_suggestion, + inline_fluent!("consider wrapping the function body in an unsafe block"), vec![(body_start, "{ unsafe ".into()), (body_end, "}".into())], Applicability::MachineApplicable, ); @@ -558,9 +634,9 @@ impl Subdiagnostic for UnsafeNotInheritedLintNote { } #[derive(LintDiagnostic)] -#[diag(mir_build_unused_unsafe)] +#[diag("unnecessary `unsafe` block")] pub(crate) struct UnusedUnsafe { - #[label] + #[label("unnecessary `unsafe` block")] pub(crate) span: Span, #[subdiagnostic] pub(crate) enclosing: Option, @@ -568,7 +644,7 @@ pub(crate) struct UnusedUnsafe { #[derive(Subdiagnostic)] pub(crate) enum UnusedUnsafeEnclosing { - #[label(mir_build_unused_unsafe_enclosing_block_label)] + #[label("because it's nested under this `unsafe` block")] Block { #[primary_span] span: Span, @@ -584,8 +660,11 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> { impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { - let mut diag = - Diag::new(dcx, level, fluent::mir_build_non_exhaustive_patterns_type_not_empty); + let mut diag = Diag::new( + dcx, + level, + inline_fluent!("non-exhaustive patterns: type `{$ty}` is non-empty"), + ); diag.span(self.scrut_span); diag.code(E0004); let peeled_ty = self.ty.peel_refs(); @@ -605,20 +684,22 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo let mut span: MultiSpan = def_span.into(); span.push_span_label(def_span, ""); - diag.span_note(span, fluent::mir_build_def_note); + diag.span_note(span, inline_fluent!("`{$peeled_ty}` defined here")); } let is_non_exhaustive = matches!(self.ty.kind(), ty::Adt(def, _) if def.variant_list_has_applicable_non_exhaustive()); if is_non_exhaustive { - diag.note(fluent::mir_build_non_exhaustive_type_note); + diag.note(inline_fluent!( + "the matched value is of type `{$ty}`, which is marked as non-exhaustive" + )); } else { - diag.note(fluent::mir_build_type_note); + diag.note(inline_fluent!("the matched value is of type `{$ty}`")); } if let ty::Ref(_, sub_ty, _) = self.ty.kind() { if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.typing_env) { - diag.note(fluent::mir_build_reference_note); + diag.note(inline_fluent!("references are always considered inhabited")); } } @@ -633,12 +714,14 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo }; diag.span_suggestion_verbose( braces_span, - fluent::mir_build_suggestion, + inline_fluent!("ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown"), format!(" {{{indentation}{more}_ => todo!(),{indentation}}}"), Applicability::HasPlaceholders, ); } else { - diag.help(fluent::mir_build_help); + diag.help(inline_fluent!( + "ensure that all possible cases are being handled by adding a match arm with a wildcard pattern" + )); } diag @@ -646,69 +729,80 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo } #[derive(Subdiagnostic)] -#[note(mir_build_non_exhaustive_match_all_arms_guarded)] +#[note("match arms with guards don't count towards exhaustivity")] pub(crate) struct NonExhaustiveMatchAllArmsGuarded; #[derive(Diagnostic)] -#[diag(mir_build_static_in_pattern, code = E0158)] +#[diag("statics cannot be referenced in patterns", code = E0158)] pub(crate) struct StaticInPattern { #[primary_span] - #[label] + #[label("can't be used in patterns")] pub(crate) span: Span, - #[label(mir_build_static_in_pattern_def)] + #[label("`static` defined here")] pub(crate) static_span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_const_param_in_pattern, code = E0158)] +#[diag("constant parameters cannot be referenced in patterns", code = E0158)] pub(crate) struct ConstParamInPattern { #[primary_span] - #[label] + #[label("can't be used in patterns")] pub(crate) span: Span, - #[label(mir_build_const_param_in_pattern_def)] + #[label("constant defined here")] pub(crate) const_span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_non_const_path, code = E0080)] +#[diag("runtime values cannot be referenced in patterns", code = E0080)] pub(crate) struct NonConstPath { #[primary_span] - #[label] + #[label("references a runtime value")] pub(crate) span: Span, } #[derive(LintDiagnostic)] -#[diag(mir_build_unreachable_pattern)] +#[diag("unreachable pattern")] pub(crate) struct UnreachablePattern<'tcx> { - #[label] + #[label("no value can reach this")] pub(crate) span: Option, - #[label(mir_build_unreachable_matches_no_values)] + #[label("matches no values because `{$matches_no_values_ty}` is uninhabited")] pub(crate) matches_no_values: Option, pub(crate) matches_no_values_ty: Ty<'tcx>, - #[note(mir_build_unreachable_uninhabited_note)] + #[note( + "to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types" + )] pub(crate) uninhabited_note: Option<()>, - #[label(mir_build_unreachable_covered_by_catchall)] + #[label("matches any value")] pub(crate) covered_by_catchall: Option, #[subdiagnostic] pub(crate) wanted_constant: Option, - #[note(mir_build_unreachable_pattern_const_reexport_accessible)] + #[note( + "there is a constant of the same name imported in another scope, which could have been used to pattern match against its value instead of introducing a new catch-all binding, but it needs to be imported in the pattern's scope" + )] pub(crate) accessible_constant: Option, - #[note(mir_build_unreachable_pattern_const_inaccessible)] + #[note( + "there is a constant of the same name, which could have been used to pattern match against its value instead of introducing a new catch-all binding, but it is not accessible from this scope" + )] pub(crate) inaccessible_constant: Option, - #[note(mir_build_unreachable_pattern_let_binding)] + #[note( + "there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings" + )] pub(crate) pattern_let_binding: Option, - #[label(mir_build_unreachable_covered_by_one)] + #[label("matches all the relevant values")] pub(crate) covered_by_one: Option, - #[note(mir_build_unreachable_covered_by_many)] + #[note("multiple earlier patterns match some of the same values")] pub(crate) covered_by_many: Option, pub(crate) covered_by_many_n_more_count: usize, - #[suggestion(code = "", applicability = "machine-applicable")] + #[suggestion("remove the match arm", code = "", applicability = "machine-applicable")] pub(crate) suggest_remove: Option, } #[derive(Subdiagnostic)] #[suggestion( - mir_build_unreachable_pattern_wanted_const, + "you might have meant to pattern match against the value of {$is_typo -> + [true] similarly named constant + *[false] constant + } `{$const_name}` instead of introducing a new catch-all binding", code = "{const_path}", applicability = "machine-applicable" )] @@ -721,48 +815,50 @@ pub(crate) struct WantedConstant { } #[derive(LintDiagnostic)] -#[diag(mir_build_unreachable_due_to_uninhabited)] +#[diag("unreachable {$descr}")] pub(crate) struct UnreachableDueToUninhabited<'desc, 'tcx> { pub descr: &'desc str, - #[label] + #[label("unreachable {$descr}")] pub expr: Span, - #[label(mir_build_label_orig)] - #[note] + #[label("any code following this expression is unreachable")] + #[note("this expression has type `{$ty}`, which is uninhabited")] pub orig: Span, pub ty: Ty<'tcx>, } #[derive(Diagnostic)] -#[diag(mir_build_const_pattern_depends_on_generic_parameter, code = E0158)] +#[diag("constant pattern cannot depend on generic parameters", code = E0158)] pub(crate) struct ConstPatternDependsOnGenericParameter { #[primary_span] - #[label] + #[label("`const` depends on a generic parameter")] pub(crate) span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_could_not_eval_const_pattern)] +#[diag("could not evaluate constant pattern")] pub(crate) struct CouldNotEvalConstPattern { #[primary_span] - #[label] + #[label("could not evaluate constant")] pub(crate) span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper, code = E0030)] +#[diag("lower bound for range pattern must be less than or equal to upper bound", code = E0030)] pub(crate) struct LowerRangeBoundMustBeLessThanOrEqualToUpper { #[primary_span] - #[label] + #[label("lower bound larger than upper bound")] pub(crate) span: Span, - #[note(mir_build_teach_note)] + #[note( + "When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range." + )] pub(crate) teach: bool, } #[derive(Diagnostic)] -#[diag(mir_build_literal_in_range_out_of_bounds)] +#[diag("literal out of range for `{$ty}`")] pub(crate) struct LiteralOutOfRange<'tcx> { #[primary_span] - #[label] + #[label("this value does not fit into the type `{$ty}` whose range is `{$min}..={$max}`")] pub(crate) span: Span, pub(crate) ty: Ty<'tcx>, pub(crate) min: i128, @@ -770,93 +866,173 @@ pub(crate) struct LiteralOutOfRange<'tcx> { } #[derive(Diagnostic)] -#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = E0579)] +#[diag("lower bound for range pattern must be less than upper bound", code = E0579)] pub(crate) struct LowerRangeBoundMustBeLessThanUpper { #[primary_span] pub(crate) span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_upper_range_bound_cannot_be_min, code = E0579)] +#[diag("exclusive upper bound for a range bound cannot be the minimum", code = E0579)] pub(crate) struct UpperRangeBoundCannotBeMin { #[primary_span] pub(crate) span: Span, } #[derive(LintDiagnostic)] -#[diag(mir_build_leading_irrefutable_let_patterns)] -#[note] -#[help] +#[diag( + "leading irrefutable {$count -> + [one] pattern + *[other] patterns +} in let chain" +)] +#[note( + "{$count -> + [one] this pattern + *[other] these patterns +} will always match" +)] +#[help( + "consider moving {$count -> + [one] it + *[other] them +} outside of the construct" +)] pub(crate) struct LeadingIrrefutableLetPatterns { pub(crate) count: usize, } #[derive(LintDiagnostic)] -#[diag(mir_build_trailing_irrefutable_let_patterns)] -#[note] -#[help] +#[diag( + "trailing irrefutable {$count -> + [one] pattern + *[other] patterns +} in let chain" +)] +#[note( + "{$count -> + [one] this pattern + *[other] these patterns +} will always match" +)] +#[help( + "consider moving {$count -> + [one] it + *[other] them +} into the body" +)] pub(crate) struct TrailingIrrefutableLetPatterns { pub(crate) count: usize, } #[derive(LintDiagnostic)] -#[diag(mir_build_bindings_with_variant_name, code = E0170)] +#[diag("pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`", code = E0170)] pub(crate) struct BindingsWithVariantName { - #[suggestion(code = "{ty_path}::{name}", applicability = "machine-applicable")] + #[suggestion( + "to match on the variant, qualify the path", + code = "{ty_path}::{name}", + applicability = "machine-applicable" + )] pub(crate) suggestion: Option, pub(crate) ty_path: String, pub(crate) name: Ident, } #[derive(LintDiagnostic)] -#[diag(mir_build_irrefutable_let_patterns_if_let)] -#[note] -#[help] +#[diag( + "irrefutable `if let` {$count -> + [one] pattern + *[other] patterns +}" +)] +#[note( + "{$count -> + [one] this pattern + *[other] these patterns +} will always match, so the `if let` is useless" +)] +#[help("consider replacing the `if let` with a `let`")] pub(crate) struct IrrefutableLetPatternsIfLet { pub(crate) count: usize, } #[derive(LintDiagnostic)] -#[diag(mir_build_irrefutable_let_patterns_if_let_guard)] -#[note] -#[help] +#[diag( + "irrefutable `if let` guard {$count -> + [one] pattern + *[other] patterns +}" +)] +#[note( + "{$count -> + [one] this pattern + *[other] these patterns +} will always match, so the guard is useless" +)] +#[help("consider removing the guard and adding a `let` inside the match arm")] pub(crate) struct IrrefutableLetPatternsIfLetGuard { pub(crate) count: usize, } #[derive(LintDiagnostic)] -#[diag(mir_build_irrefutable_let_patterns_let_else)] -#[note] -#[help] +#[diag( + "irrefutable `let...else` {$count -> + [one] pattern + *[other] patterns +}" +)] +#[note( + "{$count -> + [one] this pattern + *[other] these patterns +} will always match, so the `else` clause is useless" +)] +#[help("consider removing the `else` clause")] pub(crate) struct IrrefutableLetPatternsLetElse { pub(crate) count: usize, } #[derive(LintDiagnostic)] -#[diag(mir_build_irrefutable_let_patterns_while_let)] -#[note] -#[help] +#[diag( + "irrefutable `while let` {$count -> + [one] pattern + *[other] patterns +}" +)] +#[note( + "{$count -> + [one] this pattern + *[other] these patterns +} will always match, so the loop will never exit" +)] +#[help("consider instead using a `loop {\"{\"} ... {\"}\"}` with a `let` inside it")] pub(crate) struct IrrefutableLetPatternsWhileLet { pub(crate) count: usize, } #[derive(Diagnostic)] -#[diag(mir_build_borrow_of_moved_value)] +#[diag("borrow of moved value")] pub(crate) struct BorrowOfMovedValue<'tcx> { #[primary_span] - #[label] - #[label(mir_build_occurs_because_label)] + #[label("value moved into `{$name}` here")] + #[label( + "move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait" + )] pub(crate) binding_span: Span, - #[label(mir_build_value_borrowed_label)] + #[label("value borrowed here after move")] pub(crate) conflicts_ref: Vec, pub(crate) name: Ident, pub(crate) ty: Ty<'tcx>, - #[suggestion(code = "ref ", applicability = "machine-applicable")] + #[suggestion( + "borrow this binding in the pattern to avoid moving the value", + code = "ref ", + applicability = "machine-applicable" + )] pub(crate) suggest_borrowing: Option, } #[derive(Diagnostic)] -#[diag(mir_build_multiple_mut_borrows)] +#[diag("cannot borrow value as mutable more than once at a time")] pub(crate) struct MultipleMutBorrows { #[primary_span] pub(crate) span: Span, @@ -865,7 +1041,7 @@ pub(crate) struct MultipleMutBorrows { } #[derive(Diagnostic)] -#[diag(mir_build_already_borrowed)] +#[diag("cannot borrow value as mutable because it is also borrowed as immutable")] pub(crate) struct AlreadyBorrowed { #[primary_span] pub(crate) span: Span, @@ -874,7 +1050,7 @@ pub(crate) struct AlreadyBorrowed { } #[derive(Diagnostic)] -#[diag(mir_build_already_mut_borrowed)] +#[diag("cannot borrow value as immutable because it is also borrowed as mutable")] pub(crate) struct AlreadyMutBorrowed { #[primary_span] pub(crate) span: Span, @@ -883,7 +1059,7 @@ pub(crate) struct AlreadyMutBorrowed { } #[derive(Diagnostic)] -#[diag(mir_build_moved_while_borrowed)] +#[diag("cannot move out of value because it is borrowed")] pub(crate) struct MovedWhileBorrowed { #[primary_span] pub(crate) span: Span, @@ -893,19 +1069,19 @@ pub(crate) struct MovedWhileBorrowed { #[derive(Subdiagnostic)] pub(crate) enum Conflict { - #[label(mir_build_mutable_borrow)] + #[label("value is mutably borrowed by `{$name}` here")] Mut { #[primary_span] span: Span, name: Symbol, }, - #[label(mir_build_borrow)] + #[label("value is borrowed by `{$name}` here")] Ref { #[primary_span] span: Span, name: Symbol, }, - #[label(mir_build_moved)] + #[label("value is moved into `{$name}` here")] Moved { #[primary_span] span: Span, @@ -914,50 +1090,56 @@ pub(crate) enum Conflict { } #[derive(Diagnostic)] -#[diag(mir_build_union_pattern)] +#[diag("cannot use unions in constant patterns")] pub(crate) struct UnionPattern { #[primary_span] - #[label] + #[label("can't use a `union` here")] pub(crate) span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_type_not_structural)] +#[diag("constant of non-structural type `{$ty}` in a pattern")] pub(crate) struct TypeNotStructural<'tcx> { #[primary_span] - #[label] + #[label("constant of non-structural type")] pub(crate) span: Span, - #[label(mir_build_type_not_structural_def)] + #[label("`{$ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns")] pub(crate) ty_def_span: Span, pub(crate) ty: Ty<'tcx>, - #[note(mir_build_type_not_structural_tip)] + #[note( + "the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details" + )] pub(crate) manual_partialeq_impl_span: Option, - #[note(mir_build_type_not_structural_more_info)] + #[note( + "see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details" + )] pub(crate) manual_partialeq_impl_note: bool, } #[derive(Diagnostic)] -#[diag(mir_build_non_partial_eq_match)] -#[note(mir_build_type_not_structural_more_info)] +#[diag("constant of non-structural type `{$ty}` in a pattern")] +#[note( + "see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details" +)] pub(crate) struct TypeNotPartialEq<'tcx> { #[primary_span] - #[label] + #[label("constant of non-structural type")] pub(crate) span: Span, pub(crate) ty: Ty<'tcx>, } #[derive(Diagnostic)] -#[diag(mir_build_invalid_pattern)] +#[diag("{$prefix} `{$non_sm_ty}` cannot be used in patterns")] pub(crate) struct InvalidPattern<'tcx> { #[primary_span] - #[label] + #[label("{$prefix} can't be used in patterns")] pub(crate) span: Span, pub(crate) non_sm_ty: Ty<'tcx>, pub(crate) prefix: String, } #[derive(Diagnostic)] -#[diag(mir_build_unsized_pattern)] +#[diag("cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns")] pub(crate) struct UnsizedPattern<'tcx> { #[primary_span] pub(crate) span: Span, @@ -965,36 +1147,38 @@ pub(crate) struct UnsizedPattern<'tcx> { } #[derive(Diagnostic)] -#[diag(mir_build_nan_pattern)] -#[note] -#[help] +#[diag("cannot use NaN in patterns")] +#[note("NaNs compare inequal to everything, even themselves, so this pattern would never match")] +#[help("try using the `is_nan` method instead")] pub(crate) struct NaNPattern { #[primary_span] - #[label] + #[label("evaluates to `NaN`, which is not allowed in patterns")] pub(crate) span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_pointer_pattern)] -#[note] +#[diag( + "function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon" +)] +#[note("see https://github.com/rust-lang/rust/issues/70861 for details")] pub(crate) struct PointerPattern { #[primary_span] - #[label] + #[label("can't be used in patterns")] pub(crate) span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_non_empty_never_pattern)] -#[note] +#[diag("mismatched types")] +#[note("the matched value is of type `{$ty}`")] pub(crate) struct NonEmptyNeverPattern<'tcx> { #[primary_span] - #[label] + #[label("a never pattern must be used on an uninhabited type")] pub(crate) span: Span, pub(crate) ty: Ty<'tcx>, } #[derive(Diagnostic)] -#[diag(mir_build_pattern_not_covered, code = E0005)] +#[diag("refutable pattern in {$origin}", code = E0005)] pub(crate) struct PatternNotCovered<'s, 'tcx> { #[primary_span] pub(crate) span: Span, @@ -1009,10 +1193,12 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { pub(crate) interpreted_as_const_sugg: Option, #[subdiagnostic] pub(crate) adt_defined_here: Option>, - #[note(mir_build_privately_uninhabited)] + #[note( + "pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future" + )] pub(crate) witness_1_is_privately_uninhabited: bool, pub(crate) witness_1: String, - #[note(mir_build_pattern_ty)] + #[note("the matched value is of type `{$pattern_ty}`")] pub(crate) _p: (), pub(crate) pattern_ty: Ty<'tcx>, #[subdiagnostic] @@ -1022,12 +1208,16 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { } #[derive(Subdiagnostic)] -#[note(mir_build_inform_irrefutable)] -#[note(mir_build_more_information)] +#[note( + "`let` bindings require an \"irrefutable pattern\", like a `struct` or an `enum` with only one variant" +)] +#[note("for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html")] pub(crate) struct Inform; #[derive(Subdiagnostic)] -#[label(mir_build_confused)] +#[label( + "missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable" +)] pub(crate) struct InterpretedAsConst { #[primary_span] pub(crate) span: Span, @@ -1050,16 +1240,16 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { let mut spans = MultiSpan::from(self.adt_def_span); for Variant { span } in self.variants { - spans.push_span_label(span, fluent::mir_build_variant_defined_here); + spans.push_span_label(span, inline_fluent!("not covered")); } - diag.span_note(spans, fluent::mir_build_adt_defined_here); + diag.span_note(spans, inline_fluent!("`{$ty}` defined here")); } } #[derive(Subdiagnostic)] #[suggestion( - mir_build_interpreted_as_const, + "introduce a variable instead", code = "{variable}_var", applicability = "maybe-incorrect", style = "verbose" @@ -1072,7 +1262,13 @@ pub(crate) struct InterpretedAsConstSugg { #[derive(Subdiagnostic)] pub(crate) enum SuggestLet { - #[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")] + #[multipart_suggestion( + "you might want to use `if let` to ignore the {$count -> +[one] variant that isn't +*[other] variants that aren't +} matched", + applicability = "has-placeholders" + )] If { #[suggestion_part(code = "if ")] start_span: Span, @@ -1081,7 +1277,10 @@ pub(crate) enum SuggestLet { count: usize, }, #[suggestion( - mir_build_suggest_let_else, + "you might want to use `let...else` to handle the {$count -> +[one] variant that isn't +*[other] variants that aren't +} matched", code = " else {{ todo!() }}", applicability = "has-placeholders" )] @@ -1095,7 +1294,7 @@ pub(crate) enum SuggestLet { #[derive(Subdiagnostic)] pub(crate) enum MiscPatternSuggestion { #[suggestion( - mir_build_suggest_attempted_int_lit, + "alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits", code = "_", applicability = "maybe-incorrect" )] @@ -1106,25 +1305,25 @@ pub(crate) enum MiscPatternSuggestion { } #[derive(Diagnostic)] -#[diag(mir_build_loop_match_invalid_update)] +#[diag("invalid update of the `#[loop_match]` state")] pub(crate) struct LoopMatchInvalidUpdate { #[primary_span] pub lhs: Span, - #[label] + #[label("the assignment must update this variable")] pub scrutinee: Span, } #[derive(Diagnostic)] -#[diag(mir_build_loop_match_invalid_match)] -#[note] +#[diag("invalid match on `#[loop_match]` state")] +#[note("a local variable must be the scrutinee within a `#[loop_match]`")] pub(crate) struct LoopMatchInvalidMatch { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_loop_match_unsupported_type)] -#[note] +#[diag("this `#[loop_match]` state value has type `{$ty}`, which is not supported")] +#[note("only integers, floats, bool, char, and enums without fields are supported")] pub(crate) struct LoopMatchUnsupportedType<'tcx> { #[primary_span] pub span: Span, @@ -1132,36 +1331,36 @@ pub(crate) struct LoopMatchUnsupportedType<'tcx> { } #[derive(Diagnostic)] -#[diag(mir_build_loop_match_bad_statements)] +#[diag("statements are not allowed in this position within a `#[loop_match]`")] pub(crate) struct LoopMatchBadStatements { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_loop_match_bad_rhs)] +#[diag("this expression must be a single `match` wrapped in a labeled block")] pub(crate) struct LoopMatchBadRhs { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_loop_match_missing_assignment)] +#[diag("expected a single assignment expression")] pub(crate) struct LoopMatchMissingAssignment { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_loop_match_arm_with_guard)] +#[diag("match arms that are part of a `#[loop_match]` cannot have guards")] pub(crate) struct LoopMatchArmWithGuard { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_const_continue_not_const)] -#[help] +#[diag("could not determine the target branch for this `#[const_continue]`")] +#[help("try extracting the expression into a `const` item")] pub(crate) struct ConstContinueNotMonomorphicConst { #[primary_span] pub span: Span, @@ -1172,19 +1371,19 @@ pub(crate) struct ConstContinueNotMonomorphicConst { #[derive(Subdiagnostic)] pub(crate) enum ConstContinueNotMonomorphicConstReason { - #[label(mir_build_const_continue_not_const_constant_parameter)] + #[label("constant parameters may use generics, and are not evaluated early enough")] ConstantParameter { #[primary_span] span: Span, }, - #[label(mir_build_const_continue_not_const_const_block)] + #[label("`const` blocks may use generics, and are not evaluated early enough")] ConstBlock { #[primary_span] span: Span, }, - #[label(mir_build_const_continue_not_const_const_other)] + #[label("this value must be a literal or a monomorphic const")] Other { #[primary_span] span: Span, @@ -1192,22 +1391,22 @@ pub(crate) enum ConstContinueNotMonomorphicConstReason { } #[derive(Diagnostic)] -#[diag(mir_build_const_continue_bad_const)] +#[diag("could not determine the target branch for this `#[const_continue]`")] pub(crate) struct ConstContinueBadConst { #[primary_span] - #[label] + #[label("this value is too generic")] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_const_continue_missing_label_or_value)] +#[diag("a `#[const_continue]` must break to a label with a value")] pub(crate) struct ConstContinueMissingLabelOrValue { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_build_const_continue_unknown_jump_target)] +#[diag("the target of this `#[const_continue]` is not statically known")] pub(crate) struct ConstContinueUnknownJumpTarget { #[primary_span] pub span: Span, diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 5c5d979306bfa..cc8035e2b0acf 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -18,8 +18,6 @@ pub mod thir; use rustc_middle::util::Providers; -rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - pub fn provide(providers: &mut Providers) { providers.queries.check_match = thir::pattern::check_match; providers.queries.lit_to_const = thir::constant::lit_to_const; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 290d4ab2bfbb0..4eb7b3671e9c4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -3,7 +3,9 @@ use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::codes::*; -use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err}; +use rustc_errors::{ + Applicability, ErrorGuaranteed, MultiSpan, inline_fluent, struct_span_code_err, +}; use rustc_hir::def::*; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource}; @@ -29,7 +31,6 @@ use rustc_trait_selection::infer::InferCtxtExt; use tracing::instrument; use crate::errors::*; -use crate::fluent_generated as fluent; pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { let typeck_results = tcx.typeck(def_id); @@ -988,20 +989,20 @@ fn report_unreachable_pattern<'p, 'tcx>( for p in iter.by_ref().take(CAP_COVERED_BY_MANY) { multispan.push_span_label( p.data().span, - fluent::mir_build_unreachable_matches_same_values, + inline_fluent!("matches some of the same values"), ); } let remain = iter.count(); if remain == 0 { multispan.push_span_label( pat_span, - fluent::mir_build_unreachable_making_this_unreachable, + inline_fluent!("collectively making this unreachable"), ); } else { lint.covered_by_many_n_more_count = remain; multispan.push_span_label( pat_span, - fluent::mir_build_unreachable_making_this_unreachable_n_more, + inline_fluent!("...and {$covered_by_many_n_more_count} other patterns collectively make this unreachable"), ); } lint.covered_by_many = Some(multispan); 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 0a0e0d06061eb..6f0f6478f2d74 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 @@ -3,7 +3,7 @@ use core::ops::ControlFlow; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_apfloat::Float; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::Diag; +use rustc_errors::{Diag, inline_fluent}; use rustc_hir as hir; use rustc_hir::attrs::AttributeKind; use rustc_hir::find_attr; @@ -82,10 +82,7 @@ impl<'tcx> ConstToPat<'tcx> { err.span_label(self.tcx.def_span(self.tcx.local_parent(def_id)), ""); } if let hir::def::DefKind::Const | hir::def::DefKind::AssocConst = def_kind { - err.span_label( - self.tcx.def_span(uv.def), - crate::fluent_generated::mir_build_const_defined_here, - ); + err.span_label(self.tcx.def_span(uv.def), inline_fluent!("constant defined here")); } } Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()), extra: None }) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 84fe6770be583..11cde35fab17f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1627,16 +1627,8 @@ impl<'a> Parser<'a> { let first_expr = self.parse_expr()?; if self.eat(exp!(Semi)) { // Repeating array syntax: `[ 0; 512 ]` - let count = if self.eat_keyword(exp!(Const)) { - // While we could just disambiguate `Direct` from `AnonConst` by - // treating all const block exprs as `AnonConst`, that would - // complicate the DefCollector and likely all other visitors. - // So we strip the const blockiness and just store it as a block - // in the AST with the extra disambiguator on the AnonConst - self.parse_mgca_const_block(false)? - } else { - self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))? - }; + let count = + self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?; self.expect(close)?; ExprKind::Repeat(first_expr, count) } else if self.eat(exp!(Comma)) { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 0ff0b66229366..a6b956b09bc16 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -33,9 +33,9 @@ use rustc_ast::tokenstream::{ }; use rustc_ast::util::case::Case; use rustc_ast::{ - self as ast, AnonConst, AttrArgs, AttrId, BlockCheckMode, ByRef, Const, CoroutineKind, - DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, MgcaDisambiguation, - Mutability, Recovered, Safety, StrLit, Visibility, VisibilityKind, + self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID, + DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, MgcaDisambiguation, Mutability, + Recovered, Safety, StrLit, Visibility, VisibilityKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::debug_assert_matches; @@ -1269,19 +1269,6 @@ impl<'a> Parser<'a> { } } - fn parse_mgca_const_block(&mut self, gate_syntax: bool) -> PResult<'a, AnonConst> { - let kw_span = self.prev_token.span; - let value = self.parse_expr_block(None, kw_span, BlockCheckMode::Default)?; - if gate_syntax { - self.psess.gated_spans.gate(sym::min_generic_const_args, kw_span.to(value.span)); - } - Ok(AnonConst { - id: ast::DUMMY_NODE_ID, - value, - mgca_disambiguation: MgcaDisambiguation::AnonConst, - }) - } - /// Parses inline const expressions. fn parse_const_block(&mut self, span: Span) -> PResult<'a, Box> { self.expect_keyword(exp!(Const))?; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index dd190707c42b4..9196d8d156d8e 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -847,6 +847,7 @@ impl<'a> Parser<'a> { /// - A literal. /// - A numeric literal prefixed by `-`. /// - A single-segment path. + /// - A const block (under mGCA) pub(super) fn expr_is_valid_const_arg(&self, expr: &Box) -> bool { match &expr.kind { ast::ExprKind::Block(_, _) @@ -863,6 +864,10 @@ impl<'a> Parser<'a> { { true } + ast::ExprKind::ConstBlock(_) => { + self.psess.gated_spans.gate(sym::min_generic_const_args, expr.span); + true + } _ => false, } } @@ -874,14 +879,6 @@ impl<'a> Parser<'a> { let (value, mgca_disambiguation) = if self.token.kind == token::OpenBrace { let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?; (value, MgcaDisambiguation::Direct) - } else if self.eat_keyword(exp!(Const)) { - // While we could just disambiguate `Direct` from `AnonConst` by - // treating all const block exprs as `AnonConst`, that would - // complicate the DefCollector and likely all other visitors. - // So we strip the const blockiness and just store it as a block - // in the AST with the extra disambiguator on the AnonConst - let value = self.parse_mgca_const_block(true)?; - (value.value, MgcaDisambiguation::AnonConst) } else { self.parse_unambiguous_unbraced_const_arg()? }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 380b6a2148461..6ff165eb22b71 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -658,16 +658,8 @@ impl<'a> Parser<'a> { }; let ty = if self.eat(exp!(Semi)) { - let mut length = if self.eat_keyword(exp!(Const)) { - // While we could just disambiguate `Direct` from `AnonConst` by - // treating all const block exprs as `AnonConst`, that would - // complicate the DefCollector and likely all other visitors. - // So we strip the const blockiness and just store it as a block - // in the AST with the extra disambiguator on the AnonConst - self.parse_mgca_const_block(false)? - } else { - self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))? - }; + let mut length = + self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?; if let Err(e) = self.expect(exp!(CloseBracket)) { // Try to recover from `X` when `X::` works diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index a918ae929d2e0..325f54d78a505 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -953,6 +953,13 @@ impl Step for Rustc { cargo.rustdocflag("--extern-html-root-url"); cargo.rustdocflag("ena=https://docs.rs/ena/latest/"); + // Point std library crate links to local docs for offline usage. + for krate in STD_PUBLIC_CRATES { + cargo.rustdocflag("--extern-html-root-url"); + cargo.rustdocflag(&format!("{krate}=../")); + } + cargo.rustdocflag("--extern-html-root-takes-precedence"); + let mut to_open = None; let out_dir = builder.stage_out(build_compiler, Mode::Rustc).join(target).join("doc"); diff --git a/src/tools/rustfmt/tests/source/issue-6788.rs b/src/tools/rustfmt/tests/source/issue-6788.rs new file mode 100644 index 0000000000000..0e63ab53a1ac9 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-6788.rs @@ -0,0 +1,7 @@ +fn foo() { + let a = [(); const { let x = 1; x }]; +} + +fn foo() { + let x = [(); const { 1 }]; +} diff --git a/src/tools/rustfmt/tests/target/issue-6788.rs b/src/tools/rustfmt/tests/target/issue-6788.rs new file mode 100644 index 0000000000000..c559438b2d52b --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-6788.rs @@ -0,0 +1,10 @@ +fn foo() { + let a = [(); const { + let x = 1; + x + }]; +} + +fn foo() { + let x = [(); const { 1 }]; +} diff --git a/tests/ui/check-cfg/cfg-select.rs b/tests/ui/check-cfg/cfg-select.rs index 39703489818d8..ffa5e40bff085 100644 --- a/tests/ui/check-cfg/cfg-select.rs +++ b/tests/ui/check-cfg/cfg-select.rs @@ -4,7 +4,7 @@ #![crate_type = "lib"] cfg_select! { - true => {} + false => {} invalid_cfg1 => {} //~^ WARN unexpected `cfg` condition name _ => {} @@ -13,6 +13,6 @@ cfg_select! { cfg_select! { invalid_cfg2 => {} //~^ WARN unexpected `cfg` condition name - true => {} + false => {} _ => {} } diff --git a/tests/ui/consts/const-try-feature-gate.stderr b/tests/ui/consts/const-try-feature-gate.stderr index 62a4a5fba4ffb..eb5728aaaa78e 100644 --- a/tests/ui/consts/const-try-feature-gate.stderr +++ b/tests/ui/consts/const-try-feature-gate.stderr @@ -30,6 +30,7 @@ LL | Some(())?; = note: see issue #143874 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `FromResidual` is not yet stable as a const trait --> $DIR/const-try-feature-gate.rs:4:5 diff --git a/tests/ui/feature-gates/feature-gate-cfg-select.rs b/tests/ui/feature-gates/feature-gate-cfg-select.rs new file mode 100644 index 0000000000000..0963ed0015082 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-select.rs @@ -0,0 +1,11 @@ +#![warn(unreachable_cfg_select_predicates)] +//~^ WARN unknown lint: `unreachable_cfg_select_predicates` + +cfg_select! { + //~^ ERROR use of unstable library feature `cfg_select` + _ => {} + // With the feature enabled, this branch would trip the unreachable_cfg_select_predicate lint. + true => {} +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg-select.stderr b/tests/ui/feature-gates/feature-gate-cfg-select.stderr new file mode 100644 index 0000000000000..0fdce49751645 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-select.stderr @@ -0,0 +1,25 @@ +error[E0658]: use of unstable library feature `cfg_select` + --> $DIR/feature-gate-cfg-select.rs:4:1 + | +LL | cfg_select! { + | ^^^^^^^^^^ + | + = note: see issue #115585 for more information + = help: add `#![feature(cfg_select)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +warning: unknown lint: `unreachable_cfg_select_predicates` + --> $DIR/feature-gate-cfg-select.rs:1:9 + | +LL | #![warn(unreachable_cfg_select_predicates)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `unreachable_cfg_select_predicates` lint is unstable + = note: see issue #115585 for more information + = help: add `#![feature(cfg_select)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: `#[warn(unknown_lints)]` on by default + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs index 2369158ba82a2..09d2c116a86d5 100644 --- a/tests/ui/macros/cfg_select.rs +++ b/tests/ui/macros/cfg_select.rs @@ -1,5 +1,6 @@ #![feature(cfg_select)] #![crate_type = "lib"] +#![warn(unreachable_cfg_select_predicates)] // Unused warnings are disabled by default in UI tests. fn print() { println!(cfg_select! { @@ -23,40 +24,40 @@ fn arm_rhs_expr_1() -> i32 { fn arm_rhs_expr_2() -> i32 { cfg_select! { - true => 1, - false => 2 + false => 2, + true => 1 } } fn arm_rhs_expr_3() -> i32 { cfg_select! { - true => 1, - false => 2, - true => { 42 } - false => -1 as i32, - true => 2 + 2, - false => "", - true => if true { 42 } else { 84 } - false => if true { 42 } else { 84 }, - true => return 42, - false => loop {} - true => (1, 2), - false => (1, 2,), - true => todo!(), - false => println!("hello"), + any(true) => 1, + any(false) => 2, + any(true) => { 42 } + any(false) => -1 as i32, + any(true) => 2 + 2, + any(false) => "", + any(true) => if true { 42 } else { 84 } + any(false) => if true { 42 } else { 84 }, + any(true) => return 42, + any(false) => loop {} + any(true) => (1, 2), + any(false) => (1, 2,), + any(true) => todo!(), + any(false) => println!("hello"), } } fn expand_to_statements() -> i32 { cfg_select! { - true => { - let a = 1; - a + 1 - } false => { let b = 2; b + 1 } + true => { + let a = 1; + a + 1 + } } } @@ -76,7 +77,7 @@ fn expand_to_pattern(x: Option) -> bool { } cfg_select! { - true => { + false => { fn foo() {} } _ => { @@ -88,7 +89,7 @@ struct S; impl S { cfg_select! { - true => { + false => { fn foo() {} } _ => { @@ -99,7 +100,7 @@ impl S { trait T { cfg_select! { - true => { + false => { fn a(); } _ => { @@ -110,7 +111,7 @@ trait T { impl T for S { cfg_select! { - true => { + false => { fn a() {} } _ => { @@ -121,7 +122,7 @@ impl T for S { extern "C" { cfg_select! { - true => { + false => { fn puts(s: *const i8) -> i32; } _ => { @@ -133,7 +134,26 @@ extern "C" { cfg_select! { _ => {} true => {} - //~^ WARN unreachable predicate + //~^ WARN unreachable configuration predicate +} + +cfg_select! { + true => {} + _ => {} + //~^ WARN unreachable configuration predicate +} + +cfg_select! { + unix => {} + not(unix) => {} + _ => {} + //~^ WARN unreachable configuration predicate +} + +cfg_select! { + unix => {} + unix => {} + //~^ WARN unreachable configuration predicate } cfg_select! { diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index ffd8540425ab0..be238e0a65e51 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -1,13 +1,5 @@ -warning: unreachable predicate - --> $DIR/cfg_select.rs:135:5 - | -LL | _ => {} - | - always matches -LL | true => {} - | ^^^^ this predicate is never reached - error: none of the predicates in this `cfg_select` evaluated to true - --> $DIR/cfg_select.rs:139:1 + --> $DIR/cfg_select.rs:159:1 | LL | / cfg_select! { LL | | @@ -16,55 +8,89 @@ LL | | } | |_^ error: none of the predicates in this `cfg_select` evaluated to true - --> $DIR/cfg_select.rs:144:1 + --> $DIR/cfg_select.rs:164:1 | LL | cfg_select! {} | ^^^^^^^^^^^^^^ error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>` - --> $DIR/cfg_select.rs:148:5 + --> $DIR/cfg_select.rs:168:5 | LL | => {} | ^^ error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression - --> $DIR/cfg_select.rs:153:5 + --> $DIR/cfg_select.rs:173:5 | LL | () => {} | ^^ expressions are not allowed here error[E0539]: malformed `cfg_select` macro input - --> $DIR/cfg_select.rs:158:5 + --> $DIR/cfg_select.rs:178:5 | LL | "str" => {} | ^^^^^ expected a valid identifier here error[E0539]: malformed `cfg_select` macro input - --> $DIR/cfg_select.rs:163:5 + --> $DIR/cfg_select.rs:183:5 | LL | a::b => {} | ^^^^ expected a valid identifier here error[E0537]: invalid predicate `a` - --> $DIR/cfg_select.rs:168:5 + --> $DIR/cfg_select.rs:188:5 | LL | a() => {} | ^^^ error: expected one of `(`, `::`, `=>`, or `=`, found `+` - --> $DIR/cfg_select.rs:173:7 + --> $DIR/cfg_select.rs:193:7 | LL | a + 1 => {} | ^ expected one of `(`, `::`, `=>`, or `=` error: expected one of `(`, `::`, `=>`, or `=`, found `!` - --> $DIR/cfg_select.rs:179:8 + --> $DIR/cfg_select.rs:199:8 | LL | cfg!() => {} | ^ expected one of `(`, `::`, `=>`, or `=` +warning: unreachable configuration predicate + --> $DIR/cfg_select.rs:136:5 + | +LL | _ => {} + | - always matches +LL | true => {} + | ^^^^ this configuration predicate is never reached + | +note: the lint level is defined here + --> $DIR/cfg_select.rs:3:9 + | +LL | #![warn(unreachable_cfg_select_predicates)] // Unused warnings are disabled by default in UI tests. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unreachable configuration predicate + --> $DIR/cfg_select.rs:142:5 + | +LL | true => {} + | ---- always matches +LL | _ => {} + | ^ this configuration predicate is never reached + +warning: unreachable configuration predicate + --> $DIR/cfg_select.rs:149:5 + | +LL | _ => {} + | ^ this configuration predicate is never reached + +warning: unreachable configuration predicate + --> $DIR/cfg_select.rs:155:5 + | +LL | unix => {} + | ^^^^ this configuration predicate is never reached + warning: unexpected `cfg` condition name: `a` - --> $DIR/cfg_select.rs:173:5 + --> $DIR/cfg_select.rs:193:5 | LL | a + 1 => {} | ^ help: found config with similar value: `target_feature = "a"` @@ -75,7 +101,7 @@ LL | a + 1 => {} = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition name: `cfg` - --> $DIR/cfg_select.rs:179:5 + --> $DIR/cfg_select.rs:199:5 | LL | cfg!() => {} | ^^^ @@ -83,7 +109,7 @@ LL | cfg!() => {} = help: to expect this configuration use `--check-cfg=cfg(cfg)` = note: see for more information about checking conditional configuration -error: aborting due to 9 previous errors; 3 warnings emitted +error: aborting due to 9 previous errors; 6 warnings emitted Some errors have detailed explanations: E0537, E0539. For more information about an error, try `rustc --explain E0537`.