diff options
Diffstat (limited to 'compiler')
76 files changed, 2643 insertions, 1191 deletions
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 6a02a3b56f6..69a78d165ef 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -199,7 +199,9 @@ impl LitKind { let symbol = if value { kw::True } else { kw::False }; (token::Bool, symbol, None) } - LitKind::Err => unreachable!(), + // This only shows up in places like `-Zunpretty=hir` output, so we + // don't bother to produce something useful. + LitKind::Err => (token::Err, Symbol::intern("<bad-literal>"), None), }; token::Lit::new(kind, symbol, suffix) diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 39ba62ef2ff..474aff2e2aa 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -15,6 +15,7 @@ rustc_target = { path = "../rustc_target" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } rustc_middle = { path = "../rustc_middle" } +rustc_macros = { path = "../rustc_macros" } rustc_query_system = { path = "../rustc_query_system" } rustc_span = { path = "../rustc_span" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 4166b4fc2e5..0dba9da63da 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -1,11 +1,17 @@ use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt}; +use super::errors::{ + AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported, + InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst, + InvalidAsmTemplateModifierRegClass, InvalidAsmTemplateModifierRegClassSub, + InvalidAsmTemplateModifierSym, InvalidRegister, InvalidRegisterClass, RegisterClassOnlyClobber, + RegisterConflict, +}; use super::LoweringContext; use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::definitions::DefPathData; @@ -26,13 +32,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let asm_arch = if self.tcx.sess.opts.actually_rustdoc { None } else { self.tcx.sess.asm_arch }; if asm_arch.is_none() && !self.tcx.sess.opts.actually_rustdoc { - struct_span_err!( - self.tcx.sess, - sp, - E0472, - "inline assembly is unsupported on this target" - ) - .emit(); + self.tcx.sess.emit_err(InlineAsmUnsupportedTarget { span: sp }); } if let Some(asm_arch) = asm_arch { // Inline assembly is currently only stable for these architectures. @@ -59,10 +59,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64)) && !self.tcx.sess.opts.actually_rustdoc { - self.tcx - .sess - .struct_span_err(sp, "the `att_syntax` option is only supported on x86") - .emit(); + self.tcx.sess.emit_err(AttSyntaxOnlyX86 { span: sp }); } if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind { feature_err( @@ -82,51 +79,37 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // If the abi was already in the list, emit an error match clobber_abis.get(&abi) { Some((prev_name, prev_sp)) => { - let mut err = self.tcx.sess.struct_span_err( - *abi_span, - &format!("`{}` ABI specified multiple times", prev_name), - ); - err.span_label(*prev_sp, "previously specified here"); - // Multiple different abi names may actually be the same ABI // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI let source_map = self.tcx.sess.source_map(); - if source_map.span_to_snippet(*prev_sp) - != source_map.span_to_snippet(*abi_span) - { - err.note("these ABIs are equivalent on the current target"); - } + let equivalent = (source_map.span_to_snippet(*prev_sp) + != source_map.span_to_snippet(*abi_span)) + .then_some(()); - err.emit(); + self.tcx.sess.emit_err(AbiSpecifiedMultipleTimes { + abi_span: *abi_span, + prev_name: *prev_name, + prev_span: *prev_sp, + equivalent, + }); } None => { - clobber_abis.insert(abi, (abi_name, *abi_span)); + clobber_abis.insert(abi, (*abi_name, *abi_span)); } } } Err(&[]) => { - self.tcx - .sess - .struct_span_err( - *abi_span, - "`clobber_abi` is not supported on this target", - ) - .emit(); + self.tcx.sess.emit_err(ClobberAbiNotSupported { abi_span: *abi_span }); } Err(supported_abis) => { - let mut err = self - .tcx - .sess - .struct_span_err(*abi_span, "invalid ABI for `clobber_abi`"); let mut abis = format!("`{}`", supported_abis[0]); for m in &supported_abis[1..] { let _ = write!(abis, ", `{}`", m); } - err.note(&format!( - "the following ABIs are supported on this target: {}", - abis - )); - err.emit(); + self.tcx.sess.emit_err(InvalidAbiClobberAbi { + abi_span: *abi_span, + supported_abis: abis, + }); } } } @@ -141,24 +124,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .iter() .map(|(op, op_sp)| { let lower_reg = |reg| match reg { - InlineAsmRegOrRegClass::Reg(s) => { + InlineAsmRegOrRegClass::Reg(reg) => { asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch { - asm::InlineAsmReg::parse(asm_arch, s).unwrap_or_else(|e| { - let msg = format!("invalid register `{}`: {}", s, e); - sess.struct_span_err(*op_sp, &msg).emit(); + asm::InlineAsmReg::parse(asm_arch, reg).unwrap_or_else(|error| { + sess.emit_err(InvalidRegister { op_span: *op_sp, reg, error }); asm::InlineAsmReg::Err }) } else { asm::InlineAsmReg::Err }) } - InlineAsmRegOrRegClass::RegClass(s) => { + InlineAsmRegOrRegClass::RegClass(reg_class) => { asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch { - asm::InlineAsmRegClass::parse(asm_arch, s).unwrap_or_else(|e| { - let msg = format!("invalid register class `{}`: {}", s, e); - sess.struct_span_err(*op_sp, &msg).emit(); - asm::InlineAsmRegClass::Err - }) + asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else( + |error| { + sess.emit_err(InvalidRegisterClass { + op_span: *op_sp, + reg_class, + error, + }); + asm::InlineAsmRegClass::Err + }, + ) } else { asm::InlineAsmRegClass::Err }) @@ -282,50 +269,39 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let valid_modifiers = class.valid_modifiers(asm_arch.unwrap()); if !valid_modifiers.contains(&modifier) { - let mut err = sess.struct_span_err( - placeholder_span, - "invalid asm template modifier for this register class", - ); - err.span_label(placeholder_span, "template modifier"); - err.span_label(op_sp, "argument"); - if !valid_modifiers.is_empty() { + let sub = if !valid_modifiers.is_empty() { let mut mods = format!("`{}`", valid_modifiers[0]); for m in &valid_modifiers[1..] { let _ = write!(mods, ", `{}`", m); } - err.note(&format!( - "the `{}` register class supports \ - the following template modifiers: {}", - class.name(), - mods - )); + InvalidAsmTemplateModifierRegClassSub::SupportModifier { + class_name: class.name(), + modifiers: mods, + } } else { - err.note(&format!( - "the `{}` register class does not support template modifiers", - class.name() - )); - } - err.emit(); + InvalidAsmTemplateModifierRegClassSub::DoesNotSupportModifier { + class_name: class.name(), + } + }; + sess.emit_err(InvalidAsmTemplateModifierRegClass { + placeholder_span, + op_span: op_sp, + sub, + }); } } hir::InlineAsmOperand::Const { .. } => { - let mut err = sess.struct_span_err( + sess.emit_err(InvalidAsmTemplateModifierConst { placeholder_span, - "asm template modifiers are not allowed for `const` arguments", - ); - err.span_label(placeholder_span, "template modifier"); - err.span_label(op_sp, "argument"); - err.emit(); + op_span: op_sp, + }); } hir::InlineAsmOperand::SymFn { .. } | hir::InlineAsmOperand::SymStatic { .. } => { - let mut err = sess.struct_span_err( + sess.emit_err(InvalidAsmTemplateModifierSym { placeholder_span, - "asm template modifiers are not allowed for `sym` arguments", - ); - err.span_label(placeholder_span, "template modifier"); - err.span_label(op_sp, "argument"); - err.emit(); + op_span: op_sp, + }); } } } @@ -346,12 +322,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // require that the operand name an explicit register, not a // register class. if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() { - let msg = format!( - "register class `{}` can only be used as a clobber, \ - not as an input or output", - reg_class.name() - ); - sess.struct_span_err(op_sp, &msg).emit(); + sess.emit_err(RegisterClassOnlyClobber { + op_span: op_sp, + reg_class_name: reg_class.name(), + }); continue; } @@ -391,16 +365,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { unreachable!(); }; - let msg = format!( - "register `{}` conflicts with register `{}`", - reg.name(), - reg2.name() - ); - let mut err = sess.struct_span_err(op_sp, &msg); - err.span_label(op_sp, &format!("register `{}`", reg.name())); - err.span_label(op_sp2, &format!("register `{}`", reg2.name())); - - match (op, op2) { + let in_out = match (op, op2) { ( hir::InlineAsmOperand::In { .. }, hir::InlineAsmOperand::Out { late, .. }, @@ -411,14 +376,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) => { assert!(!*late); let out_op_sp = if input { op_sp2 } else { op_sp }; - let msg = "use `lateout` instead of \ - `out` to avoid conflict"; - err.span_help(out_op_sp, msg); - } - _ => {} - } + Some(out_op_sp) + }, + _ => None, + }; - err.emit(); + sess.emit_err(RegisterConflict { + op_span1: op_sp, + op_span2: op_sp2, + reg1_name: reg.name(), + reg2_name: reg2.name(), + in_out + }); } Entry::Vacant(v) => { if r == reg { diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs new file mode 100644 index 00000000000..59f1b7180e4 --- /dev/null +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -0,0 +1,329 @@ +use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay}; +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_span::{symbol::Ident, Span, Symbol}; + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::generic_type_with_parentheses, code = "E0214")] +pub struct GenericTypeWithParentheses { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub sub: Option<UseAngleBrackets>, +} + +#[derive(Clone, Copy)] +pub struct UseAngleBrackets { + pub open_param: Span, + pub close_param: Span, +} + +impl AddSubdiagnostic for UseAngleBrackets { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + diag.multipart_suggestion( + fluent::ast_lowering::use_angle_brackets, + vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))], + Applicability::MaybeIncorrect, + ); + } +} + +#[derive(SessionDiagnostic)] +#[help] +#[diag(ast_lowering::invalid_abi, code = "E0703")] +pub struct InvalidAbi { + #[primary_span] + #[label] + pub span: Span, + pub abi: Symbol, + pub valid_abis: String, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::assoc_ty_parentheses)] +pub struct AssocTyParentheses { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: AssocTyParenthesesSub, +} + +#[derive(Clone, Copy)] +pub enum AssocTyParenthesesSub { + Empty { parentheses_span: Span }, + NotEmpty { open_param: Span, close_param: Span }, +} + +impl AddSubdiagnostic for AssocTyParenthesesSub { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + match self { + Self::Empty { parentheses_span } => diag.multipart_suggestion( + fluent::ast_lowering::remove_parentheses, + vec![(parentheses_span, String::new())], + Applicability::MaybeIncorrect, + ), + Self::NotEmpty { open_param, close_param } => diag.multipart_suggestion( + fluent::ast_lowering::use_angle_brackets, + vec![(open_param, String::from("<")), (close_param, String::from(">"))], + Applicability::MaybeIncorrect, + ), + }; + } +} + +#[derive(SessionDiagnostic)] +#[diag(ast_lowering::misplaced_impl_trait, code = "E0562")] +pub struct MisplacedImplTrait<'a> { + #[primary_span] + pub span: Span, + pub position: DiagnosticArgFromDisplay<'a>, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::rustc_box_attribute_error)] +pub struct RustcBoxAttributeError { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::underscore_expr_lhs_assign)] +pub struct UnderscoreExprLhsAssign { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::base_expression_double_dot)] +pub struct BaseExpressionDoubleDot { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::await_only_in_async_fn_and_blocks, code = "E0728")] +pub struct AwaitOnlyInAsyncFnAndBlocks { + #[primary_span] + #[label] + pub dot_await_span: Span, + #[label(ast_lowering::this_not_async)] + pub item_span: Option<Span>, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::generator_too_many_parameters, code = "E0628")] +pub struct GeneratorTooManyParameters { + #[primary_span] + pub fn_decl_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::closure_cannot_be_static, code = "E0697")] +pub struct ClosureCannotBeStatic { + #[primary_span] + pub fn_decl_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[help] +#[diag(ast_lowering::async_non_move_closure_not_supported, code = "E0708")] +pub struct AsyncNonMoveClosureNotSupported { + #[primary_span] + pub fn_decl_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::functional_record_update_destructuring_assignment)] +pub struct FunctionalRecordUpdateDestructuringAssignemnt { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::async_generators_not_supported, code = "E0727")] +pub struct AsyncGeneratorsNotSupported { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::inline_asm_unsupported_target, code = "E0472")] +pub struct InlineAsmUnsupportedTarget { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::att_syntax_only_x86)] +pub struct AttSyntaxOnlyX86 { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::abi_specified_multiple_times)] +pub struct AbiSpecifiedMultipleTimes { + #[primary_span] + pub abi_span: Span, + pub prev_name: Symbol, + #[label] + pub prev_span: Span, + #[note] + pub equivalent: Option<()>, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::clobber_abi_not_supported)] +pub struct ClobberAbiNotSupported { + #[primary_span] + pub abi_span: Span, +} + +#[derive(SessionDiagnostic)] +#[note] +#[diag(ast_lowering::invalid_abi_clobber_abi)] +pub struct InvalidAbiClobberAbi { + #[primary_span] + pub abi_span: Span, + pub supported_abis: String, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::invalid_register)] +pub struct InvalidRegister<'a> { + #[primary_span] + pub op_span: Span, + pub reg: Symbol, + pub error: &'a str, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::invalid_register_class)] +pub struct InvalidRegisterClass<'a> { + #[primary_span] + pub op_span: Span, + pub reg_class: Symbol, + pub error: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_lowering::invalid_asm_template_modifier_reg_class)] +pub struct InvalidAsmTemplateModifierRegClass { + #[primary_span] + #[label(ast_lowering::template_modifier)] + pub placeholder_span: Span, + #[label(ast_lowering::argument)] + pub op_span: Span, + #[subdiagnostic] + pub sub: InvalidAsmTemplateModifierRegClassSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum InvalidAsmTemplateModifierRegClassSub { + #[note(ast_lowering::support_modifiers)] + SupportModifier { class_name: Symbol, modifiers: String }, + #[note(ast_lowering::does_not_support_modifiers)] + DoesNotSupportModifier { class_name: Symbol }, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::invalid_asm_template_modifier_const)] +pub struct InvalidAsmTemplateModifierConst { + #[primary_span] + #[label(ast_lowering::template_modifier)] + pub placeholder_span: Span, + #[label(ast_lowering::argument)] + pub op_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::invalid_asm_template_modifier_sym)] +pub struct InvalidAsmTemplateModifierSym { + #[primary_span] + #[label(ast_lowering::template_modifier)] + pub placeholder_span: Span, + #[label(ast_lowering::argument)] + pub op_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::register_class_only_clobber)] +pub struct RegisterClassOnlyClobber { + #[primary_span] + pub op_span: Span, + pub reg_class_name: Symbol, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::register_conflict)] +pub struct RegisterConflict<'a> { + #[primary_span] + #[label(ast_lowering::register1)] + pub op_span1: Span, + #[label(ast_lowering::register2)] + pub op_span2: Span, + pub reg1_name: &'a str, + pub reg2_name: &'a str, + #[help] + pub in_out: Option<Span>, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[help] +#[diag(ast_lowering::sub_tuple_binding)] +pub struct SubTupleBinding<'a> { + #[primary_span] + #[label] + #[suggestion_verbose( + ast_lowering::sub_tuple_binding_suggestion, + code = "..", + applicability = "maybe-incorrect" + )] + pub span: Span, + pub ident: Ident, + pub ident_name: Symbol, + pub ctx: &'a str, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::extra_double_dot)] +pub struct ExtraDoubleDot<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(ast_lowering::previously_used_here)] + pub prev_span: Span, + pub ctx: &'a str, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[note] +#[diag(ast_lowering::misplaced_double_dot)] +pub struct MisplacedDoubleDot { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::misplaced_relax_trait_bound)] +pub struct MisplacedRelaxTraitBound { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::not_supported_for_lifetime_binder_async_closure)] +pub struct NotSupportedForLifetimeBinderAsyncClosure { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[diag(ast_lowering::arbitrary_expression_in_pattern)] +pub struct ArbitraryExpressionInPattern { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index bd61f4fa87a..61f8c0216f1 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,3 +1,9 @@ +use super::errors::{ + AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, + BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt, + GeneratorTooManyParameters, NotSupportedForLifetimeBinderAsyncClosure, RustcBoxAttributeError, + UnderscoreExprLhsAssign, +}; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use crate::{FnDeclKind, ImplTraitPosition}; @@ -6,7 +12,6 @@ use rustc_ast::attr; use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::definitions::DefPathData; @@ -45,13 +50,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let hir_id = self.lower_node_id(e.id); return hir::Expr { hir_id, kind, span: self.lower_span(e.span) }; } else { - self.tcx.sess - .struct_span_err( - e.span, - "#[rustc_box] requires precisely one argument \ - and no other attributes are allowed", - ) - .emit(); + self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span }); hir::ExprKind::Err } } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) { @@ -211,13 +210,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims) } ExprKind::Underscore => { - self.tcx - .sess.struct_span_err( - e.span, - "in expressions, `_` can only be used on the left-hand side of an assignment", - ) - .span_label(e.span, "`_` not allowed here") - .emit(); + self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span }); hir::ExprKind::Err } ExprKind::Path(ref qself, ref path) => { @@ -249,11 +242,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let rest = match &se.rest { StructRest::Base(e) => Some(self.lower_expr(e)), StructRest::Rest(sp) => { - self.tcx - .sess - .struct_span_err(*sp, "base expression required after `..`") - .span_label(*sp, "add a base expression here") - .emit(); + self.tcx.sess.emit_err(BaseExpressionDoubleDot { span: *sp }); Some(&*self.arena.alloc(self.expr_err(*sp))) } StructRest::None => None, @@ -662,17 +651,10 @@ impl<'hir> LoweringContext<'_, 'hir> { match self.generator_kind { Some(hir::GeneratorKind::Async(_)) => {} Some(hir::GeneratorKind::Gen) | None => { - let mut err = struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks { dot_await_span, - E0728, - "`await` is only allowed inside `async` functions and blocks" - ); - err.span_label(dot_await_span, "only allowed inside `async` functions and blocks"); - if let Some(item_sp) = self.current_item { - err.span_label(item_sp, "this is not `async`"); - } - err.emit(); + item_span: self.current_item, + }); } } let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None); @@ -892,13 +874,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match generator_kind { Some(hir::GeneratorKind::Gen) => { if decl.inputs.len() > 1 { - struct_span_err!( - self.tcx.sess, - fn_decl_span, - E0628, - "too many parameters for a generator (expected 0 or 1 parameters)" - ) - .emit(); + self.tcx.sess.emit_err(GeneratorTooManyParameters { fn_decl_span }); } Some(movability) } @@ -907,13 +883,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } None => { if movability == Movability::Static { - struct_span_err!( - self.tcx.sess, - fn_decl_span, - E0697, - "closures cannot be static" - ) - .emit(); + self.tcx.sess.emit_err(ClosureCannotBeStatic { fn_decl_span }); } None } @@ -946,10 +916,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: Span, ) -> hir::ExprKind<'hir> { if let &ClosureBinder::For { span, .. } = binder { - self.tcx.sess.span_err( - span, - "`for<...>` binders on `async` closures are not currently supported", - ); + self.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span }); } let (binder_clause, generic_params) = self.lower_closure_binder(binder); @@ -960,17 +927,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let body = self.with_new_scopes(|this| { // FIXME(cramertj): allow `async` non-`move` closures with arguments. if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() { - struct_span_err!( - this.tcx.sess, - fn_decl_span, - E0708, - "`async` non-`move` closures with parameters are not currently supported", - ) - .help( - "consider using `let` statements to manually capture \ - variables by reference before entering an `async move` closure", - ) - .emit(); + this.tcx.sess.emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span }); } // Transform `async |x: u8| -> X { ... }` into @@ -1210,20 +1167,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let fields_omitted = match &se.rest { StructRest::Base(e) => { - self.tcx - .sess - .struct_span_err( - e.span, - "functional record updates are not allowed in destructuring \ - assignments", - ) - .span_suggestion( - e.span, - "consider removing the trailing pattern", - "", - rustc_errors::Applicability::MachineApplicable, - ) - .emit(); + self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignemnt { + span: e.span, + }); true } StructRest::Rest(_) => true, @@ -1420,13 +1366,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match self.generator_kind { Some(hir::GeneratorKind::Gen) => {} Some(hir::GeneratorKind::Async(_)) => { - struct_span_err!( - self.tcx.sess, - span, - E0727, - "`async` generators are not yet supported" - ) - .emit(); + self.tcx.sess.emit_err(AsyncGeneratorsNotSupported { span }); } None => self.generator_kind = Some(hir::GeneratorKind::Gen), } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 0f1bab24f96..fd338ffc0c5 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,3 +1,4 @@ +use super::errors::{InvalidAbi, MisplacedRelaxTraitBound}; use super::ResolverAstLoweringExt; use super::{AstOwner, ImplTraitContext, ImplTraitPosition}; use super::{FnDeclKind, LoweringContext, ParamMode}; @@ -7,7 +8,6 @@ use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -1260,10 +1260,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn error_on_invalid_abi(&self, abi: StrLit) { - struct_span_err!(self.tcx.sess, abi.span, E0703, "invalid ABI: found `{}`", abi.symbol) - .span_label(abi.span, "invalid ABI") - .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) - .emit(); + self.tcx.sess.emit_err(InvalidAbi { + span: abi.span, + abi: abi.symbol, + valid_abis: abi::all_names().join(", "), + }); } fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync { @@ -1338,11 +1339,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let is_param = *is_param.get_or_insert_with(compute_is_param); if !is_param { - self.diagnostic().span_err( - bound.span(), - "`?Trait` bounds are only permitted at the \ - point where a type parameter is declared", - ); + self.tcx.sess.emit_err(MisplacedRelaxTraitBound { span: bound.span() }); } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8ab1daf23e8..becb67d1165 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -39,6 +39,8 @@ #[macro_use] extern crate tracing; +use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait}; + use rustc_ast::ptr::P; use rustc_ast::visit; use rustc_ast::{self as ast, *}; @@ -49,7 +51,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_err, Applicability, Handler, StashKey}; +use rustc_errors::{DiagnosticArgFromDisplay, Handler, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -75,6 +77,7 @@ macro_rules! arena_vec { mod asm; mod block; +mod errors; mod expr; mod index; mod item; @@ -1070,19 +1073,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn emit_bad_parenthesized_trait_in_assoc_ty(&self, data: &ParenthesizedArgs) { - let mut err = self.tcx.sess.struct_span_err( - data.span, - "parenthesized generic arguments cannot be used in associated type constraints", - ); // Suggest removing empty parentheses: "Trait()" -> "Trait" - if data.inputs.is_empty() { + let sub = if data.inputs.is_empty() { let parentheses_span = data.inputs_span.shrink_to_lo().to(data.inputs_span.shrink_to_hi()); - err.multipart_suggestion( - "remove these parentheses", - vec![(parentheses_span, String::new())], - Applicability::MaybeIncorrect, - ); + AssocTyParenthesesSub::Empty { parentheses_span } } // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>` else { @@ -1096,13 +1091,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // End of last argument to end of parameters let close_param = data.inputs.last().unwrap().span.shrink_to_hi().to(data.inputs_span.shrink_to_hi()); - err.multipart_suggestion( - &format!("use angle brackets instead",), - vec![(open_param, String::from("<")), (close_param, String::from(">"))], - Applicability::MaybeIncorrect, - ); - } - err.emit(); + AssocTyParenthesesSub::NotEmpty { open_param, close_param } + }; + self.tcx.sess.emit_err(AssocTyParentheses { span: data.span, sub }); } #[instrument(level = "debug", skip(self))] @@ -1341,14 +1332,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { path } ImplTraitContext::Disallowed(position) => { - let mut err = struct_span_err!( - self.tcx.sess, - t.span, - E0562, - "`impl Trait` only allowed in function and inherent method return types, not in {}", - position - ); - err.emit(); + self.tcx.sess.emit_err(MisplacedImplTrait { + span: t.span, + position: DiagnosticArgFromDisplay(&position), + }); hir::TyKind::Err } } diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 51f67e505f4..1efa19a3a82 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -1,3 +1,6 @@ +use super::errors::{ + ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, +}; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode}; use crate::ImplTraitPosition; @@ -5,7 +8,6 @@ use crate::ImplTraitPosition; use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_span::symbol::Ident; @@ -134,20 +136,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // This is not allowed as a sub-tuple pattern PatKind::Ident(ref _bm, ident, Some(ref sub)) if sub.is_rest() => { let sp = pat.span; - self.diagnostic() - .struct_span_err( - sp, - &format!("`{} @` is not allowed in a {}", ident.name, ctx), - ) - .span_label(sp, "this is only allowed in slice patterns") - .help("remove this and bind each tuple field independently") - .span_suggestion_verbose( - sp, - &format!("if you don't need to use the contents of {}, discard the tuple's remaining fields", ident), - "..", - Applicability::MaybeIncorrect, - ) - .emit(); + self.tcx.sess.emit_err(SubTupleBinding { + span: sp, + ident_name: ident.name, + ident, + ctx, + }); } _ => {} } @@ -296,19 +290,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern. pub(crate) fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) { - self.diagnostic() - .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx)) - .span_label(sp, &format!("can only be used once per {} pattern", ctx)) - .span_label(prev_sp, "previously used here") - .emit(); + self.tcx.sess.emit_err(ExtraDoubleDot { span: sp, prev_span: prev_sp, ctx }); } /// Used to ban the `..` pattern in places it shouldn't be semantically. fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> { - self.diagnostic() - .struct_span_err(sp, "`..` patterns are not allowed here") - .note("only allowed in tuple, tuple struct, and slice patterns") - .emit(); + self.tcx.sess.emit_err(MisplacedDoubleDot { span: sp }); // We're not in a list context so `..` can be reasonably treated // as `_` because it should always be valid and roughly matches the @@ -345,8 +332,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} _ => { - self.diagnostic() - .span_err(expr.span, "arbitrary expressions aren't allowed in patterns"); + self.tcx.sess.emit_err(ArbitraryExpressionInPattern { span: expr.span }); return self.arena.alloc(self.expr_err(expr.span)); } } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 393be3b454c..5874d08a94f 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,11 +1,11 @@ use crate::ImplTraitPosition; +use super::errors::{GenericTypeWithParentheses, UseAngleBrackets}; use super::ResolverAstLoweringExt; use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs}; use super::{ImplTraitContext, LoweringContext, ParamMode}; use rustc_ast::{self as ast, *}; -use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::GenericArg; @@ -185,7 +185,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::PathSegment<'hir> { debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,); let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args { - let msg = "parenthesized type parameters may only be used with a `Fn` trait"; match **generic_args { GenericArgs::AngleBracketed(ref data) => { self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) @@ -193,10 +192,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args { ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), ParenthesizedGenericArgs::Err => { - let mut err = struct_span_err!(self.tcx.sess, data.span, E0214, "{}", msg); - err.span_label(data.span, "only `Fn` traits may use parentheses"); // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>` - if !data.inputs.is_empty() { + let sub = if !data.inputs.is_empty() { // Start of the span to the 1st character of 1st argument let open_param = data.inputs_span.shrink_to_lo().to(data .inputs @@ -212,16 +209,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .span .shrink_to_hi() .to(data.inputs_span.shrink_to_hi()); - err.multipart_suggestion( - &format!("use angle brackets instead",), - vec![ - (open_param, String::from("<")), - (close_param, String::from(">")), - ], - Applicability::MaybeIncorrect, - ); - } - err.emit(); + + Some(UseAngleBrackets { open_param, close_param }) + } else { + None + }; + self.tcx.sess.emit_err(GenericTypeWithParentheses { span: data.span, sub }); ( self.lower_angle_bracketed_parameter_data( &data.as_angle_bracketed_args(), diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 62ccd734fe7..65edab78ce7 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -3,7 +3,6 @@ use rustc_ast as ast; use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem, NodeId}; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability}; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; use rustc_macros::HashStable_Generic; use rustc_session::lint::builtin::UNEXPECTED_CFGS; @@ -14,6 +13,8 @@ use rustc_span::hygiene::Transparency; use rustc_span::{symbol::sym, symbol::Symbol, Span}; use std::num::NonZeroU32; +use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; + pub fn is_builtin_attr(attr: &Attribute) -> bool { attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some() } @@ -25,46 +26,38 @@ enum AttrError { NonIdentFeature, MissingFeature, MultipleStabilityLevels, - UnsupportedLiteral(&'static str, /* is_bytestr */ bool), + UnsupportedLiteral(UnsupportedLiteralReason, /* is_bytestr */ bool), +} + +pub(crate) enum UnsupportedLiteralReason { + Generic, + CfgString, + DeprecatedString, + DeprecatedKvPair, } fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { - let diag = &sess.span_diagnostic; match error { AttrError::MultipleItem(item) => { - struct_span_err!(diag, span, E0538, "multiple '{}' items", item).emit(); + sess.emit_err(session_diagnostics::MultipleItem { span, item }); } AttrError::UnknownMetaItem(item, expected) => { - let expected = expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>(); - struct_span_err!(diag, span, E0541, "unknown meta item '{}'", item) - .span_label(span, format!("expected one of {}", expected.join(", "))) - .emit(); + sess.emit_err(session_diagnostics::UnknownMetaItem { span, item, expected }); } AttrError::MissingSince => { - struct_span_err!(diag, span, E0542, "missing 'since'").emit(); + sess.emit_err(session_diagnostics::MissingSince { span }); } AttrError::NonIdentFeature => { - struct_span_err!(diag, span, E0546, "'feature' is not an identifier").emit(); + sess.emit_err(session_diagnostics::NonIdentFeature { span }); } AttrError::MissingFeature => { - struct_span_err!(diag, span, E0546, "missing 'feature'").emit(); + sess.emit_err(session_diagnostics::MissingFeature { span }); } AttrError::MultipleStabilityLevels => { - struct_span_err!(diag, span, E0544, "multiple stability levels").emit(); + sess.emit_err(session_diagnostics::MultipleStabilityLevels { span }); } - AttrError::UnsupportedLiteral(msg, is_bytestr) => { - let mut err = struct_span_err!(diag, span, E0565, "{}", msg); - if is_bytestr { - if let Ok(lint_str) = sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "consider removing the prefix", - &lint_str[1..], - Applicability::MaybeIncorrect, - ); - } - } - err.emit(); + AttrError::UnsupportedLiteral(reason, is_bytestr) => { + sess.emit_err(session_diagnostics::UnsupportedLiteral { span, reason, is_bytestr }); } } } @@ -243,8 +236,6 @@ where let mut promotable = false; let mut allowed_through_unstable_modules = false; - let diagnostic = &sess.parse_sess.span_diagnostic; - 'outer: for attr in attrs_iter { if ![ sym::rustc_const_unstable, @@ -284,7 +275,7 @@ where *item = Some(v); true } else { - struct_span_err!(diagnostic, meta.span, E0539, "incorrect meta item").emit(); + sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span }); false } }; @@ -326,7 +317,7 @@ where handle_errors( &sess.parse_sess, meta.span(), - AttrError::UnsupportedLiteral("unsupported literal", false), + AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false), ); continue 'outer; }; @@ -350,39 +341,28 @@ where // is a name/value pair string literal. issue_num = match issue.unwrap().as_str() { "none" => None, - issue => { - let emit_diag = |msg: &str| { - struct_span_err!( - diagnostic, - mi.span, - E0545, - "`issue` must be a non-zero numeric string \ - or \"none\"", - ) - .span_label(mi.name_value_literal_span().unwrap(), msg) - .emit(); - }; - match issue.parse() { - Ok(0) => { - emit_diag( - "`issue` must not be \"0\", \ - use \"none\" instead", - ); - continue 'outer; - } - Ok(num) => NonZeroU32::new(num), - Err(err) => { - emit_diag(&err.to_string()); - continue 'outer; - } + issue => match issue.parse::<NonZeroU32>() { + Ok(num) => Some(num), + Err(err) => { + sess.emit_err( + session_diagnostics::InvalidIssueString { + span: mi.span, + cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind( + mi.name_value_literal_span().unwrap(), + err.kind(), + ), + }, + ); + continue 'outer; } - } + }, }; } sym::soft => { if !mi.is_word() { - let msg = "`soft` should not have any arguments"; - sess.parse_sess.span_diagnostic.span_err(mi.span, msg); + sess.emit_err(session_diagnostics::SoftNoArgs { + span: mi.span, + }); } is_soft = true; } @@ -440,8 +420,7 @@ where continue; } _ => { - struct_span_err!(diagnostic, attr.span, E0547, "missing 'issue'") - .emit(); + sess.emit_err(session_diagnostics::MissingIssue { span: attr.span }); continue; } } @@ -494,7 +473,10 @@ where handle_errors( &sess.parse_sess, lit.span, - AttrError::UnsupportedLiteral("unsupported literal", false), + AttrError::UnsupportedLiteral( + UnsupportedLiteralReason::Generic, + false, + ), ); continue 'outer; } @@ -533,14 +515,7 @@ where if let Some((ref mut stab, _)) = const_stab { stab.promotable = promotable; } else { - struct_span_err!( - diagnostic, - item_sp, - E0717, - "`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` \ - or a `rustc_const_stable` attribute" - ) - .emit(); + sess.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp }); } } @@ -555,13 +530,7 @@ where { *allowed_through_unstable_modules = true; } else { - struct_span_err!( - diagnostic, - item_sp, - E0789, - "`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute" - ) - .emit(); + sess.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp }); } } @@ -675,25 +644,18 @@ pub fn eval_condition( NestedMetaItem::Literal(Lit { span, .. }) | NestedMetaItem::MetaItem(MetaItem { span, .. }), ] => { - sess.span_diagnostic - .struct_span_err(*span, "expected a version literal") - .emit(); + sess.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); return false; } [..] => { - sess.span_diagnostic - .struct_span_err(cfg.span, "expected single version literal") - .emit(); + sess.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { + span: cfg.span, + }); return false; } }; let Some(min_version) = parse_version(min_version.as_str(), false) else { - sess.span_diagnostic - .struct_span_warn( - *span, - "unknown version literal format, assuming it refers to a future version", - ) - .emit(); + sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span }); return false; }; let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap(); @@ -711,7 +673,7 @@ pub fn eval_condition( handle_errors( sess, mi.span(), - AttrError::UnsupportedLiteral("unsupported literal", false), + AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false), ); return false; } @@ -736,13 +698,9 @@ pub fn eval_condition( }), sym::not => { if mis.len() != 1 { - struct_span_err!( - sess.span_diagnostic, - cfg.span, - E0536, - "expected 1 cfg-pattern" - ) - .emit(); + sess.emit_err(session_diagnostics::ExpectedOneCfgPattern { + span: cfg.span, + }); return false; } @@ -768,21 +726,16 @@ pub fn eval_condition( }) } _ => { - struct_span_err!( - sess.span_diagnostic, - cfg.span, - E0537, - "invalid predicate `{}`", - pprust::path_to_string(&cfg.path) - ) - .emit(); + sess.emit_err(session_diagnostics::InvalidPredicate { + span: cfg.span, + predicate: pprust::path_to_string(&cfg.path), + }); false } } } ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => { - sess.span_diagnostic - .span_err(cfg.path.span, "`cfg` predicate key must be an identifier"); + sess.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span }); true } MetaItemKind::NameValue(ref lit) if !lit.kind.is_str() => { @@ -790,7 +743,7 @@ pub fn eval_condition( sess, lit.span, AttrError::UnsupportedLiteral( - "literal in `cfg` predicate value must be a string", + UnsupportedLiteralReason::CfgString, lit.kind.is_bytestr(), ), ); @@ -834,7 +787,6 @@ where I: Iterator<Item = &'a Attribute>, { let mut depr: Option<(Deprecation, Span)> = None; - let diagnostic = &sess.parse_sess.span_diagnostic; let is_rustc = sess.features_untracked().staged_api; 'outer: for attr in attrs_iter { @@ -870,14 +822,14 @@ where &sess.parse_sess, lit.span, AttrError::UnsupportedLiteral( - "literal in `deprecated` \ - value must be a string", + UnsupportedLiteralReason::DeprecatedString, lit.kind.is_bytestr(), ), ); } else { - struct_span_err!(diagnostic, meta.span, E0551, "incorrect meta item") - .emit(); + sess.emit_err(session_diagnostics::IncorrectMetaItem2 { + span: meta.span, + }); } false @@ -899,14 +851,11 @@ where } sym::suggestion => { if !sess.features_untracked().deprecated_suggestion { - let mut diag = sess.struct_span_err( - mi.span, - "suggestions on deprecated items are unstable", - ); - if sess.is_nightly_build() { - diag.help("add `#![feature(deprecated_suggestion)]` to the crate root"); - } - diag.note("see #94785 for more details").emit(); + sess.emit_err(session_diagnostics::DeprecatedItemSuggestion { + span: mi.span, + is_nightly: sess.is_nightly_build().then_some(()), + details: (), + }); } if !get(mi, &mut suggestion) { @@ -934,7 +883,7 @@ where &sess.parse_sess, lit.span, AttrError::UnsupportedLiteral( - "item in `deprecated` must be a key/value pair", + UnsupportedLiteralReason::DeprecatedKvPair, false, ), ); @@ -952,7 +901,7 @@ where } if note.is_none() { - struct_span_err!(diagnostic, attr.span, E0543, "missing 'note'").emit(); + sess.emit_err(session_diagnostics::MissingNote { span: attr.span }); continue; } } @@ -1022,19 +971,9 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { sym::simd => Some(ReprSimd), sym::transparent => Some(ReprTransparent), sym::align => { - let mut err = struct_span_err!( - diagnostic, - item.span(), - E0589, - "invalid `repr(align)` attribute: `align` needs an argument" - ); - err.span_suggestion( - item.span(), - "supply an argument here", - "align(...)", - Applicability::HasPlaceholders, - ); - err.emit(); + sess.emit_err(session_diagnostics::InvalidReprAlignNeedArg { + span: item.span(), + }); recognised = true; None } @@ -1063,57 +1002,32 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { || int_type_of_word(name).is_some() { recognised = true; - struct_span_err!( - diagnostic, - item.span(), - E0552, - "invalid representation hint: `{}` does not take a parenthesized argument list", - name.to_ident_string(), - ).emit(); + sess.emit_err(session_diagnostics::InvalidReprHintNoParen { + span: item.span(), + name: name.to_ident_string(), + }); } if let Some(literal_error) = literal_error { - struct_span_err!( - diagnostic, - item.span(), - E0589, - "invalid `repr({})` attribute: {}", - name.to_ident_string(), - literal_error - ) - .emit(); + sess.emit_err(session_diagnostics::InvalidReprGeneric { + span: item.span(), + repr_arg: name.to_ident_string(), + error_part: literal_error, + }); } } else if let Some(meta_item) = item.meta_item() { if let MetaItemKind::NameValue(ref value) = meta_item.kind { if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) { let name = meta_item.name_or_empty().to_ident_string(); recognised = true; - let mut err = struct_span_err!( - diagnostic, - item.span(), - E0693, - "incorrect `repr({})` attribute format", - name, - ); - match value.kind { - ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { - err.span_suggestion( - item.span(), - "use parentheses instead", - format!("{}({})", name, int), - Applicability::MachineApplicable, - ); - } - ast::LitKind::Str(s, _) => { - err.span_suggestion( - item.span(), - "use parentheses instead", - format!("{}({})", name, s), - Applicability::MachineApplicable, - ); - } - _ => {} - } - err.emit(); + sess.emit_err(session_diagnostics::IncorrectReprFormatGeneric { + span: item.span(), + repr_arg: &name, + cause: IncorrectReprFormatGenericCause::from_lit_kind( + item.span(), + &value.kind, + &name, + ), + }); } else { if matches!( meta_item.name_or_empty(), @@ -1121,51 +1035,33 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { ) || int_type_of_word(meta_item.name_or_empty()).is_some() { recognised = true; - struct_span_err!( - diagnostic, - meta_item.span, - E0552, - "invalid representation hint: `{}` does not take a value", - meta_item.name_or_empty().to_ident_string(), - ) - .emit(); + sess.emit_err(session_diagnostics::InvalidReprHintNoValue { + span: meta_item.span, + name: meta_item.name_or_empty().to_ident_string(), + }); } } } else if let MetaItemKind::List(_) = meta_item.kind { if meta_item.has_name(sym::align) { recognised = true; - struct_span_err!( - diagnostic, - meta_item.span, - E0693, - "incorrect `repr(align)` attribute format: \ - `align` takes exactly one argument in parentheses" - ) - .emit(); + sess.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg { + span: meta_item.span, + }); } else if meta_item.has_name(sym::packed) { recognised = true; - struct_span_err!( - diagnostic, - meta_item.span, - E0552, - "incorrect `repr(packed)` attribute format: \ - `packed` takes exactly one parenthesized argument, \ - or no parentheses at all" - ) - .emit(); + sess.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg { + span: meta_item.span, + }); } else if matches!( meta_item.name_or_empty(), sym::C | sym::simd | sym::transparent ) || int_type_of_word(meta_item.name_or_empty()).is_some() { recognised = true; - struct_span_err!( - diagnostic, - meta_item.span, - E0552, - "invalid representation hint: `{}` does not take a parenthesized argument list", - meta_item.name_or_empty().to_ident_string(), - ).emit(); + sess.emit_err(session_diagnostics::InvalidReprHintNoParen { + span: meta_item.span, + name: meta_item.name_or_empty().to_ident_string(), + }); } } } @@ -1262,10 +1158,10 @@ fn allow_unstable<'a>( let list = attrs .filter_map(move |attr| { attr.meta_item_list().or_else(|| { - sess.diagnostic().span_err( - attr.span, - &format!("`{}` expects a list of feature names", symbol.to_ident_string()), - ); + sess.emit_err(session_diagnostics::ExpectsFeatureList { + span: attr.span, + name: symbol.to_ident_string(), + }); None }) }) @@ -1274,10 +1170,10 @@ fn allow_unstable<'a>( list.into_iter().filter_map(move |it| { let name = it.ident().map(|ident| ident.name); if name.is_none() { - sess.diagnostic().span_err( - it.span(), - &format!("`{}` expects feature names", symbol.to_ident_string()), - ); + sess.emit_err(session_diagnostics::ExpectsFeatures { + span: it.span(), + name: symbol.to_ident_string(), + }); } name }) diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index c95c1c40a34..3a43f1aad02 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -5,11 +5,14 @@ //! to this crate. #![feature(let_else)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; mod builtin; +mod session_diagnostics; pub use builtin::*; pub use IntType::*; diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs new file mode 100644 index 00000000000..a75e7409fba --- /dev/null +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -0,0 +1,397 @@ +use std::num::IntErrorKind; + +use rustc_ast as ast; +use rustc_errors::{error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_macros::SessionDiagnostic; +use rustc_session::{parse::ParseSess, SessionDiagnostic}; +use rustc_span::{Span, Symbol}; + +use crate::UnsupportedLiteralReason; + +#[derive(SessionDiagnostic)] +#[diag(attr::expected_one_cfg_pattern, code = "E0536")] +pub(crate) struct ExpectedOneCfgPattern { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::invalid_predicate, code = "E0537")] +pub(crate) struct InvalidPredicate { + #[primary_span] + pub span: Span, + + pub predicate: String, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::multiple_item, code = "E0538")] +pub(crate) struct MultipleItem { + #[primary_span] + pub span: Span, + + pub item: String, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::incorrect_meta_item, code = "E0539")] +pub(crate) struct IncorrectMetaItem { + #[primary_span] + pub span: Span, +} + +// Error code: E0541 +pub(crate) struct UnknownMetaItem<'a> { + pub span: Span, + pub item: String, + pub expected: &'a [&'a str], +} + +// Manual implementation to be able to format `expected` items correctly. +impl<'a> SessionDiagnostic<'a> for UnknownMetaItem<'_> { + fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>(); + let mut diag = sess.span_diagnostic.struct_span_err_with_code( + self.span, + fluent::attr::unknown_meta_item, + error_code!(E0541), + ); + diag.set_arg("item", self.item); + diag.set_arg("expected", expected.join(", ")); + diag.span_label(self.span, fluent::attr::label); + diag + } +} + +#[derive(SessionDiagnostic)] +#[diag(attr::missing_since, code = "E0542")] +pub(crate) struct MissingSince { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::missing_note, code = "E0543")] +pub(crate) struct MissingNote { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::multiple_stability_levels, code = "E0544")] +pub(crate) struct MultipleStabilityLevels { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::invalid_issue_string, code = "E0545")] +pub(crate) struct InvalidIssueString { + #[primary_span] + pub span: Span, + + #[subdiagnostic] + pub cause: Option<InvalidIssueStringCause>, +} + +// The error kinds of `IntErrorKind` are duplicated here in order to allow the messages to be +// translatable. +#[derive(SessionSubdiagnostic)] +pub(crate) enum InvalidIssueStringCause { + #[label(attr::must_not_be_zero)] + MustNotBeZero { + #[primary_span] + span: Span, + }, + + #[label(attr::empty)] + Empty { + #[primary_span] + span: Span, + }, + + #[label(attr::invalid_digit)] + InvalidDigit { + #[primary_span] + span: Span, + }, + + #[label(attr::pos_overflow)] + PosOverflow { + #[primary_span] + span: Span, + }, + + #[label(attr::neg_overflow)] + NegOverflow { + #[primary_span] + span: Span, + }, +} + +impl InvalidIssueStringCause { + pub fn from_int_error_kind(span: Span, kind: &IntErrorKind) -> Option<Self> { + match kind { + IntErrorKind::Empty => Some(Self::Empty { span }), + IntErrorKind::InvalidDigit => Some(Self::InvalidDigit { span }), + IntErrorKind::PosOverflow => Some(Self::PosOverflow { span }), + IntErrorKind::NegOverflow => Some(Self::NegOverflow { span }), + IntErrorKind::Zero => Some(Self::MustNotBeZero { span }), + _ => None, + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(attr::missing_feature, code = "E0546")] +pub(crate) struct MissingFeature { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::non_ident_feature, code = "E0546")] +pub(crate) struct NonIdentFeature { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::missing_issue, code = "E0547")] +pub(crate) struct MissingIssue { + #[primary_span] + pub span: Span, +} + +// FIXME: This diagnostic is identical to `IncorrectMetaItem`, barring the error code. Consider +// changing this to `IncorrectMetaItem`. See #51489. +#[derive(SessionDiagnostic)] +#[diag(attr::incorrect_meta_item, code = "E0551")] +pub(crate) struct IncorrectMetaItem2 { + #[primary_span] + pub span: Span, +} + +// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`? +// It is more similar to `IncorrectReprFormatGeneric`. +#[derive(SessionDiagnostic)] +#[diag(attr::incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")] +pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::invalid_repr_hint_no_paren, code = "E0552")] +pub(crate) struct InvalidReprHintNoParen { + #[primary_span] + pub span: Span, + + pub name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::invalid_repr_hint_no_value, code = "E0552")] +pub(crate) struct InvalidReprHintNoValue { + #[primary_span] + pub span: Span, + + pub name: String, +} + +// Error code: E0565 +pub(crate) struct UnsupportedLiteral { + pub span: Span, + pub reason: UnsupportedLiteralReason, + pub is_bytestr: bool, +} + +impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral { + fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let mut diag = sess.span_diagnostic.struct_span_err_with_code( + self.span, + match self.reason { + UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic, + UnsupportedLiteralReason::CfgString => fluent::attr::unsupported_literal_cfg_string, + UnsupportedLiteralReason::DeprecatedString => { + fluent::attr::unsupported_literal_deprecated_string + } + UnsupportedLiteralReason::DeprecatedKvPair => { + fluent::attr::unsupported_literal_deprecated_kv_pair + } + }, + error_code!(E0565), + ); + if self.is_bytestr { + if let Ok(lint_str) = sess.source_map().span_to_snippet(self.span) { + diag.span_suggestion( + self.span, + fluent::attr::unsupported_literal_suggestion, + &lint_str[1..], + Applicability::MaybeIncorrect, + ); + } + } + diag + } +} + +#[derive(SessionDiagnostic)] +#[diag(attr::invalid_repr_align_need_arg, code = "E0589")] +pub(crate) struct InvalidReprAlignNeedArg { + #[primary_span] + #[suggestion(code = "align(...)", applicability = "has-placeholders")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::invalid_repr_generic, code = "E0589")] +pub(crate) struct InvalidReprGeneric<'a> { + #[primary_span] + pub span: Span, + + pub repr_arg: String, + pub error_part: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::incorrect_repr_format_align_one_arg, code = "E0693")] +pub(crate) struct IncorrectReprFormatAlignOneArg { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::incorrect_repr_format_generic, code = "E0693")] +pub(crate) struct IncorrectReprFormatGeneric<'a> { + #[primary_span] + pub span: Span, + + pub repr_arg: &'a str, + + #[subdiagnostic] + pub cause: Option<IncorrectReprFormatGenericCause<'a>>, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum IncorrectReprFormatGenericCause<'a> { + #[suggestion(attr::suggestion, code = "{name}({int})", applicability = "machine-applicable")] + Int { + #[primary_span] + span: Span, + + #[skip_arg] + name: &'a str, + + #[skip_arg] + int: u128, + }, + + #[suggestion( + attr::suggestion, + code = "{name}({symbol})", + applicability = "machine-applicable" + )] + Symbol { + #[primary_span] + span: Span, + + #[skip_arg] + name: &'a str, + + #[skip_arg] + symbol: Symbol, + }, +} + +impl<'a> IncorrectReprFormatGenericCause<'a> { + pub fn from_lit_kind(span: Span, kind: &ast::LitKind, name: &'a str) -> Option<Self> { + match kind { + ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { + Some(Self::Int { span, name, int: *int }) + } + ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol: *symbol }), + _ => None, + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(attr::rustc_promotable_pairing, code = "E0717")] +pub(crate) struct RustcPromotablePairing { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::rustc_allowed_unstable_pairing, code = "E0789")] +pub(crate) struct RustcAllowedUnstablePairing { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::cfg_predicate_identifier)] +pub(crate) struct CfgPredicateIdentifier { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::deprecated_item_suggestion)] +pub(crate) struct DeprecatedItemSuggestion { + #[primary_span] + pub span: Span, + + #[help] + pub is_nightly: Option<()>, + + #[note] + pub details: (), +} + +#[derive(SessionDiagnostic)] +#[diag(attr::expected_single_version_literal)] +pub(crate) struct ExpectedSingleVersionLiteral { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::expected_version_literal)] +pub(crate) struct ExpectedVersionLiteral { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::expects_feature_list)] +pub(crate) struct ExpectsFeatureList { + #[primary_span] + pub span: Span, + + pub name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::expects_features)] +pub(crate) struct ExpectsFeatures { + #[primary_span] + pub span: Span, + + pub name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::soft_no_args)] +pub(crate) struct SoftNoArgs { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(attr::unknown_version_literal)] +pub(crate) struct UnknownVersionLiteral { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch index d5fa1cec061..c59a40df039 100644 --- a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch +++ b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch @@ -14,7 +14,6 @@ index 06c7be0..359e2e7 100644 @@ -75,7 +75,6 @@ #![feature(never_type)] #![feature(unwrap_infallible)] - #![feature(result_into_ok_or_err)] -#![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(once_cell)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 1802eedf193..0faf51b062b 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -168,6 +168,13 @@ pub struct CodegenResults { pub crate_info: CrateInfo, } +pub enum CodegenErrors<'a> { + WrongFileType, + EmptyVersionNumber, + EncodingVersionMismatch { version_array: String, rlink_version: u32 }, + RustcVersionMismatch { rustc_version: String, current_version: &'a str }, +} + pub fn provide(providers: &mut Providers) { crate::back::symbol_export::provide(providers); crate::base::provide(providers); @@ -212,30 +219,34 @@ impl CodegenResults { encoder.finish() } - pub fn deserialize_rlink(data: Vec<u8>) -> Result<Self, String> { + pub fn deserialize_rlink<'a>(data: Vec<u8>) -> Result<Self, CodegenErrors<'a>> { // The Decodable machinery is not used here because it panics if the input data is invalid // and because its internal representation may change. if !data.starts_with(RLINK_MAGIC) { - return Err("The input does not look like a .rlink file".to_string()); + return Err(CodegenErrors::WrongFileType); } let data = &data[RLINK_MAGIC.len()..]; if data.len() < 4 { - return Err("The input does not contain version number".to_string()); + return Err(CodegenErrors::EmptyVersionNumber); } let mut version_array: [u8; 4] = Default::default(); version_array.copy_from_slice(&data[..4]); if u32::from_be_bytes(version_array) != RLINK_VERSION { - return Err(".rlink file was produced with encoding version {version_array}, but the current version is {RLINK_VERSION}".to_string()); + return Err(CodegenErrors::EncodingVersionMismatch { + version_array: String::from_utf8_lossy(&version_array).to_string(), + rlink_version: RLINK_VERSION, + }); } let mut decoder = MemDecoder::new(&data[4..], 0); let rustc_version = decoder.read_str(); let current_version = RUSTC_VERSION.unwrap(); if rustc_version != current_version { - return Err(format!( - ".rlink file was produced by rustc version {rustc_version}, but the current version is {current_version}." - )); + return Err(CodegenErrors::RustcVersionMismatch { + rustc_version: rustc_version.to_string(), + current_version, + }); } let codegen_results = CodegenResults::decode(&mut decoder); diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 948c3349498..d9c4ae4d53f 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,16 +1,16 @@ // Not in interpret to make sure we do not use private implementation details +use crate::errors::MaxNumNodesInConstErr; +use crate::interpret::{ + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta, + Scalar, +}; use rustc_hir::Mutability; use rustc_middle::mir; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; -use crate::interpret::{ - intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta, - Scalar, -}; - mod error; mod eval_queries; mod fn_queries; @@ -72,12 +72,17 @@ pub(crate) fn eval_to_valtree<'tcx>( Ok(valtree) => Ok(Some(valtree)), Err(err) => { let did = cid.instance.def_id(); - let s = cid.display(tcx); + let global_const_id = cid.display(tcx); match err { ValTreeCreationError::NodesOverflow => { - let msg = format!("maximum number of nodes exceeded in constant {}", &s); + let msg = format!( + "maximum number of nodes exceeded in constant {}", + &global_const_id + ); let mut diag = match tcx.hir().span_if_local(did) { - Some(span) => tcx.sess.struct_span_err(span, &msg), + Some(span) => { + tcx.sess.create_err(MaxNumNodesInConstErr { span, global_const_id }) + } None => tcx.sess.struct_err(&msg), }; diag.emit(); diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 01619dee0e4..c3547cb3abd 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -87,3 +87,110 @@ pub(crate) struct TransientMutBorrowErrRaw { pub span: Span, pub kind: ConstContext, } + +#[derive(SessionDiagnostic)] +#[diag(const_eval::max_num_nodes_in_const)] +pub(crate) struct MaxNumNodesInConstErr { + #[primary_span] + pub span: Span, + pub global_const_id: String, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_fn_pointer_call)] +pub(crate) struct UnallowedFnPointerCall { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unstable_const_fn)] +pub(crate) struct UnstableConstFn { + #[primary_span] + pub span: Span, + pub def_path: String, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_mutable_refs, code = "E0764")] +pub(crate) struct UnallowedMutableRefs { + #[primary_span] + pub span: Span, + pub kind: ConstContext, + #[note(const_eval::teach_note)] + pub teach: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_mutable_refs_raw, code = "E0764")] +pub(crate) struct UnallowedMutableRefsRaw { + #[primary_span] + pub span: Span, + pub kind: ConstContext, + #[note(const_eval::teach_note)] + pub teach: Option<()>, +} +#[derive(SessionDiagnostic)] +#[diag(const_eval::non_const_fmt_macro_call, code = "E0015")] +pub(crate) struct NonConstFmtMacroCall { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::non_const_fn_call, code = "E0015")] +pub(crate) struct NonConstFnCall { + #[primary_span] + pub span: Span, + pub def_path_str: String, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_op_in_const_context)] +pub(crate) struct UnallowedOpInConstContext { + #[primary_span] + pub span: Span, + pub msg: String, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_heap_allocations, code = "E0010")] +pub(crate) struct UnallowedHeapAllocations { + #[primary_span] + #[label] + pub span: Span, + pub kind: ConstContext, + #[note(const_eval::teach_note)] + pub teach: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_inline_asm, code = "E0015")] +pub(crate) struct UnallowedInlineAsm { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::interior_mutable_data_refer, code = "E0492")] +pub(crate) struct InteriorMutableDataRefer { + #[primary_span] + #[label] + pub span: Span, + #[help] + pub opt_help: Option<()>, + pub kind: ConstContext, + #[note(const_eval::teach_note)] + pub teach: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::interior_mutability_borrow)] +pub(crate) struct InteriorMutabilityBorrow { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index c9cfc1f3f46..5fb4bf638b3 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -24,8 +24,11 @@ use rustc_trait_selection::traits::SelectionContext; use super::ConstCx; use crate::errors::{ - MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr, - TransientMutBorrowErr, TransientMutBorrowErrRaw, + InteriorMutabilityBorrow, InteriorMutableDataRefer, MutDerefErr, NonConstFmtMacroCall, + NonConstFnCall, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr, + TransientMutBorrowErr, TransientMutBorrowErrRaw, UnallowedFnPointerCall, + UnallowedHeapAllocations, UnallowedInlineAsm, UnallowedMutableRefs, UnallowedMutableRefsRaw, + UnallowedOpInConstContext, UnstableConstFn, }; use crate::util::{call_kind, CallDesugaringKind, CallKind}; @@ -97,10 +100,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - ccx.tcx.sess.struct_span_err( - span, - &format!("function pointer calls are not allowed in {}s", ccx.const_kind()), - ) + ccx.tcx.sess.create_err(UnallowedFnPointerCall { span, kind: ccx.const_kind() }) } } @@ -308,22 +308,13 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { err } _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => { - struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "cannot call non-const formatting macro in {}s", - ccx.const_kind(), - ) + ccx.tcx.sess.create_err(NonConstFmtMacroCall { span, kind: ccx.const_kind() }) } - _ => struct_span_err!( - ccx.tcx.sess, + _ => ccx.tcx.sess.create_err(NonConstFnCall { span, - E0015, - "cannot call non-const fn `{}` in {}s", - ccx.tcx.def_path_str_with_substs(callee, substs), - ccx.const_kind(), - ), + def_path_str: ccx.tcx.def_path_str_with_substs(callee, substs), + kind: ccx.const_kind(), + }), }; err.note(&format!( @@ -354,10 +345,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let FnCallUnstable(def_id, feature) = *self; - let mut err = ccx.tcx.sess.struct_span_err( - span, - &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)), - ); + let mut err = ccx + .tcx + .sess + .create_err(UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) }); if ccx.is_const_stable_const_fn() { err.help("const-stable functions can only call other const-stable functions"); @@ -392,9 +383,12 @@ impl<'tcx> NonConstOp<'tcx> for Generator { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind()); if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { - feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg) + ccx.tcx.sess.create_feature_err( + UnallowedOpInConstContext { span, msg }, + sym::const_async_blocks, + ) } else { - ccx.tcx.sess.struct_span_err(span, &msg) + ccx.tcx.sess.create_err(UnallowedOpInConstContext { span, msg }) } } } @@ -407,23 +401,11 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = struct_span_err!( - ccx.tcx.sess, + ccx.tcx.sess.create_err(UnallowedHeapAllocations { span, - E0010, - "allocations are not allowed in {}s", - ccx.const_kind() - ); - err.span_label(span, format!("allocation not allowed in {}s", ccx.const_kind())); - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "The value of statics and constants must be known at compile time, \ - and they live for the entire lifetime of a program. Creating a boxed \ - value allocates memory on the heap at runtime, and therefore cannot \ - be done at compile time.", - ); - } - err + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0010)).then_some(()), + }) } } @@ -435,13 +417,7 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "inline assembly is not allowed in {}s", - ccx.const_kind() - ) + ccx.tcx.sess.create_err(UnallowedInlineAsm { span, kind: ccx.const_kind() }) } } @@ -487,12 +463,7 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_refs_to_cell, - span, - "cannot borrow here, since the borrowed element may contain interior mutability", - ) + ccx.tcx.sess.create_feature_err(InteriorMutabilityBorrow { span }, sym::const_refs_to_cell) } } @@ -507,32 +478,22 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0492, - "{}s cannot refer to interior mutable data", - ccx.const_kind(), - ); - err.span_label( - span, - "this borrow of an interior mutable value may end up in the final value", - ); + // FIXME: Maybe a more elegant solution to this if else case if let hir::ConstContext::Static(_) = ccx.const_kind() { - err.help( - "to fix this, the value can be extracted to a separate \ - `static` item and then referenced", - ); - } - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "A constant containing interior mutable data behind a reference can allow you - to modify that data. This would make multiple uses of a constant to be able to - see different values and allow circumventing the `Send` and `Sync` requirements - for shared mutable data, which is unsound.", - ); + ccx.tcx.sess.create_err(InteriorMutableDataRefer { + span, + opt_help: Some(()), + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + }) + } else { + ccx.tcx.sess.create_err(InteriorMutableDataRefer { + span, + opt_help: None, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + }) } - err } } @@ -558,33 +519,18 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let raw = match self.0 { - hir::BorrowKind::Raw => "raw ", - hir::BorrowKind::Ref => "", - }; - - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0764, - "{}mutable references are not allowed in the final value of {}s", - raw, - ccx.const_kind(), - ); - - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "References in statics and constants may only refer \ - to immutable values.\n\n\ - Statics are shared everywhere, and if they refer to \ - mutable data one might violate memory safety since \ - holding multiple mutable references to shared data \ - is not allowed.\n\n\ - If you really want global mutable state, try using \ - static mut or a global UnsafeCell.", - ); + match self.0 { + hir::BorrowKind::Raw => ccx.tcx.sess.create_err(UnallowedMutableRefsRaw { + span, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + }), + hir::BorrowKind::Ref => ccx.tcx.sess.create_err(UnallowedMutableRefs { + span, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + }), } - err } } diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index 08d5d4f343c..4570c144833 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -19,6 +19,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_macros = { path = "../rustc_macros" } rustc_metadata = { path = "../rustc_metadata" } rustc_parse = { path = "../rustc_parse" } rustc_plugin_impl = { path = "../rustc_plugin_impl" } diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index dac8df7dc55..a193d5db691 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -9,6 +9,8 @@ #![feature(once_cell)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; @@ -16,7 +18,7 @@ extern crate tracing; pub extern crate rustc_plugin_impl as plugin; use rustc_ast as ast; -use rustc_codegen_ssa::{traits::CodegenBackend, CodegenResults}; +use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; @@ -56,6 +58,12 @@ use std::time::Instant; pub mod args; pub mod pretty; +mod session_diagnostics; + +use crate::session_diagnostics::{ + RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch, + RLinkWrongFileType, RlinkNotAFile, RlinkUnableToRead, +}; /// Exit status code used for successful compilation and help output. pub const EXIT_SUCCESS: i32 = 0; @@ -581,18 +589,35 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp sess.init_crate_types(collect_crate_types(sess, &[])); let outputs = compiler.build_output_filenames(sess, &[]); let rlink_data = fs::read(file).unwrap_or_else(|err| { - sess.fatal(&format!("failed to read rlink file: {}", err)); + sess.emit_fatal(RlinkUnableToRead { err }); }); let codegen_results = match CodegenResults::deserialize_rlink(rlink_data) { Ok(codegen) => codegen, - Err(error) => { - sess.fatal(&format!("Could not deserialize .rlink file: {error}")); + Err(err) => { + match err { + CodegenErrors::WrongFileType => sess.emit_fatal(RLinkWrongFileType), + CodegenErrors::EmptyVersionNumber => { + sess.emit_fatal(RLinkEmptyVersionNumber) + } + CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => { + sess.emit_fatal(RLinkEncodingVersionMismatch { + version_array, + rlink_version, + }) + } + CodegenErrors::RustcVersionMismatch { rustc_version, current_version } => { + sess.emit_fatal(RLinkRustcVersionMismatch { + rustc_version, + current_version, + }) + } + }; } }; let result = compiler.codegen_backend().link(sess, codegen_results, &outputs); abort_on_err(result, sess); } else { - sess.fatal("rlink must be a file") + sess.emit_fatal(RlinkNotAFile {}) } Compilation::Stop } else { diff --git a/compiler/rustc_driver/src/session_diagnostics.rs b/compiler/rustc_driver/src/session_diagnostics.rs new file mode 100644 index 00000000000..fe64d0fca9b --- /dev/null +++ b/compiler/rustc_driver/src/session_diagnostics.rs @@ -0,0 +1,33 @@ +use rustc_macros::SessionDiagnostic; + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_unable_to_read)] +pub(crate) struct RlinkUnableToRead { + pub err: std::io::Error, +} + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_wrong_file_type)] +pub(crate) struct RLinkWrongFileType; + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_empty_version_number)] +pub(crate) struct RLinkEmptyVersionNumber; + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_encoding_version_mismatch)] +pub(crate) struct RLinkEncodingVersionMismatch { + pub version_array: String, + pub rlink_version: u32, +} + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_rustc_version_mismatch)] +pub(crate) struct RLinkRustcVersionMismatch<'a> { + pub rustc_version: String, + pub current_version: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(driver::rlink_no_a_file)] +pub(crate) struct RlinkNotAFile; diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl new file mode 100644 index 00000000000..dcb1e2b0830 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl @@ -0,0 +1,131 @@ +ast_lowering_generic_type_with_parentheses = + parenthesized type parameters may only be used with a `Fn` trait + .label = only `Fn` traits may use parentheses + +ast_lowering_use_angle_brackets = use angle brackets instead + +ast_lowering_invalid_abi = + invalid ABI: found `{$abi}` + .label = invalid ABI + .help = valid ABIs: {$valid_abis} + +ast_lowering_assoc_ty_parentheses = + parenthesized generic arguments cannot be used in associated type constraints + +ast_lowering_remove_parentheses = remove these parentheses + +ast_lowering_misplaced_impl_trait = + `impl Trait` only allowed in function and inherent method return types, not in {$position} + +ast_lowering_rustc_box_attribute_error = + #[rustc_box] requires precisely one argument and no other attributes are allowed + +ast_lowering_underscore_expr_lhs_assign = + in expressions, `_` can only be used on the left-hand side of an assignment + .label = `_` not allowed here + +ast_lowering_base_expression_double_dot = + base expression required after `..` + .label = add a base expression here + +ast_lowering_await_only_in_async_fn_and_blocks = + `await` is only allowed inside `async` functions and blocks + .label = only allowed inside `async` functions and blocks + +ast_lowering_this_not_async = this is not `async` + +ast_lowering_generator_too_many_parameters = + too many parameters for a generator (expected 0 or 1 parameters) + +ast_lowering_closure_cannot_be_static = closures cannot be static + +ast_lowering_async_non_move_closure_not_supported = + `async` non-`move` closures with parameters are not currently supported + .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure + +ast_lowering_functional_record_update_destructuring_assignment = + functional record updates are not allowed in destructuring assignments + .suggestion = consider removing the trailing pattern + +ast_lowering_async_generators_not_supported = + `async` generators are not yet supported + +ast_lowering_inline_asm_unsupported_target = + inline assembly is unsupported on this target + +ast_lowering_att_syntax_only_x86 = + the `att_syntax` option is only supported on x86 + +ast_lowering_abi_specified_multiple_times = + `{$prev_name}` ABI specified multiple times + .label = previously specified here + .note = these ABIs are equivalent on the current target + +ast_lowering_clobber_abi_not_supported = + `clobber_abi` is not supported on this target + +ast_lowering_invalid_abi_clobber_abi = + invalid ABI for `clobber_abi` + .note = the following ABIs are supported on this target: {$supported_abis} + +ast_lowering_invalid_register = + invalid register `{$reg}`: {$error} + +ast_lowering_invalid_register_class = + invalid register class `{$reg_class}`: {$error} + +ast_lowering_invalid_asm_template_modifier_reg_class = + invalid asm template modifier for this register class + +ast_lowering_argument = argument + +ast_lowering_template_modifier = template modifier + +ast_lowering_support_modifiers = + the `{$class_name}` register class supports the following template modifiers: {$modifiers} + +ast_lowering_does_not_support_modifiers = + the `{$class_name}` register class does not support template modifiers + +ast_lowering_invalid_asm_template_modifier_const = + asm template modifiers are not allowed for `const` arguments + +ast_lowering_invalid_asm_template_modifier_sym = + asm template modifiers are not allowed for `sym` arguments + +ast_lowering_register_class_only_clobber = + register class `{$reg_class_name}` can only be used as a clobber, not as an input or output + +ast_lowering_register_conflict = + register `{$reg1_name}` conflicts with register `{$reg2_name}` + .help = use `lateout` instead of `out` to avoid conflict + +ast_lowering_register1 = register `{$reg1_name}` + +ast_lowering_register2 = register `{$reg2_name}` + +ast_lowering_sub_tuple_binding = + `{$ident_name} @` is not allowed in a {$ctx} + .label = this is only allowed in slice patterns + .help = remove this and bind each tuple field independently + +ast_lowering_sub_tuple_binding_suggestion = if you don't need to use the contents of {$ident}, discard the tuple's remaining fields + +ast_lowering_extra_double_dot = + `..` can only be used once per {$ctx} pattern + .label = can only be used once per {$ctx} pattern + +ast_lowering_previously_used_here = previously used here + +ast_lowering_misplaced_double_dot = + `..` patterns are not allowed here + .note = only allowed in tuple, tuple struct, and slice patterns + +ast_lowering_misplaced_relax_trait_bound = + `?Trait` bounds are only permitted at the point where a type parameter is declared + +ast_lowering_not_supported_for_lifetime_binder_async_closure = + `for<...>` binders on `async` closures are not currently supported + +ast_lowering_arbitrary_expression_in_pattern = + arbitrary expressions aren't allowed in patterns diff --git a/compiler/rustc_error_messages/locales/en-US/attr.ftl b/compiler/rustc_error_messages/locales/en-US/attr.ftl new file mode 100644 index 00000000000..a7f8c993d42 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/attr.ftl @@ -0,0 +1,107 @@ +attr_expected_one_cfg_pattern = + expected 1 cfg-pattern + +attr_invalid_predicate = + invalid predicate `{$predicate}` + +attr_multiple_item = + multiple '{$item}' items + +attr_incorrect_meta_item = + incorrect meta item + +attr_unknown_meta_item = + unknown meta item '{$item}' + .label = expected one of {$expected} + +attr_missing_since = + missing 'since' + +attr_missing_note = + missing 'note' + +attr_multiple_stability_levels = + multiple stability levels + +attr_invalid_issue_string = + `issue` must be a non-zero numeric string or "none" + .must_not_be_zero = `issue` must not be "0", use "none" instead + .empty = cannot parse integer from empty string + .invalid_digit = invalid digit found in string + .pos_overflow = number too large to fit in target type + .neg_overflow = number too small to fit in target type + +attr_missing_feature = + missing 'feature' + +attr_non_ident_feature = + 'feature' is not an identifier + +attr_missing_issue = + missing 'issue' + +attr_incorrect_repr_format_packed_one_or_zero_arg = + incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all + +attr_invalid_repr_hint_no_paren = + invalid representation hint: `{$name}` does not take a parenthesized argument list + +attr_invalid_repr_hint_no_value = + invalid representation hint: `{$name}` does not take a value + +attr_unsupported_literal_generic = + unsupported literal +attr_unsupported_literal_cfg_string = + literal in `cfg` predicate value must be a string +attr_unsupported_literal_deprecated_string = + literal in `deprecated` value must be a string +attr_unsupported_literal_deprecated_kv_pair = + item in `deprecated` must be a key/value pair +attr_unsupported_literal_suggestion = + consider removing the prefix + +attr_invalid_repr_align_need_arg = + invalid `repr(align)` attribute: `align` needs an argument + .suggestion = supply an argument here + +attr_invalid_repr_generic = + invalid `repr({$repr_arg})` attribute: {$error_part} + +attr_incorrect_repr_format_align_one_arg = + incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses + +attr_incorrect_repr_format_generic = + incorrect `repr({$repr_arg})` attribute format + .suggestion = use parentheses instead + +attr_rustc_promotable_pairing = + `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute + +attr_rustc_allowed_unstable_pairing = + `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute + +attr_cfg_predicate_identifier = + `cfg` predicate key must be an identifier + +attr_deprecated_item_suggestion = + suggestions on deprecated items are unstable + .help = add `#![feature(deprecated_suggestion)]` to the crate root + .note = see #94785 for more details + +attr_expected_single_version_literal = + expected single version literal + +attr_expected_version_literal = + expected a version literal + +attr_expects_feature_list = + `{$name}` expects a list of feature names + +attr_expects_features = + `{$name}` expects feature names + +attr_soft_no_args = + `soft` should not have any arguments + +attr_unknown_version_literal = + unknown version literal format, assuming it refers to a future version diff --git a/compiler/rustc_error_messages/locales/en-US/const_eval.ftl b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl index 341f05efefd..33bb116d6fa 100644 --- a/compiler/rustc_error_messages/locales/en-US/const_eval.ftl +++ b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl @@ -29,3 +29,55 @@ const_eval_mut_deref = const_eval_transient_mut_borrow = mutable references are not allowed in {$kind}s const_eval_transient_mut_borrow_raw = raw mutable references are not allowed in {$kind}s + +const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} + +const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {$kind}s + +const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn + +const_eval_unallowed_mutable_refs = + mutable references are not allowed in the final value of {$kind}s + .teach_note = + References in statics and constants may only refer to immutable values.\n\n + Statics are shared everywhere, and if they refer to mutable data one might violate memory + safety since holding multiple mutable references to shared data is not allowed.\n\n + If you really want global mutable state, try using static mut or a global UnsafeCell. + +const_eval_unallowed_mutable_refs_raw = + raw mutable references are not allowed in the final value of {$kind}s + .teach_note = + References in statics and constants may only refer to immutable values.\n\n + Statics are shared everywhere, and if they refer to mutable data one might violate memory + safety since holding multiple mutable references to shared data is not allowed.\n\n + If you really want global mutable state, try using static mut or a global UnsafeCell. + +const_eval_non_const_fmt_macro_call = + cannot call non-const formatting macro in {$kind}s + +const_eval_non_const_fn_call = + cannot call non-const fn `{$def_path_str}` in {$kind}s + +const_eval_unallowed_op_in_const_context = + {$msg} + +const_eval_unallowed_heap_allocations = + allocations are not allowed in {$kind}s + .label = allocation not allowed in {$kind}s + .teach_note = + The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. + +const_eval_unallowed_inline_asm = + inline assembly is not allowed in {$kind}s + +const_eval_interior_mutable_data_refer = + {$kind}s cannot refer to interior mutable data + .label = this borrow of an interior mutable value may end up in the final value + .help = to fix this, the value can be extracted to a separate `static` item and then referenced + .teach_note = + A constant containing interior mutable data behind a reference can allow you to modify that data. + This would make multiple uses of a constant to be able to see different values and allow circumventing + the `Send` and `Sync` requirements for shared mutable data, which is unsound. + +const_eval_interior_mutability_borrow = + cannot borrow here, since the borrowed element may contain interior mutability diff --git a/compiler/rustc_error_messages/locales/en-US/driver.ftl b/compiler/rustc_error_messages/locales/en-US/driver.ftl new file mode 100644 index 00000000000..73f084cf329 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/driver.ftl @@ -0,0 +1,11 @@ +driver_rlink_unable_to_read = failed to read rlink file: `{$err}` + +driver_rlink_wrong_file_type = The input does not look like a .rlink file + +driver_rlink_empty_version_number = The input does not contain version number + +driver_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}` + +driver_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}` + +driver_rlink_no_a_file = rlink must be a file diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 97317114716..27ad3e45366 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -393,3 +393,37 @@ lint_builtin_deref_nullptr = dereferencing a null pointer .label = this code causes undefined behavior when executed lint_builtin_asm_labels = avoid using named labels in inline assembly + +lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid + .label = overruled by previous forbid + +lint_default_source = `forbid` lint level is the default for {$id} + +lint_node_source = `forbid` level set here + .note = {$reason} + +lint_command_line_source = `forbid` lint level was set on command line + +lint_malformed_attribute = malformed lint attribute input + +lint_bad_attribute_argument = bad attribute argument + +lint_reason_must_be_string_literal = reason must be a string literal + +lint_reason_must_come_last = reason in lint attribute must come last + +lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}` + .help = add `#![register_tool({$tool_name})]` to the crate root + +lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ + +lint_requested_level = requested on the command line with `{$level} {$lint_name}` + +lint_check_name_unknown = unknown lint: `{$lint_name}` + .help = did you mean: `{$suggestion}` + +lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}` + +lint_check_name_warning = {$msg} + +lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name} diff --git a/compiler/rustc_error_messages/locales/en-US/mir_dataflow.ftl b/compiler/rustc_error_messages/locales/en-US/mir_dataflow.ftl new file mode 100644 index 00000000000..98854152508 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/mir_dataflow.ftl @@ -0,0 +1,29 @@ +mir_dataflow_path_must_end_in_filename = + path must end in a filename + +mir_dataflow_unknown_formatter = + unknown formatter + +mir_dataflow_duplicate_values_for = + duplicate values for `{$name}` + +mir_dataflow_requires_an_argument = + `{$name}` requires an argument + +mir_dataflow_stop_after_dataflow_ended_compilation = + stop_after_dataflow ended compilation + +mir_dataflow_peek_must_be_place_or_ref_place = + rustc_peek: argument expression must be either `place` or `&place` + +mir_dataflow_peek_must_be_not_temporary = + dataflow::sanity_check cannot feed a non-temp to rustc_peek + +mir_dataflow_peek_bit_not_set = + rustc_peek: bit not set + +mir_dataflow_peek_argument_not_a_local = + rustc_peek: argument was not a local + +mir_dataflow_peek_argument_untracked = + rustc_peek: argument untracked diff --git a/compiler/rustc_error_messages/locales/en-US/ty_utils.ftl b/compiler/rustc_error_messages/locales/en-US/ty_utils.ftl new file mode 100644 index 00000000000..1040ee1c97d --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/ty_utils.ftl @@ -0,0 +1,47 @@ +ty_utils_needs_drop_overflow = overflow while checking whether `{$query_ty}` requires drop + +ty_utils_generic_constant_too_complex = overly complex generic constant + .help = consider moving this anonymous constant into a `const` function + .maybe_supported = this operation may be supported in the future + +ty_utils_borrow_not_supported = borrowing is not supported in generic constants + +ty_utils_address_and_deref_not_supported = dereferencing or taking the address is not supported in generic constants + +ty_utils_array_not_supported = array construction is not supported in generic constants + +ty_utils_block_not_supported = blocks are not supported in generic constant + +ty_utils_never_to_any_not_supported = converting nevers to any is not supported in generic constant + +ty_utils_tuple_not_supported = tuple construction is not supported in generic constants + +ty_utils_index_not_supported = indexing is not supported in generic constant + +ty_utils_field_not_supported = field access is not supported in generic constant + +ty_utils_const_block_not_supported = const blocks are not supported in generic constant + +ty_utils_adt_not_supported = struct/enum construction is not supported in generic constants + +ty_utils_pointer_not_supported = pointer casts are not allowed in generic constants + +ty_utils_yield_not_supported = generator control flow is not allowed in generic constants + +ty_utils_loop_not_supported = loops and loop control flow are not supported in generic constants + +ty_utils_box_not_supported = allocations are not allowed in generic constants + +ty_utils_binary_not_supported = unsupported binary operation in generic constants + +ty_utils_logical_op_not_supported = unsupported operation in generic constants, short-circuiting operations would imply control flow + +ty_utils_assign_not_supported = assignment is not supported in generic constants + +ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants + +ty_utils_control_flow_not_supported = control flow is not supported in generic constants + +ty_utils_inline_asm_not_supported = assembly is not supported in generic constants + +ty_utils_operation_not_supported = unsupported operation in generic constant diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 2d001d445be..b18d1f553e4 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -32,10 +32,13 @@ pub use unic_langid::{langid, LanguageIdentifier}; // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module. fluent_messages! { + ast_lowering => "../locales/en-US/ast_lowering.ftl", ast_passes => "../locales/en-US/ast_passes.ftl", + attr => "../locales/en-US/attr.ftl", borrowck => "../locales/en-US/borrowck.ftl", builtin_macros => "../locales/en-US/builtin_macros.ftl", const_eval => "../locales/en-US/const_eval.ftl", + driver => "../locales/en-US/driver.ftl", expand => "../locales/en-US/expand.ftl", interface => "../locales/en-US/interface.ftl", lint => "../locales/en-US/lint.ftl", @@ -44,7 +47,9 @@ fluent_messages! { plugin_impl => "../locales/en-US/plugin_impl.ftl", privacy => "../locales/en-US/privacy.ftl", save_analysis => "../locales/en-US/save_analysis.ftl", + ty_utils => "../locales/en-US/ty_utils.ftl", typeck => "../locales/en-US/typeck.ftl", + mir_dataflow => "../locales/en-US/mir_dataflow.ftl", } pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index bd58021f78f..af7ef96e485 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -21,6 +21,7 @@ //! `late_lint_methods!` invocation in `lib.rs`. use crate::{ + errors::BuiltinEllpisisInclusiveRangePatterns, types::{transparent_newtype_field, CItemKind}, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, }; @@ -1760,18 +1761,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { None => format!("&(..={})", end), }; if join.edition() >= Edition::Edition2021 { - let mut err = cx.sess().struct_span_err_with_code( - pat.span, - msg, - rustc_errors::error_code!(E0783), - ); - err.span_suggestion( - pat.span, - suggestion, + cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns { + span: pat.span, + suggestion: pat.span, replace, - Applicability::MachineApplicable, - ) - .emit(); + }); } else { cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| { lint.build(msg) @@ -1787,18 +1781,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } else { let replace = "..="; if join.edition() >= Edition::Edition2021 { - let mut err = cx.sess().struct_span_err_with_code( - pat.span, - msg, - rustc_errors::error_code!(E0783), - ); - err.span_suggestion_short( - join, - suggestion, - replace, - Applicability::MachineApplicable, - ) - .emit(); + cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns { + span: pat.span, + suggestion: join, + replace: replace.to_string(), + }); } else { cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| { lint.build(msg) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 6586fe440f3..002bba4759b 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -16,12 +16,16 @@ use self::TargetLint::*; +use crate::errors::{ + CheckNameDeprecated, CheckNameUnknown, CheckNameUnknownTool, CheckNameWarning, RequestedLevel, + UnsupportedGroup, +}; use crate::levels::LintLevelsBuilder; use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; -use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err}; +use rustc_errors::add_elided_lifetime_in_path_suggestion; use rustc_errors::{ Applicability, DecorateLint, LintDiagnosticBuilder, MultiSpan, SuggestionStyle, }; @@ -39,7 +43,7 @@ use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintI use rustc_session::Session; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{BytePos, Span, DUMMY_SP}; +use rustc_span::{BytePos, Span}; use rustc_target::abi; use tracing::debug; @@ -326,68 +330,41 @@ impl LintStore { ) { let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name); if lint_name_only == crate::WARNINGS.name_lower() && matches!(level, Level::ForceWarn(_)) { - struct_span_err!( - sess, - DUMMY_SP, - E0602, - "`{}` lint group is not supported with ´--force-warn´", - crate::WARNINGS.name_lower() - ) - .emit(); + sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() }); return; } - let db = match self.check_lint_name(lint_name_only, tool_name, registered_tools) { - CheckLintNameResult::Ok(_) => None, - CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)), + let lint_name = lint_name.to_string(); + match self.check_lint_name(lint_name_only, tool_name, registered_tools) { + CheckLintNameResult::Warning(msg, _) => { + sess.emit_warning(CheckNameWarning { + msg, + sub: RequestedLevel { level, lint_name }, + }); + } CheckLintNameResult::NoLint(suggestion) => { - let mut err = - struct_span_err!(sess, DUMMY_SP, E0602, "unknown lint: `{}`", lint_name); - - if let Some(suggestion) = suggestion { - err.help(&format!("did you mean: `{}`", suggestion)); + sess.emit_err(CheckNameUnknown { + lint_name: lint_name.clone(), + suggestion, + sub: RequestedLevel { level, lint_name }, + }); + } + CheckLintNameResult::Tool(result) => { + if let Err((Some(_), new_name)) = result { + sess.emit_warning(CheckNameDeprecated { + lint_name: lint_name.clone(), + new_name, + sub: RequestedLevel { level, lint_name }, + }); } - - Some(err.forget_guarantee()) } - CheckLintNameResult::Tool(result) => match result { - Err((Some(_), new_name)) => Some(sess.struct_warn(&format!( - "lint name `{}` is deprecated \ - and does not have an effect anymore. \ - Use: {}", - lint_name, new_name - ))), - _ => None, - }, - CheckLintNameResult::NoTool => Some( - struct_span_err!( - sess, - DUMMY_SP, - E0602, - "unknown lint tool: `{}`", - tool_name.unwrap() - ) - .forget_guarantee(), - ), + CheckLintNameResult::NoTool => { + sess.emit_err(CheckNameUnknownTool { + tool_name: tool_name.unwrap(), + sub: RequestedLevel { level, lint_name }, + }); + } + _ => {} }; - - if let Some(mut db) = db { - let msg = format!( - "requested on the command line with `{} {}`", - match level { - Level::Allow => "-A", - Level::Warn => "-W", - Level::ForceWarn(_) => "--force-warn", - Level::Deny => "-D", - Level::Forbid => "-F", - Level::Expect(_) => { - unreachable!("lints with the level of `expect` should not run this code"); - } - }, - lint_name - ); - db.note(&msg); - db.emit(); - } } /// True if this symbol represents a lint group name. diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs new file mode 100644 index 00000000000..606d8bda8aa --- /dev/null +++ b/compiler/rustc_lint/src/errors.rs @@ -0,0 +1,162 @@ +use rustc_errors::{fluent, AddSubdiagnostic, ErrorGuaranteed}; +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_session::{lint::Level, parse::ParseSess, SessionDiagnostic}; +use rustc_span::{Span, Symbol}; + +#[derive(SessionDiagnostic)] +#[diag(lint::overruled_attribute, code = "E0453")] +pub struct OverruledAttribute { + #[primary_span] + pub span: Span, + #[label] + pub overruled: Span, + pub lint_level: String, + pub lint_source: Symbol, + #[subdiagnostic] + pub sub: OverruledAttributeSub, +} +// +pub enum OverruledAttributeSub { + DefaultSource { id: String }, + NodeSource { span: Span, reason: Option<Symbol> }, + CommandLineSource, +} + +impl AddSubdiagnostic for OverruledAttributeSub { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self { + OverruledAttributeSub::DefaultSource { id } => { + diag.note(fluent::lint::default_source); + diag.set_arg("id", id); + } + OverruledAttributeSub::NodeSource { span, reason } => { + diag.span_label(span, fluent::lint::node_source); + if let Some(rationale) = reason { + diag.note(rationale.as_str()); + } + } + OverruledAttributeSub::CommandLineSource => { + diag.note(fluent::lint::command_line_source); + } + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(lint::malformed_attribute, code = "E0452")] +pub struct MalformedAttribute { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: MalformedAttributeSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum MalformedAttributeSub { + #[label(lint::bad_attribute_argument)] + BadAttributeArgument(#[primary_span] Span), + #[label(lint::reason_must_be_string_literal)] + ReasonMustBeStringLiteral(#[primary_span] Span), + #[label(lint::reason_must_come_last)] + ReasonMustComeLast(#[primary_span] Span), +} + +#[derive(SessionDiagnostic)] +#[diag(lint::unknown_tool_in_scoped_lint, code = "E0710")] +pub struct UnknownToolInScopedLint { + #[primary_span] + pub span: Option<Span>, + pub tool_name: Symbol, + pub lint_name: String, + #[help] + pub is_nightly_build: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(lint::builtin_ellipsis_inclusive_range_patterns, code = "E0783")] +pub struct BuiltinEllpisisInclusiveRangePatterns { + #[primary_span] + pub span: Span, + #[suggestion_short(code = "{replace}", applicability = "machine-applicable")] + pub suggestion: Span, + pub replace: String, +} + +pub struct RequestedLevel { + pub level: Level, + pub lint_name: String, +} + +impl AddSubdiagnostic for RequestedLevel { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + diag.note(fluent::lint::requested_level); + diag.set_arg( + "level", + match self.level { + Level::Allow => "-A", + Level::Warn => "-W", + Level::ForceWarn(_) => "--force-warn", + Level::Deny => "-D", + Level::Forbid => "-F", + Level::Expect(_) => { + unreachable!("lints with the level of `expect` should not run this code"); + } + }, + ); + diag.set_arg("lint_name", self.lint_name); + } +} + +#[derive(SessionDiagnostic)] +#[diag(lint::unsupported_group, code = "E0602")] +pub struct UnsupportedGroup { + pub lint_group: String, +} + +pub struct CheckNameUnknown { + pub lint_name: String, + pub suggestion: Option<Symbol>, + pub sub: RequestedLevel, +} + +impl SessionDiagnostic<'_> for CheckNameUnknown { + fn into_diagnostic( + self, + sess: &ParseSess, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.struct_err(fluent::lint::check_name_unknown); + diag.code(rustc_errors::error_code!(E0602)); + if let Some(suggestion) = self.suggestion { + diag.help(fluent::lint::help); + diag.set_arg("suggestion", suggestion); + } + diag.set_arg("lint_name", self.lint_name); + diag.subdiagnostic(self.sub); + diag + } +} + +#[derive(SessionDiagnostic)] +#[diag(lint::check_name_unknown_tool, code = "E0602")] +pub struct CheckNameUnknownTool { + pub tool_name: Symbol, + #[subdiagnostic] + pub sub: RequestedLevel, +} + +#[derive(SessionDiagnostic)] +#[diag(lint::check_name_warning)] +pub struct CheckNameWarning { + pub msg: String, + #[subdiagnostic] + pub sub: RequestedLevel, +} + +#[derive(SessionDiagnostic)] +#[diag(lint::check_name_deprecated)] +pub struct CheckNameDeprecated { + pub lint_name: String, + pub new_name: String, + #[subdiagnostic] + pub sub: RequestedLevel, +} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 1cabb58bbeb..89409b58f88 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -3,7 +3,7 @@ use crate::late::unerased_lint_store; use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan}; +use rustc_errors::{Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::nested_filter; @@ -23,6 +23,11 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use tracing::debug; +use crate::errors::{ + MalformedAttribute, MalformedAttributeSub, OverruledAttribute, OverruledAttributeSub, + UnknownToolInScopedLint, +}; + fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap { let store = unerased_lint_store(tcx); let levels = @@ -186,16 +191,26 @@ impl<'s> LintLevelsBuilder<'s> { } }; if !fcw_warning { - let mut diag_builder = struct_span_err!( - self.sess, - src.span(), - E0453, - "{}({}) incompatible with previous forbid", - level.as_str(), - src.name(), - ); - decorate_diag(&mut diag_builder); - diag_builder.emit(); + self.sess.emit_err(OverruledAttribute { + span: src.span(), + overruled: src.span(), + lint_level: level.as_str().to_string(), + lint_source: src.name(), + sub: match old_src { + LintLevelSource::Default => { + OverruledAttributeSub::DefaultSource { id: id.to_string() } + } + LintLevelSource::Node(_, forbid_source_span, reason) => { + OverruledAttributeSub::NodeSource { + span: forbid_source_span, + reason, + } + } + LintLevelSource::CommandLine(_, _) => { + OverruledAttributeSub::CommandLineSource + } + }, + }); } else { self.struct_lint( FORBIDDEN_LINT_GROUPS, @@ -266,7 +281,6 @@ impl<'s> LintLevelsBuilder<'s> { self.cur = self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev }); let sess = self.sess; - let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input"); for (attr_index, attr) in attrs.iter().enumerate() { if attr.has_name(sym::automatically_derived) { self.current_specs_mut().insert( @@ -317,20 +331,27 @@ impl<'s> LintLevelsBuilder<'s> { } reason = Some(rationale); } else { - bad_attr(name_value.span) - .span_label(name_value.span, "reason must be a string literal") - .emit(); + sess.emit_err(MalformedAttribute { + span: name_value.span, + sub: MalformedAttributeSub::ReasonMustBeStringLiteral( + name_value.span, + ), + }); } // found reason, reslice meta list to exclude it metas.pop().unwrap(); } else { - bad_attr(item.span) - .span_label(item.span, "bad attribute argument") - .emit(); + sess.emit_err(MalformedAttribute { + span: item.span, + sub: MalformedAttributeSub::BadAttributeArgument(item.span), + }); } } ast::MetaItemKind::List(_) => { - bad_attr(item.span).span_label(item.span, "bad attribute argument").emit(); + sess.emit_err(MalformedAttribute { + span: item.span, + sub: MalformedAttributeSub::BadAttributeArgument(item.span), + }); } } } @@ -348,20 +369,21 @@ impl<'s> LintLevelsBuilder<'s> { let meta_item = match li { ast::NestedMetaItem::MetaItem(meta_item) if meta_item.is_word() => meta_item, _ => { - let mut err = bad_attr(sp); - let mut add_label = true; if let Some(item) = li.meta_item() { if let ast::MetaItemKind::NameValue(_) = item.kind { if item.path == sym::reason { - err.span_label(sp, "reason in lint attribute must come last"); - add_label = false; + sess.emit_err(MalformedAttribute { + span: sp, + sub: MalformedAttributeSub::ReasonMustComeLast(sp), + }); + continue; } } } - if add_label { - err.span_label(sp, "bad attribute argument"); - } - err.emit(); + sess.emit_err(MalformedAttribute { + span: sp, + sub: MalformedAttributeSub::BadAttributeArgument(sp), + }); continue; } }; @@ -485,22 +507,12 @@ impl<'s> LintLevelsBuilder<'s> { } &CheckLintNameResult::NoTool => { - let mut err = struct_span_err!( - sess, - tool_ident.map_or(DUMMY_SP, |ident| ident.span), - E0710, - "unknown tool name `{}` found in scoped lint: `{}::{}`", - tool_name.unwrap(), - tool_name.unwrap(), - pprust::path_to_string(&meta_item.path), - ); - if sess.is_nightly_build() { - err.help(&format!( - "add `#![register_tool({})]` to the crate root", - tool_name.unwrap() - )); - } - err.emit(); + sess.emit_err(UnknownToolInScopedLint { + span: tool_ident.map(|ident| ident.span), + tool_name: tool_name.unwrap(), + lint_name: pprust::path_to_string(&meta_item.path), + is_nightly_build: sess.is_nightly_build().then_some(()), + }); continue; } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index f087c624917..f34e062fd12 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -47,6 +47,7 @@ pub mod builtin; mod context; mod early; mod enum_intrinsics_non_enums; +mod errors; mod expect; pub mod hidden_unicode_codepoints; mod internal; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7ab71f9009d..9da9b4e91f6 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1531,6 +1531,7 @@ impl<'tcx> Place<'tcx> { } impl From<Local> for Place<'_> { + #[inline] fn from(local: Local) -> Self { Place { local, projection: List::empty() } } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 5e26a52900e..0f2504e3d9a 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -15,50 +15,33 @@ use rustc_hir::def_id::DefId; use rustc_hir::RangeEnd; use rustc_index::newtype_index; use rustc_index::vec::IndexVec; -use rustc_middle::infer::canonical::Canonical; use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp}; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::CanonicalUserTypeAnnotation; -use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts, UserType}; +use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts}; +use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation}; +use rustc_span::def_id::LocalDefId; use rustc_span::{Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::asm::InlineAsmRegOrRegClass; - -use rustc_span::def_id::LocalDefId; use std::fmt; use std::ops::Index; pub mod visit; -newtype_index! { - /// An index to an [`Arm`] stored in [`Thir::arms`] - #[derive(HashStable)] - pub struct ArmId { - DEBUG_FORMAT = "a{}" - } -} - -newtype_index! { - /// An index to an [`Expr`] stored in [`Thir::exprs`] - #[derive(HashStable)] - pub struct ExprId { - DEBUG_FORMAT = "e{}" - } -} - -newtype_index! { - #[derive(HashStable)] - /// An index to a [`Stmt`] stored in [`Thir::stmts`] - pub struct StmtId { - DEBUG_FORMAT = "s{}" - } -} - macro_rules! thir_with_elements { - ($($name:ident: $id:ty => $value:ty,)*) => { + ($($name:ident: $id:ty => $value:ty => $format:literal,)*) => { + $( + newtype_index! { + #[derive(HashStable)] + pub struct $id { + DEBUG_FORMAT = $format + } + } + )* + /// A container for a THIR body. /// /// This can be indexed directly by any THIR index (e.g. [`ExprId`]). @@ -91,9 +74,10 @@ macro_rules! thir_with_elements { } thir_with_elements! { - arms: ArmId => Arm<'tcx>, - exprs: ExprId => Expr<'tcx>, - stmts: StmtId => Stmt<'tcx>, + arms: ArmId => Arm<'tcx> => "a{}", + blocks: BlockId => Block => "b{}", + exprs: ExprId => Expr<'tcx> => "e{}", + stmts: StmtId => Stmt<'tcx> => "s{}", } #[derive(Copy, Clone, Debug, HashStable)] @@ -121,8 +105,10 @@ pub struct Block { pub safety_mode: BlockSafety, } +type UserTy<'tcx> = Option<Box<CanonicalUserType<'tcx>>>; + #[derive(Clone, Debug, HashStable)] -pub struct Adt<'tcx> { +pub struct AdtExpr<'tcx> { /// The ADT we're constructing. pub adt_def: AdtDef<'tcx>, /// The variant of the ADT. @@ -131,13 +117,30 @@ pub struct Adt<'tcx> { /// Optional user-given substs: for something like `let x = /// Bar::<T> { ... }`. - pub user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, + pub user_ty: UserTy<'tcx>, pub fields: Box<[FieldExpr]>, /// The base, e.g. `Foo {x: 1, .. base}`. pub base: Option<FruInfo<'tcx>>, } +#[derive(Clone, Debug, HashStable)] +pub struct ClosureExpr<'tcx> { + pub closure_id: LocalDefId, + pub substs: UpvarSubsts<'tcx>, + pub upvars: Box<[ExprId]>, + pub movability: Option<hir::Movability>, + pub fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>, +} + +#[derive(Clone, Debug, HashStable)] +pub struct InlineAsmExpr<'tcx> { + pub template: &'tcx [InlineAsmTemplatePiece], + pub operands: Box<[InlineAsmOperand<'tcx>]>, + pub options: InlineAsmOptions, + pub line_spans: &'tcx [Span], +} + #[derive(Copy, Clone, Debug, HashStable)] pub enum BlockSafety { Safe, @@ -183,7 +186,7 @@ pub enum StmtKind<'tcx> { initializer: Option<ExprId>, /// `let pat: ty = <INIT> else { <ELSE> } - else_block: Option<Block>, + else_block: Option<BlockId>, /// The lint level for this `let` statement. lint_level: LintLevel, @@ -307,7 +310,7 @@ pub enum ExprKind<'tcx> { }, /// A block. Block { - body: Block, + block: BlockId, }, /// An assignment: `lhs = rhs`. Assign { @@ -387,27 +390,21 @@ pub enum ExprKind<'tcx> { fields: Box<[ExprId]>, }, /// An ADT constructor, e.g. `Foo {x: 1, y: 2}`. - Adt(Box<Adt<'tcx>>), + Adt(Box<AdtExpr<'tcx>>), /// A type ascription on a place. PlaceTypeAscription { source: ExprId, /// Type that the user gave to this expression - user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, + user_ty: UserTy<'tcx>, }, /// A type ascription on a value, e.g. `42: i32`. ValueTypeAscription { source: ExprId, /// Type that the user gave to this expression - user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, + user_ty: UserTy<'tcx>, }, /// A closure definition. - Closure { - closure_id: LocalDefId, - substs: UpvarSubsts<'tcx>, - upvars: Box<[ExprId]>, - movability: Option<hir::Movability>, - fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>, - }, + Closure(Box<ClosureExpr<'tcx>>), /// A literal. Literal { lit: &'tcx hir::Lit, @@ -416,17 +413,17 @@ pub enum ExprKind<'tcx> { /// For literals that don't correspond to anything in the HIR NonHirLiteral { lit: ty::ScalarInt, - user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, + user_ty: UserTy<'tcx>, }, /// A literal of a ZST type. ZstLiteral { - user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, + user_ty: UserTy<'tcx>, }, /// Associated constants and named constants NamedConst { def_id: DefId, substs: SubstsRef<'tcx>, - user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, + user_ty: UserTy<'tcx>, }, ConstParam { param: ty::ParamConst, @@ -443,12 +440,7 @@ pub enum ExprKind<'tcx> { def_id: DefId, }, /// Inline assembly, i.e. `asm!()`. - InlineAsm { - template: &'tcx [InlineAsmTemplatePiece], - operands: Box<[InlineAsmOperand<'tcx>]>, - options: InlineAsmOptions, - line_spans: &'tcx [Span], - }, + InlineAsm(Box<InlineAsmExpr<'tcx>>), /// An expression taking a reference to a thread local. ThreadLocalRef(DefId), /// A `yield` expression. @@ -815,7 +807,10 @@ mod size_asserts { use super::*; // These are in alphabetical order, which is easy to maintain. static_assert_size!(Block, 56); - static_assert_size!(Expr<'_>, 104); + static_assert_size!(Expr<'_>, 64); + static_assert_size!(ExprKind<'_>, 40); static_assert_size!(Pat<'_>, 24); - static_assert_size!(Stmt<'_>, 120); + static_assert_size!(PatKind<'_>, 112); + static_assert_size!(Stmt<'_>, 72); + static_assert_size!(StmtKind<'_>, 64); } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 97249fdd175..c5c48a63609 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -1,5 +1,6 @@ use super::{ - Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, + AdtExpr, Arm, Block, ClosureExpr, Expr, ExprKind, Guard, InlineAsmExpr, InlineAsmOperand, Pat, + PatKind, Stmt, StmtKind, Thir, }; pub trait Visitor<'a, 'tcx: 'a>: Sized { @@ -75,7 +76,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp visitor.visit_arm(&visitor.thir()[arm]); } } - Block { ref body } => visitor.visit_block(body), + Block { block } => visitor.visit_block(&visitor.thir()[block]), Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { visitor.visit_expr(&visitor.thir()[lhs]); visitor.visit_expr(&visitor.thir()[rhs]); @@ -108,7 +109,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp visitor.visit_expr(&visitor.thir()[field]); } } - Adt(box crate::thir::Adt { + Adt(box AdtExpr { ref fields, ref base, adt_def: _, @@ -126,14 +127,20 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => { visitor.visit_expr(&visitor.thir()[source]) } - Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} + Closure(box ClosureExpr { + closure_id: _, + substs: _, + upvars: _, + movability: _, + fake_reads: _, + }) => {} Literal { lit: _, neg: _ } => {} NonHirLiteral { lit: _, user_ty: _ } => {} ZstLiteral { user_ty: _ } => {} NamedConst { def_id: _, substs: _, user_ty: _ } => {} ConstParam { param: _, def_id: _ } => {} StaticRef { alloc_id: _, ty: _, def_id: _ } => {} - InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { + InlineAsm(box InlineAsmExpr { ref operands, template: _, options: _, line_spans: _ }) => { for op in &**operands { use InlineAsmOperand::*; match op { @@ -174,7 +181,7 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm } visitor.visit_pat(pattern); if let Some(block) = else_block { - visitor.visit_block(block) + visitor.visit_block(&visitor.thir()[*block]) } } } diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 280b6aad12c..d5213dc0e04 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -11,7 +11,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, destination: Place<'tcx>, block: BasicBlock, - ast_block: &Block, + ast_block: BlockId, source_info: SourceInfo, ) -> BlockAnd<()> { let Block { @@ -22,7 +22,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr, targeted_by_break, safety_mode, - } = *ast_block; + } = self.thir[ast_block]; let expr = expr.map(|expr| &self.thir[expr]); self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| { this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| { @@ -146,7 +146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, init, initializer_span, - else_block, + *else_block, visibility_scope, last_remainder_scope, remainder_span, diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 19d420f154d..b316a6eeac1 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -41,11 +41,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span, user_ty: None, literal } } - ExprKind::NonHirLiteral { lit, user_ty } => { - let user_ty = user_ty.map(|user_ty| { + ExprKind::NonHirLiteral { lit, ref user_ty } => { + let user_ty = user_ty.as_ref().map(|box user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, - user_ty, + user_ty: *user_ty, inferred_ty: ty, }) }); @@ -53,11 +53,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span, user_ty: user_ty, literal } } - ExprKind::ZstLiteral { user_ty } => { - let user_ty = user_ty.map(|user_ty| { + ExprKind::ZstLiteral { ref user_ty } => { + let user_ty = user_ty.as_ref().map(|box user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, - user_ty, + user_ty: *user_ty, inferred_ty: ty, }) }); @@ -65,11 +65,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span, user_ty: user_ty, literal } } - ExprKind::NamedConst { def_id, substs, user_ty } => { - let user_ty = user_ty.map(|user_ty| { + ExprKind::NamedConst { def_id, substs, ref user_ty } => { + let user_ty = user_ty.as_ref().map(|box user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, - user_ty, + user_ty: *user_ty, inferred_ty: ty, }) }); diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 0c06aad4e44..b8277f28cdc 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -513,7 +513,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(place_builder) } - ExprKind::PlaceTypeAscription { source, user_ty } => { + ExprKind::PlaceTypeAscription { source, ref user_ty } => { let place_builder = unpack!( block = this.expr_as_place( block, @@ -522,11 +522,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrow_temps, ) ); - if let Some(user_ty) = user_ty { + if let Some(box user_ty) = user_ty { let annotation_index = this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span: source_info.span, - user_ty, + user_ty: *user_ty, inferred_ty: expr.ty, }); @@ -547,15 +547,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } block.and(place_builder) } - ExprKind::ValueTypeAscription { source, user_ty } => { + ExprKind::ValueTypeAscription { source, ref user_ty } => { let source = &this.thir[source]; let temp = unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability)); - if let Some(user_ty) = user_ty { + if let Some(box user_ty) = user_ty { let annotation_index = this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span: source_info.span, - user_ty, + user_ty: *user_ty, inferred_ty: expr.ty, }); this.cfg.push( diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 15f2d17c4e0..4b232a1b515 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -302,7 +302,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Aggregate(Box::new(AggregateKind::Tuple), fields)) } - ExprKind::Closure { closure_id, substs, ref upvars, movability, ref fake_reads } => { + ExprKind::Closure(box ClosureExpr { + closure_id, + substs, + ref upvars, + movability, + ref fake_reads, + }) => { // Convert the closure fake reads, if any, from `ExprRef` to mir `Place` // and push the fake reads. // This must come before creating the operands. This is required in case diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 724b72f8769..e5dafb820bf 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -83,8 +83,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Don't bother with StorageLive and Dead for these temporaries, // they are never assigned. ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (), - ExprKind::Block { body: Block { expr: None, targeted_by_break: false, .. } } - if expr_ty.is_never() => {} + ExprKind::Block { block } + if let Block { expr: None, targeted_by_break: false, .. } = this.thir[block] + && expr_ty.is_never() => {} _ => { this.cfg .push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) }); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 017d43d10a9..48ec7a06724 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) }) } - ExprKind::Block { body: ref ast_block } => { + ExprKind::Block { block: ast_block } => { this.ast_block(destination, block, ast_block, source_info) } ExprKind::Match { scrutinee, ref arms } => { @@ -314,11 +314,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push_assign(block, source_info, destination, address_of); block.unit() } - ExprKind::Adt(box Adt { + ExprKind::Adt(box AdtExpr { adt_def, variant_index, substs, - user_ty, + ref user_ty, ref fields, ref base, }) => { @@ -378,10 +378,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let inferred_ty = expr.ty; - let user_ty = user_ty.map(|ty| { + let user_ty = user_ty.as_ref().map(|box user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span: source_info.span, - user_ty: ty, + user_ty: *user_ty, inferred_ty, }) }); @@ -400,7 +400,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); block.unit() } - ExprKind::InlineAsm { template, ref operands, options, line_spans } => { + ExprKind::InlineAsm(box InlineAsmExpr { + template, + ref operands, + options, + line_spans, + }) => { use rustc_middle::{mir, thir}; let operands = operands .into_iter() diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index a7e1331aabc..00dbcaeb0c9 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -116,14 +116,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // it is usually better to focus on `the_value` rather // than the entirety of block(s) surrounding it. let adjusted_span = (|| { - if let ExprKind::Block { body } = &expr.kind && let Some(tail_ex) = body.expr { + if let ExprKind::Block { block } = expr.kind + && let Some(tail_ex) = this.thir[block].expr + { let mut expr = &this.thir[tail_ex]; - while let ExprKind::Block { - body: Block { expr: Some(nested_expr), .. }, - } - | ExprKind::Scope { value: nested_expr, .. } = expr.kind - { - expr = &this.thir[nested_expr]; + loop { + match expr.kind { + ExprKind::Block { block } + if let Some(nested_expr) = this.thir[block].expr => + { + expr = &this.thir[nested_expr]; + } + ExprKind::Scope { value: nested_expr, .. } => { + expr = &this.thir[nested_expr]; + } + _ => break, + } } this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored: true, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index ce38283724d..080dab03031 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2280,15 +2280,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mut block: BasicBlock, init: &Expr<'tcx>, initializer_span: Span, - else_block: &Block, + else_block: BlockId, visibility_scope: Option<SourceScope>, remainder_scope: region::Scope, remainder_span: Span, pattern: &Pat<'tcx>, ) -> BlockAnd<()> { + let else_block_span = self.thir[else_block].span; let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| { let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span)); - let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) }; + let pat = Pat { ty: init.ty, span: else_block_span, kind: Box::new(PatKind::Wild) }; let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false); this.declare_bindings( visibility_scope, @@ -2318,7 +2319,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); // This block is for the failure case let failure = this.bind_pattern( - this.source_info(else_block.span), + this.source_info(else_block_span), wildcard, None, &fake_borrow_temps, @@ -2334,19 +2335,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This place is not really used because this destination place // should never be used to take values at the end of the failure // block. - let dummy_place = self.temp(self.tcx.types.never, else_block.span); + let dummy_place = self.temp(self.tcx.types.never, else_block_span); let failure_block; unpack!( failure_block = self.ast_block( dummy_place, failure, else_block, - self.source_info(else_block.span), + self.source_info(else_block_span), ) ); self.cfg.terminate( failure_block, - self.source_info(else_block.span), + self.source_info(else_block_span), TerminatorKind::Unreachable, ); matching.unit() diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index f0b0456c4b9..bf5a2e7c73f 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -391,7 +391,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { ExprKind::InlineAsm { .. } => { self.requires_unsafe(expr.span, UseOfInlineAssembly); } - ExprKind::Adt(box Adt { + ExprKind::Adt(box AdtExpr { adt_def, variant_index: _, substs: _, @@ -402,13 +402,13 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { (Bound::Unbounded, Bound::Unbounded) => {} _ => self.requires_unsafe(expr.span, InitializingTypeWith), }, - ExprKind::Closure { + ExprKind::Closure(box ClosureExpr { closure_id, substs: _, upvars: _, movability: _, fake_reads: _, - } => { + }) => { let closure_def = if let Some((did, const_param_id)) = ty::WithOptConstParam::try_lookup(closure_id, self.tcx) { diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index dccaa61ed89..54c4b9eda70 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -9,13 +9,13 @@ use rustc_index::vec::Idx; use rustc_middle::ty::CanonicalUserTypeAnnotation; impl<'tcx> Cx<'tcx> { - pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block { + pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> BlockId { // We have to eagerly lower the "spine" of the statements // in order to get the lexical scoping correctly. let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts); let opt_destruction_scope = self.region_scope_tree.opt_destruction_scope(block.hir_id.local_id); - Block { + let block = Block { targeted_by_break: block.targeted_by_break, region_scope: region::Scope { id: block.hir_id.local_id, @@ -34,7 +34,9 @@ impl<'tcx> Cx<'tcx> { BlockSafety::ExplicitUnsafe(block.hir_id) } }, - } + }; + + self.thir.blocks.push(block) } fn mirror_stmts( diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 985601712c4..0c2b117453f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -108,8 +108,8 @@ impl<'tcx> Cx<'tcx> { // // ^ error message points at this expression. // } let mut adjust_span = |expr: &mut Expr<'tcx>| { - if let ExprKind::Block { body } = &expr.kind { - if let Some(last_expr) = body.expr { + if let ExprKind::Block { block } = expr.kind { + if let Some(last_expr) = self.thir[block].expr { span = self.thir[last_expr].span; expr.span = span; } @@ -329,7 +329,7 @@ impl<'tcx> Cx<'tcx> { if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value { *did = adt_def.did(); } - u_ty + Box::new(u_ty) }); debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty); @@ -341,7 +341,7 @@ impl<'tcx> Cx<'tcx> { expr: self.mirror_expr(e), }) .collect(); - ExprKind::Adt(Box::new(Adt { + ExprKind::Adt(Box::new(AdtExpr { adt_def, substs, variant_index: index, @@ -369,7 +369,7 @@ impl<'tcx> Cx<'tcx> { ExprKind::AddressOf { mutability, arg: self.mirror_expr(arg) } } - hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: self.mirror_block(blk) }, + hir::ExprKind::Block(ref blk, _) => ExprKind::Block { block: self.mirror_block(blk) }, hir::ExprKind::Assign(ref lhs, ref rhs, _) => { ExprKind::Assign { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs) } @@ -464,9 +464,9 @@ impl<'tcx> Cx<'tcx> { ty::Adt(adt, substs) => match adt.adt_kind() { AdtKind::Struct | AdtKind::Union => { let user_provided_types = self.typeck_results().user_provided_types(); - let user_ty = user_provided_types.get(expr.hir_id).copied(); + let user_ty = user_provided_types.get(expr.hir_id).copied().map(Box::new); debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty); - ExprKind::Adt(Box::new(Adt { + ExprKind::Adt(Box::new(AdtExpr { adt_def: *adt, variant_index: VariantIdx::new(0), substs, @@ -490,9 +490,10 @@ impl<'tcx> Cx<'tcx> { let index = adt.variant_index_with_id(variant_id); let user_provided_types = self.typeck_results().user_provided_types(); - let user_ty = user_provided_types.get(expr.hir_id).copied(); + let user_ty = + user_provided_types.get(expr.hir_id).copied().map(Box::new); debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty); - ExprKind::Adt(Box::new(Adt { + ExprKind::Adt(Box::new(AdtExpr { adt_def: *adt, variant_index: index, substs, @@ -547,7 +548,13 @@ impl<'tcx> Cx<'tcx> { None => Vec::new(), }; - ExprKind::Closure { closure_id: def_id, substs, upvars, movability, fake_reads } + ExprKind::Closure(Box::new(ClosureExpr { + closure_id: def_id, + substs, + upvars, + movability, + fake_reads, + })) } hir::ExprKind::Path(ref qpath) => { @@ -555,7 +562,7 @@ impl<'tcx> Cx<'tcx> { self.convert_path_expr(expr, res) } - hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm { + hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm(Box::new(InlineAsmExpr { template: asm.template, operands: asm .operands @@ -614,7 +621,7 @@ impl<'tcx> Cx<'tcx> { .collect(), options: asm.options, line_spans: asm.line_spans, - }, + })), hir::ExprKind::ConstBlock(ref anon_const) => { let ty = self.typeck_results().node_type(anon_const.hir_id); @@ -679,8 +686,8 @@ impl<'tcx> Cx<'tcx> { let body = self.thir.exprs.push(Expr { ty: block_ty, temp_lifetime, - span: block.span, - kind: ExprKind::Block { body: block }, + span: self.thir[block].span, + kind: ExprKind::Block { block }, }); ExprKind::Loop { body } } @@ -712,14 +719,17 @@ impl<'tcx> Cx<'tcx> { }); debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty); - ExprKind::ValueTypeAscription { source: cast_expr, user_ty: Some(*user_ty) } + ExprKind::ValueTypeAscription { + source: cast_expr, + user_ty: Some(Box::new(*user_ty)), + } } else { cast } } hir::ExprKind::Type(ref source, ref ty) => { let user_provided_types = self.typeck_results.user_provided_types(); - let user_ty = user_provided_types.get(ty.hir_id).copied(); + let user_ty = user_provided_types.get(ty.hir_id).copied().map(Box::new); debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty); let mirrored = self.mirror_expr(source); if source.is_syntactic_place_expr() { @@ -748,7 +758,7 @@ impl<'tcx> Cx<'tcx> { &mut self, hir_id: hir::HirId, res: Res, - ) -> Option<ty::CanonicalUserType<'tcx>> { + ) -> Option<Box<ty::CanonicalUserType<'tcx>>> { debug!("user_substs_applied_to_res: res={:?}", res); let user_provided_type = match res { // A reference to something callable -- e.g., a fn, method, or @@ -759,7 +769,7 @@ impl<'tcx> Cx<'tcx> { | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => { - self.typeck_results().user_provided_types().get(hir_id).copied() + self.typeck_results().user_provided_types().get(hir_id).copied().map(Box::new) } // A unit struct/variant which is used as a value (e.g., @@ -767,11 +777,11 @@ impl<'tcx> Cx<'tcx> { // this variant -- but with the substitutions given by the // user. Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => { - self.user_substs_applied_to_ty_of_hir_id(hir_id) + self.user_substs_applied_to_ty_of_hir_id(hir_id).map(Box::new) } // `Self` is used in expression as a tuple struct constructor or a unit struct constructor - Res::SelfCtor(_) => self.user_substs_applied_to_ty_of_hir_id(hir_id), + Res::SelfCtor(_) => self.user_substs_applied_to_ty_of_hir_id(hir_id).map(Box::new), _ => bug!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res, hir_id), }; @@ -846,22 +856,22 @@ impl<'tcx> Cx<'tcx> { Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => { let user_ty = self.user_substs_applied_to_res(expr.hir_id, res); - ExprKind::NamedConst { def_id, substs, user_ty: user_ty } + ExprKind::NamedConst { def_id, substs, user_ty } } Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => { let user_provided_types = self.typeck_results.user_provided_types(); - let user_provided_type = user_provided_types.get(expr.hir_id).copied(); - debug!("convert_path_expr: user_provided_type={:?}", user_provided_type); + let user_ty = user_provided_types.get(expr.hir_id).copied().map(Box::new); + debug!("convert_path_expr: user_ty={:?}", user_ty); let ty = self.typeck_results().node_type(expr.hir_id); match ty.kind() { // A unit struct/variant which is used as a value. // We return a completely different ExprKind here to account for this special case. - ty::Adt(adt_def, substs) => ExprKind::Adt(Box::new(Adt { + ty::Adt(adt_def, substs) => ExprKind::Adt(Box::new(AdtExpr { adt_def: *adt_def, variant_index: adt_def.variant_index_with_ctor_id(def_id), substs, - user_ty: user_provided_type, + user_ty, fields: Box::new([]), base: None, })), diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index baf9735fbc8..385e9ba748f 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -13,10 +13,13 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } rustc_graphviz = { path = "../rustc_graphviz" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_mir_dataflow/src/errors.rs b/compiler/rustc_mir_dataflow/src/errors.rs new file mode 100644 index 00000000000..cc14257876c --- /dev/null +++ b/compiler/rustc_mir_dataflow/src/errors.rs @@ -0,0 +1,71 @@ +use rustc_macros::SessionDiagnostic; +use rustc_span::{Span, Symbol}; + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::path_must_end_in_filename)] +pub(crate) struct PathMustEndInFilename { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::unknown_formatter)] +pub(crate) struct UnknownFormatter { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::duplicate_values_for)] +pub(crate) struct DuplicateValuesFor { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::requires_an_argument)] +pub(crate) struct RequiresAnArgument { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::stop_after_dataflow_ended_compilation)] +pub(crate) struct StopAfterDataFlowEndedCompilation; + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::peek_must_be_place_or_ref_place)] +pub(crate) struct PeekMustBePlaceOrRefPlace { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::peek_must_be_not_temporary)] +pub(crate) struct PeekMustBeNotTemporary { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::peek_bit_not_set)] +pub(crate) struct PeekBitNotSet { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::peek_argument_not_a_local)] +pub(crate) struct PeekArgumentNotALocal { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_dataflow::peek_argument_untracked)] +pub(crate) struct PeekArgumentUntracked { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index f374658ceb6..112204c7599 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -1,5 +1,8 @@ //! A solver for dataflow problems. +use crate::errors::{ + DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, +}; use crate::framework::BitSetExt; use std::ffi::OsString; @@ -347,7 +350,7 @@ impl RustcMirAttrs { match path.file_name() { Some(_) => Ok(path), None => { - tcx.sess.span_err(attr.span(), "path must end in a filename"); + tcx.sess.emit_err(PathMustEndInFilename { span: attr.span() }); Err(()) } } @@ -356,7 +359,7 @@ impl RustcMirAttrs { Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s { sym::gen_kill | sym::two_phase => Ok(s), _ => { - tcx.sess.span_err(attr.span(), "unknown formatter"); + tcx.sess.emit_err(UnknownFormatter { span: attr.span() }); Err(()) } }) @@ -377,8 +380,7 @@ impl RustcMirAttrs { mapper: impl FnOnce(Symbol) -> Result<T, ()>, ) -> Result<(), ()> { if field.is_some() { - tcx.sess - .span_err(attr.span(), &format!("duplicate values for `{}`", attr.name_or_empty())); + tcx.sess.emit_err(DuplicateValuesFor { span: attr.span(), name: attr.name_or_empty() }); return Err(()); } @@ -387,8 +389,7 @@ impl RustcMirAttrs { *field = Some(mapper(s)?); Ok(()) } else { - tcx.sess - .span_err(attr.span(), &format!("`{}` requires an argument", attr.name_or_empty())); + tcx.sess.emit_err(RequiresAnArgument { span: attr.span(), name: attr.name_or_empty() }); Err(()) } } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 21132eb991f..483c1e274aa 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -23,12 +23,6 @@ use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKi /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis pub struct MaybeLiveLocals; -impl MaybeLiveLocals { - fn transfer_function<'a, T>(&self, trans: &'a mut T) -> TransferFunction<'a, T> { - TransferFunction(trans) - } -} - impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals { type Domain = ChunkedBitSet<Local>; type Direction = Backward; @@ -54,7 +48,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { statement: &mir::Statement<'tcx>, location: Location, ) { - self.transfer_function(trans).visit_statement(statement, location); + TransferFunction(trans).visit_statement(statement, location); } fn terminator_effect( @@ -63,7 +57,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { terminator: &mir::Terminator<'tcx>, location: Location, ) { - self.transfer_function(trans).visit_terminator(terminator, location); + TransferFunction(trans).visit_terminator(terminator, location); } fn call_return_effect( @@ -85,9 +79,11 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { _resume_block: mir::BasicBlock, resume_place: mir::Place<'tcx>, ) { - if let Some(local) = resume_place.as_local() { - trans.kill(local); - } + YieldResumeEffect(trans).visit_place( + &resume_place, + PlaceContext::MutatingUse(MutatingUseContext::Yield), + Location::START, + ) } } @@ -98,28 +94,51 @@ where T: GenKill<Local>, { fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { - let local = place.local; - - // We purposefully do not call `super_place` here to avoid calling `visit_local` for this - // place with one of the `Projection` variants of `PlaceContext`. - self.visit_projection(place.as_ref(), context, location); + if let PlaceContext::MutatingUse(MutatingUseContext::Yield) = context { + // The resume place is evaluated and assigned to only after generator resumes, so its + // effect is handled separately in `yield_resume_effect`. + return; + } match DefUse::for_place(*place, context) { - Some(DefUse::Def) => self.0.kill(local), - Some(DefUse::Use) => self.0.gen(local), + Some(DefUse::Def) => { + if let PlaceContext::MutatingUse( + MutatingUseContext::Call | MutatingUseContext::AsmOutput, + ) = context + { + // For the associated terminators, this is only a `Def` when the terminator returns + // "successfully." As such, we handle this case separately in `call_return_effect` + // above. However, if the place looks like `*_5`, this is still unconditionally a use of + // `_5`. + } else { + self.0.kill(place.local); + } + } + Some(DefUse::Use) => self.0.gen(place.local), None => {} } + + self.visit_projection(place.as_ref(), context, location); } fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { - // Because we do not call `super_place` above, `visit_local` is only called for locals that - // do not appear as part of a `Place` in the MIR. This handles cases like the implicit use - // of the return place in a `Return` terminator or the index in an `Index` projection. - match DefUse::for_place(local.into(), context) { - Some(DefUse::Def) => self.0.kill(local), - Some(DefUse::Use) => self.0.gen(local), - None => {} - } + DefUse::apply(self.0, local.into(), context); + } +} + +struct YieldResumeEffect<'a, T>(&'a mut T); + +impl<'tcx, T> Visitor<'tcx> for YieldResumeEffect<'_, T> +where + T: GenKill<Local>, +{ + fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { + DefUse::apply(self.0, *place, context); + self.visit_projection(place.as_ref(), context, location); + } + + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { + DefUse::apply(self.0, local.into(), context); } } @@ -130,11 +149,25 @@ enum DefUse { } impl DefUse { + fn apply<'tcx>(trans: &mut impl GenKill<Local>, place: Place<'tcx>, context: PlaceContext) { + match DefUse::for_place(place, context) { + Some(DefUse::Def) => trans.kill(place.local), + Some(DefUse::Use) => trans.gen(place.local), + None => {} + } + } + fn for_place<'tcx>(place: Place<'tcx>, context: PlaceContext) -> Option<DefUse> { match context { PlaceContext::NonUse(_) => None, - PlaceContext::MutatingUse(MutatingUseContext::Store | MutatingUseContext::Deinit) => { + PlaceContext::MutatingUse( + MutatingUseContext::Call + | MutatingUseContext::Yield + | MutatingUseContext::AsmOutput + | MutatingUseContext::Store + | MutatingUseContext::Deinit, + ) => { if place.is_indirect() { // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a // use. @@ -152,16 +185,6 @@ impl DefUse { place.is_indirect().then_some(DefUse::Use) } - // For the associated terminators, this is only a `Def` when the terminator returns - // "successfully." As such, we handle this case separately in `call_return_effect` - // above. However, if the place looks like `*_5`, this is still unconditionally a use of - // `_5`. - PlaceContext::MutatingUse( - MutatingUseContext::Call - | MutatingUseContext::Yield - | MutatingUseContext::AsmOutput, - ) => place.is_indirect().then_some(DefUse::Use), - // All other contexts are uses... PlaceContext::MutatingUse( MutatingUseContext::AddressOf @@ -290,8 +313,10 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { _resume_block: mir::BasicBlock, resume_place: mir::Place<'tcx>, ) { - if let Some(local) = resume_place.as_local() { - trans.remove(local); - } + YieldResumeEffect(trans).visit_place( + &resume_place, + PlaceContext::MutatingUse(MutatingUseContext::Yield), + Location::START, + ) } } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 5793a286bd0..62b712f7b8d 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -7,6 +7,8 @@ #![feature(stmt_expr_attributes)] #![feature(trusted_step)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; @@ -33,6 +35,7 @@ use self::move_paths::MoveData; pub mod drop_flag_effects; pub mod elaborate_drops; +mod errors; mod framework; pub mod impls; pub mod move_paths; diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index f2471f37a52..5fb7cb6584b 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -6,6 +6,10 @@ use rustc_middle::mir::MirPass; use rustc_middle::mir::{self, Body, Local, Location}; use rustc_middle::ty::{self, Ty, TyCtxt}; +use crate::errors::{ + PeekArgumentNotALocal, PeekArgumentUntracked, PeekBitNotSet, PeekMustBeNotTemporary, + PeekMustBePlaceOrRefPlace, StopAfterDataFlowEndedCompilation, +}; use crate::framework::BitSetExt; use crate::impls::{ DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces, @@ -64,7 +68,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck { } if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() { - tcx.sess.fatal("stop_after_dataflow ended compilation"); + tcx.sess.emit_fatal(StopAfterDataFlowEndedCompilation); } } } @@ -133,9 +137,7 @@ pub fn sanity_check_via_rustc_peek<'tcx, A>( } _ => { - let msg = "rustc_peek: argument expression \ - must be either `place` or `&place`"; - tcx.sess.span_err(call.span, msg); + tcx.sess.emit_err(PeekMustBePlaceOrRefPlace { span: call.span }); } } } @@ -204,18 +206,12 @@ impl PeekCall { if let Some(local) = place.as_local() { local } else { - tcx.sess.diagnostic().span_err( - span, - "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", - ); + tcx.sess.emit_err(PeekMustBeNotTemporary { span }); return None; } } _ => { - tcx.sess.diagnostic().span_err( - span, - "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", - ); + tcx.sess.emit_err(PeekMustBeNotTemporary { span }); return None; } }; @@ -255,12 +251,12 @@ where let bit_state = flow_state.contains(peek_mpi); debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state); if !bit_state { - tcx.sess.span_err(call.span, "rustc_peek: bit not set"); + tcx.sess.emit_err(PeekBitNotSet { span: call.span }); } } LookupResult::Parent(..) => { - tcx.sess.span_err(call.span, "rustc_peek: argument untracked"); + tcx.sess.emit_err(PeekArgumentUntracked { span: call.span }); } } } @@ -276,12 +272,12 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { ) { info!(?place, "peek_at"); let Some(local) = place.as_local() else { - tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); + tcx.sess.emit_err(PeekArgumentNotALocal { span: call.span }); return; }; if !flow_state.contains(local) { - tcx.sess.span_err(call.span, "rustc_peek: bit not set"); + tcx.sess.emit_err(PeekBitNotSet { span: call.span }); } } } diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index e04094153df..294af2455d0 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -107,27 +107,8 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs { let mut visitor = ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch }; - for (block, BasicBlockData { statements, terminator, .. }) in - body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() - { - let mut index = 0; - for statement in statements { - let location = Location { block, statement_index: index }; - visitor.visit_statement(statement, location); - index += 1; - } - - let location = Location { block, statement_index: index }; - match terminator { - // yielding into a box is handled when lowering generators - Some(Terminator { kind: TerminatorKind::Yield { value, .. }, .. }) => { - visitor.visit_operand(value, location); - } - Some(terminator) => { - visitor.visit_terminator(terminator, location); - } - None => {} - } + for (block, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + visitor.visit_basic_block_data(block, data); } visitor.patch.apply(body); diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 91ecf387922..5b0d9900c0f 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1182,8 +1182,6 @@ fn create_cases<'tcx>( transform: &TransformVisitor<'tcx>, operation: Operation, ) -> Vec<(usize, BasicBlock)> { - let tcx = transform.tcx; - let source_info = SourceInfo::outermost(body.span); transform @@ -1216,85 +1214,13 @@ fn create_cases<'tcx>( if operation == Operation::Resume { // Move the resume argument to the destination place of the `Yield` terminator let resume_arg = Local::new(2); // 0 = return, 1 = self - - // handle `box yield` properly - let box_place = if let [projection @ .., ProjectionElem::Deref] = - &**point.resume_arg.projection - { - let box_place = - Place::from(point.resume_arg.local).project_deeper(projection, tcx); - - let box_ty = box_place.ty(&body.local_decls, tcx).ty; - - if box_ty.is_box() { Some((box_place, box_ty)) } else { None } - } else { - None - }; - - if let Some((box_place, box_ty)) = box_place { - let unique_did = box_ty - .ty_adt_def() - .expect("expected Box to be an Adt") - .non_enum_variant() - .fields[0] - .did; - - let Some(nonnull_def) = tcx.type_of(unique_did).ty_adt_def() else { - span_bug!(tcx.def_span(unique_did), "expected Box to contain Unique") - }; - - let nonnull_did = nonnull_def.non_enum_variant().fields[0].did; - - let (unique_ty, nonnull_ty, ptr_ty) = - crate::elaborate_box_derefs::build_ptr_tys( - tcx, - box_ty.boxed_ty(), - unique_did, - nonnull_did, - ); - - let ptr_local = body.local_decls.push(LocalDecl::new(ptr_ty, body.span)); - - statements.push(Statement { - source_info, - kind: StatementKind::StorageLive(ptr_local), - }); - - statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - Place::from(ptr_local), - Rvalue::Use(Operand::Copy(box_place.project_deeper( - &crate::elaborate_box_derefs::build_projection( - unique_ty, nonnull_ty, ptr_ty, - ), - tcx, - ))), - ))), - }); - - statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - Place::from(ptr_local) - .project_deeper(&[ProjectionElem::Deref], tcx), - Rvalue::Use(Operand::Move(resume_arg.into())), - ))), - }); - - statements.push(Statement { - source_info, - kind: StatementKind::StorageDead(ptr_local), - }); - } else { - statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - point.resume_arg, - Rvalue::Use(Operand::Move(resume_arg.into())), - ))), - }); - } + statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + point.resume_arg, + Rvalue::Use(Operand::Move(resume_arg.into())), + ))), + }); } // Then jump to the real target diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b545b979391..b08d2b376a6 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -250,13 +250,30 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .map_or_else(String::new, |res| format!("{} ", res.descr())); (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), None) }; + + let (fallback_label, suggestion) = if path_str == "async" + && expected.starts_with("struct") + { + ("`async` blocks are only allowed in Rust 2018 or later".to_string(), suggestion) + } else { + // check if we are in situation of typo like `True` instead of `true`. + let override_suggestion = + if ["true", "false"].contains(&item_str.to_string().to_lowercase().as_str()) { + let item_typo = item_str.to_string().to_lowercase(); + Some(( + item_span, + "you may want to use a bool value instead", + format!("{}", item_typo), + )) + } else { + suggestion + }; + (format!("not found in {mod_str}"), override_suggestion) + }; + BaseError { msg: format!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"), - fallback_label: if path_str == "async" && expected.starts_with("struct") { - "`async` blocks are only allowed in Rust 2018 or later".to_string() - } else { - format!("not found in {mod_str}") - }, + fallback_label, span: item_span, span_label: None, could_be_expr: false, diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 079d44bac68..91f4cfaf5ac 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -16,6 +16,7 @@ Core encoding and decoding interfaces. #![feature(maybe_uninit_slice)] #![feature(let_else)] #![feature(new_uninit)] +#![feature(allocator_api)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 9bd5550038f..751b209f11a 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -4,6 +4,7 @@ Core encoding and decoding interfaces. */ +use std::alloc::Allocator; use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::marker::PhantomData; @@ -229,9 +230,9 @@ impl<D: Decoder, T> Decodable<D> for PhantomData<T> { } } -impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<[T]> { - fn decode(d: &mut D) -> Box<[T]> { - let v: Vec<T> = Decodable::decode(d); +impl<D: Decoder, A: Allocator + Default, T: Decodable<D>> Decodable<D> for Box<[T], A> { + fn decode(d: &mut D) -> Box<[T], A> { + let v: Vec<T, A> = Decodable::decode(d); v.into_boxed_slice() } } @@ -264,12 +265,13 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for Vec<T> { } } -impl<D: Decoder, T: Decodable<D>> Decodable<D> for Vec<T> { - default fn decode(d: &mut D) -> Vec<T> { +impl<D: Decoder, T: Decodable<D>, A: Allocator + Default> Decodable<D> for Vec<T, A> { + default fn decode(d: &mut D) -> Vec<T, A> { let len = d.read_usize(); + let allocator = A::default(); // SAFETY: we set the capacity in advance, only write elements, and // only set the length at the end once the writing has succeeded. - let mut vec = Vec::with_capacity(len); + let mut vec = Vec::with_capacity_in(len, allocator); unsafe { let ptr: *mut T = vec.as_mut_ptr(); for i in 0..len { @@ -457,13 +459,15 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<T> { } } -impl<S: Encoder, T: ?Sized + Encodable<S>> Encodable<S> for Box<T> { +impl<S: Encoder, T: ?Sized + Encodable<S>, A: Allocator + Default> Encodable<S> for Box<T, A> { fn encode(&self, s: &mut S) { - (**self).encode(s); + (**self).encode(s) } } -impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<T> { - fn decode(d: &mut D) -> Box<T> { - Box::new(Decodable::decode(d)) + +impl<D: Decoder, A: Allocator + Default, T: Decodable<D>> Decodable<D> for Box<T, A> { + fn decode(d: &mut D) -> Box<T, A> { + let allocator = A::default(); + Box::new_in(Decodable::decode(d), allocator) } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 68519c8fa82..162fc9aa0a6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2423,13 +2423,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let pretty = parse_pretty(&unstable_opts, error_format); - if !unstable_opts.unstable_options - && !target_triple.triple().contains("apple") - && cg.split_debuginfo.is_some() - { - early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform"); - } - // Try to find a directory containing the Rust `src`, for more details see // the doc comment on the `real_rust_source_base_dir` field. let tmp_buf; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 4972ae2014d..ec5e5170d35 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -20,8 +20,8 @@ use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ - fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee, - ErrorGuaranteed, FluentBundle, LazyFallbackBundle, MultiSpan, + error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, + EmissionGuarantee, ErrorGuaranteed, FluentBundle, LazyFallbackBundle, MultiSpan, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -31,7 +31,7 @@ use rustc_span::{sym, SourceFileHashAlgorithm, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel}; use rustc_target::spec::{ - SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel, + DebuginfoKind, SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel, }; use std::cell::{self, RefCell}; @@ -467,6 +467,9 @@ impl Session { feature: Symbol, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut err = self.parse_sess.create_err(err); + if err.code.is_none() { + err.code = std::option::Option::Some(error_code!(E0658)); + } add_feature_diagnostics(&mut err, &self.parse_sess, feature); err } @@ -670,8 +673,9 @@ impl Session { ) } + /// Returns `true` if the target can use the current split debuginfo configuration. pub fn target_can_use_split_dwarf(&self) -> bool { - !self.target.is_like_windows && !self.target.is_like_osx + self.target.debuginfo_kind == DebuginfoKind::Dwarf } pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String { @@ -1552,6 +1556,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.err(&format!("requested DWARF version {} is greater than 5", dwarf_version)); } } + + if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo()) + && !sess.opts.unstable_opts.unstable_options + { + sess.err(&format!( + "`-Csplit-debuginfo={}` is unstable on this platform", + sess.split_debuginfo() + )); + } } /// Holds data on the current incremental compilation session, if there is one. diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index db38ff50c78..9bbee88a894 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, env}; -use crate::spec::{cvs, FramePointer, SplitDebuginfo, TargetOptions}; +use crate::spec::{cvs, DebuginfoKind, FramePointer, SplitDebuginfo, TargetOptions}; use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor}; fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs { @@ -76,9 +76,15 @@ pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOp eh_frame_header: false, lld_flavor: LldFlavor::Ld64, + debuginfo_kind: DebuginfoKind::DwarfDsym, // The historical default for macOS targets is to run `dsymutil` which // generates a packed version of debuginfo split from the main file. split_debuginfo: SplitDebuginfo::Packed, + supported_split_debuginfo: Cow::Borrowed(&[ + SplitDebuginfo::Packed, + SplitDebuginfo::Unpacked, + SplitDebuginfo::Off, + ]), // This environment variable is pretty magical but is intended for // producing deterministic builds. This was first discovered to be used diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs index f4fce3b4050..df8e848124a 100644 --- a/compiler/rustc_target/src/spec/linux_base.rs +++ b/compiler/rustc_target/src/spec/linux_base.rs @@ -1,4 +1,5 @@ -use crate::spec::{cvs, RelroLevel, TargetOptions}; +use crate::spec::{cvs, RelroLevel, SplitDebuginfo, TargetOptions}; +use std::borrow::Cow; pub fn opts() -> TargetOptions { TargetOptions { @@ -10,6 +11,11 @@ pub fn opts() -> TargetOptions { relro_level: RelroLevel::Full, has_thread_local: true, crt_static_respected: true, + supported_split_debuginfo: Cow::Borrowed(&[ + SplitDebuginfo::Packed, + SplitDebuginfo::Unpacked, + SplitDebuginfo::Off, + ]), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index cf6cb75d49a..8d00129b1b1 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -468,7 +468,57 @@ impl fmt::Display for LinkOutputKind { pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>; -#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)] +/// Which kind of debuginfo does the target use? +/// +/// Useful in determining whether a target supports Split DWARF (a target with +/// `DebuginfoKind::Dwarf` and supporting `SplitDebuginfo::Unpacked` for example). +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] +pub enum DebuginfoKind { + /// DWARF debuginfo (such as that used on `x86_64_unknown_linux_gnu`). + #[default] + Dwarf, + /// DWARF debuginfo in dSYM files (such as on Apple platforms). + DwarfDsym, + /// Program database files (such as on Windows). + Pdb, +} + +impl DebuginfoKind { + fn as_str(&self) -> &'static str { + match self { + DebuginfoKind::Dwarf => "dwarf", + DebuginfoKind::DwarfDsym => "dwarf-dsym", + DebuginfoKind::Pdb => "pdb", + } + } +} + +impl FromStr for DebuginfoKind { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "dwarf" => DebuginfoKind::Dwarf, + "dwarf-dsym" => DebuginfoKind::DwarfDsym, + "pdb" => DebuginfoKind::Pdb, + _ => return Err(()), + }) + } +} + +impl ToJson for DebuginfoKind { + fn to_json(&self) -> Json { + self.as_str().to_json() + } +} + +impl fmt::Display for DebuginfoKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] pub enum SplitDebuginfo { /// Split debug-information is disabled, meaning that on supported platforms /// you can find all debug information in the executable itself. This is @@ -476,7 +526,8 @@ pub enum SplitDebuginfo { /// /// * Windows - not supported /// * macOS - don't run `dsymutil` - /// * ELF - `.dwarf_*` sections + /// * ELF - `.debug_*` sections + #[default] Off, /// Split debug-information can be found in a "packed" location separate @@ -484,7 +535,7 @@ pub enum SplitDebuginfo { /// /// * Windows - `*.pdb` /// * macOS - `*.dSYM` (run `dsymutil`) - /// * ELF - `*.dwp` (run `rust-llvm-dwp`) + /// * ELF - `*.dwp` (run `thorin`) Packed, /// Split debug-information can be found in individual object files on the @@ -509,7 +560,7 @@ impl SplitDebuginfo { impl FromStr for SplitDebuginfo { type Err = (); - fn from_str(s: &str) -> Result<SplitDebuginfo, ()> { + fn from_str(s: &str) -> Result<Self, ()> { Ok(match s { "off" => SplitDebuginfo::Off, "unpacked" => SplitDebuginfo::Unpacked, @@ -1436,9 +1487,13 @@ pub struct TargetOptions { /// thumb and arm interworking. pub has_thumb_interworking: bool, + /// Which kind of debuginfo is used by this target? + pub debuginfo_kind: DebuginfoKind, /// How to handle split debug information, if at all. Specifying `None` has /// target-specific meaning. pub split_debuginfo: SplitDebuginfo, + /// Which kinds of split debuginfo are supported by the target? + pub supported_split_debuginfo: StaticCow<[SplitDebuginfo]>, /// The sanitizers supported by this target /// @@ -1596,7 +1651,10 @@ impl Default for TargetOptions { use_ctors_section: false, eh_frame_header: true, has_thumb_interworking: false, - split_debuginfo: SplitDebuginfo::Off, + debuginfo_kind: Default::default(), + split_debuginfo: Default::default(), + // `Off` is supported by default, but targets can remove this manually, e.g. Windows. + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), supported_sanitizers: SanitizerSet::empty(), default_adjusted_cabi: None, c_enum_min_bits: 32, @@ -1869,6 +1927,19 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); + ($key_name:ident, DebuginfoKind) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { + match s.parse::<DebuginfoKind>() { + Ok(level) => base.$key_name = level, + _ => return Some(Err( + format!("'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \ + 'dwarf-dsym' or 'pdb'.") + )), + } + Some(Ok(())) + })).unwrap_or(Ok(())) + } ); ($key_name:ident, SplitDebuginfo) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { @@ -1905,6 +1976,25 @@ impl Target { } } } ); + ($key_name:ident, falliable_list) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.remove(&name).and_then(|j| { + if let Some(v) = j.as_array() { + match v.iter().map(|a| FromStr::from_str(a.as_str().unwrap())).collect() { + Ok(l) => { base.$key_name = l }, + // FIXME: `falliable_list` can't re-use the `key!` macro for list + // elements and the error messages from that macro, so it has a bad + // generic message instead + Err(_) => return Some(Err( + format!("`{:?}` is not a valid value for `{}`", j, name) + )), + } + } else { + incorrect_type.push(name) + } + Some(Ok(())) + }).unwrap_or(Ok(())) + } ); ($key_name:ident, optional) => ( { let name = (stringify!($key_name)).replace("_", "-"); if let Some(o) = obj.remove(&name) { @@ -2191,7 +2281,9 @@ impl Target { key!(use_ctors_section, bool); key!(eh_frame_header, bool); key!(has_thumb_interworking, bool); + key!(debuginfo_kind, DebuginfoKind)?; key!(split_debuginfo, SplitDebuginfo)?; + key!(supported_split_debuginfo, falliable_list)?; key!(supported_sanitizers, SanitizerSet)?; key!(default_adjusted_cabi, Option<Abi>)?; key!(c_enum_min_bits, u64); @@ -2435,7 +2527,9 @@ impl ToJson for Target { target_option_val!(use_ctors_section); target_option_val!(eh_frame_header); target_option_val!(has_thumb_interworking); + target_option_val!(debuginfo_kind); target_option_val!(split_debuginfo); + target_option_val!(supported_split_debuginfo); target_option_val!(supported_sanitizers); target_option_val!(c_enum_min_bits); target_option_val!(generate_arange_section); diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs index edb30b72bf6..ec9609a2b26 100644 --- a/compiler/rustc_target/src/spec/msvc_base.rs +++ b/compiler/rustc_target/src/spec/msvc_base.rs @@ -1,4 +1,5 @@ use crate::spec::{LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions}; +use std::borrow::Cow; pub fn opts() -> TargetOptions { // Suppress the verbose logo and authorship debugging output, which would needlessly @@ -18,6 +19,7 @@ pub fn opts() -> TargetOptions { // Currently this is the only supported method of debuginfo on MSVC // where `*.pdb` files show up next to the final artifact. split_debuginfo: SplitDebuginfo::Packed, + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Packed]), ..Default::default() } diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index 0107f7a52c6..81d44a963f1 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -1,5 +1,6 @@ use crate::spec::crt_objects::{self, LinkSelfContainedDefault}; -use crate::spec::{cvs, LinkerFlavor, TargetOptions}; +use crate::spec::{cvs, DebuginfoKind, LinkerFlavor, SplitDebuginfo, TargetOptions}; +use std::borrow::Cow; pub fn opts() -> TargetOptions { let mut pre_link_args = TargetOptions::link_args( @@ -86,6 +87,10 @@ pub fn opts() -> TargetOptions { emit_debug_gdb_scripts: false, requires_uwtable: true, eh_frame_header: false, + // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to + // output DWO, despite using DWARF, doesn't use ELF.. + debuginfo_kind: DebuginfoKind::Pdb, + supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/windows_msvc_base.rs b/compiler/rustc_target/src/spec/windows_msvc_base.rs index 21062c337d8..67282c19541 100644 --- a/compiler/rustc_target/src/spec/windows_msvc_base.rs +++ b/compiler/rustc_target/src/spec/windows_msvc_base.rs @@ -1,4 +1,4 @@ -use crate::spec::{cvs, TargetOptions}; +use crate::spec::{cvs, DebuginfoKind, TargetOptions}; pub fn opts() -> TargetOptions { let base = super::msvc_base::opts(); @@ -28,6 +28,7 @@ pub fn opts() -> TargetOptions { // not ever be possible for us to pass this flag. no_default_libraries: false, has_thread_local: true, + debuginfo_kind: DebuginfoKind::Pdb, ..base } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 904c81f9215..e11ea7751aa 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -579,9 +579,16 @@ fn is_impossible_method<'tcx>( }); tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| { - let mut fulfill_ctxt = <dyn TraitEngine<'_>>::new(tcx); - fulfill_ctxt.register_predicate_obligations(infcx, predicates_for_trait); - !fulfill_ctxt.select_all_or_error(infcx).is_empty() + for obligation in predicates_for_trait { + // Ignore overflow error, to be conservative. + if let Ok(result) = infcx.evaluate_obligation(&obligation) + && !result.may_apply() + { + return true; + } + } + + false }) } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index aeaccffd5f5..444ca6471e2 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -557,7 +557,10 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // For cases like #95134 we would like to catch overflows early // otherwise they slip away away and cause ICE. let recursion_limit = self.tcx().recursion_limit(); - if !recursion_limit.value_within_limit(self.depth) { + if !recursion_limit.value_within_limit(self.depth) + // HACK: Don't overflow when running cargo doc see #100991 + && !self.tcx().sess.opts.actually_rustdoc + { let obligation = Obligation::with_depth( self.cause.clone(), recursion_limit.0, diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 70b3ba02b05..93cab7ca533 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -1,4 +1,5 @@ use super::{Byte, Def, Ref}; +use std::ops::ControlFlow; #[cfg(test)] mod tests; @@ -86,17 +87,18 @@ where F: Fn(D) -> bool, { match self { - Self::Seq(elts) => elts - .into_iter() - .map(|elt| elt.prune(f)) - .try_fold(Tree::unit(), |elts, elt| { + Self::Seq(elts) => match elts.into_iter().map(|elt| elt.prune(f)).try_fold( + Tree::unit(), + |elts, elt| { if elt == Tree::uninhabited() { - Err(Tree::uninhabited()) + ControlFlow::Break(Tree::uninhabited()) } else { - Ok(elts.then(elt)) + ControlFlow::Continue(elts.then(elt)) } - }) - .into_ok_or_err(), + }, + ) { + ControlFlow::Break(node) | ControlFlow::Continue(node) => node, + }, Self::Alt(alts) => alts .into_iter() .map(|alt| alt.prune(f)) diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 32e6cb9c64f..89b1ce5abe9 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,11 +1,4 @@ -#![feature( - alloc_layout_extra, - control_flow_enum, - decl_macro, - iterator_try_reduce, - never_type, - result_into_ok_or_err -)] +#![feature(alloc_layout_extra, control_flow_enum, decl_macro, iterator_try_reduce, never_type)] #![allow(dead_code, unused_variables)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index caad2ed4274..52fbd3ae047 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -10,6 +10,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } rustc_infer = { path = "../rustc_infer" } +rustc_macros = { path = "../rustc_macros" } rustc_span = { path = "../rustc_span" } rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 7c2f4db94ff..16c4d429129 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -11,6 +11,8 @@ use rustc_target::abi::VariantIdx; use std::iter; +use crate::errors::{GenericConstantTooComplex, GenericConstantTooComplexSub}; + /// Destructures array, ADT or tuple constants into the constants /// of their fields. pub(crate) fn destructure_const<'tcx>( @@ -93,26 +95,25 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.body.exprs[self.body_id].span } - fn error(&mut self, span: Span, msg: &str) -> Result<!, ErrorGuaranteed> { - let reported = self - .tcx - .sess - .struct_span_err(self.root_span(), "overly complex generic constant") - .span_label(span, msg) - .help("consider moving this anonymous constant into a `const` function") - .emit(); + fn error(&mut self, sub: GenericConstantTooComplexSub) -> Result<!, ErrorGuaranteed> { + let reported = self.tcx.sess.emit_err(GenericConstantTooComplex { + span: self.root_span(), + maybe_supported: None, + sub, + }); Err(reported) } - fn maybe_supported_error(&mut self, span: Span, msg: &str) -> Result<!, ErrorGuaranteed> { - let reported = self - .tcx - .sess - .struct_span_err(self.root_span(), "overly complex generic constant") - .span_label(span, msg) - .help("consider moving this anonymous constant into a `const` function") - .note("this operation may be supported in the future") - .emit(); + + fn maybe_supported_error( + &mut self, + sub: GenericConstantTooComplexSub, + ) -> Result<!, ErrorGuaranteed> { + let reported = self.tcx.sess.emit_err(GenericConstantTooComplex { + span: self.root_span(), + maybe_supported: Some(()), + sub, + }); Err(reported) } @@ -243,22 +244,23 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { &ExprKind::Scope { value, .. } => self.recurse_build(value)?, &ExprKind::PlaceTypeAscription { source, .. } | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, - &ExprKind::Literal { lit, neg} => { + &ExprKind::Literal { lit, neg } => { let sp = node.span; - let constant = - match self.tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) { - Ok(c) => c, - Err(LitToConstError::Reported) => { - self.tcx.const_error(node.ty) - } - Err(LitToConstError::TypeError) => { - bug!("encountered type error in lit_to_const") - } - }; + let constant = match self.tcx.at(sp).lit_to_const(LitToConstInput { + lit: &lit.node, + ty: node.ty, + neg, + }) { + Ok(c) => c, + Err(LitToConstError::Reported) => self.tcx.const_error(node.ty), + Err(LitToConstError::TypeError) => { + bug!("encountered type error in lit_to_const") + } + }; self.nodes.push(Node::Leaf(constant)) } - &ExprKind::NonHirLiteral { lit , user_ty: _} => { + &ExprKind::NonHirLiteral { lit, user_ty: _ } => { let val = ty::ValTree::from_scalar_int(lit); self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty))) } @@ -269,19 +271,17 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { &ExprKind::NamedConst { def_id, substs, user_ty: _ } => { let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs); - let constant = self.tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Unevaluated(uneval), - ty: node.ty, - }); + let constant = self + .tcx + .mk_const(ty::ConstS { kind: ty::ConstKind::Unevaluated(uneval), ty: node.ty }); self.nodes.push(Node::Leaf(constant)) } - ExprKind::ConstParam {param, ..} => { - let const_param = self.tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Param(*param), - ty: node.ty, - }); + ExprKind::ConstParam { param, .. } => { + let const_param = self + .tcx + .mk_const(ty::ConstS { kind: ty::ConstKind::Param(*param), ty: node.ty }); self.nodes.push(Node::Leaf(const_param)) } @@ -311,8 +311,15 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // bar::<{ N + 1 }>(); // } // ``` - ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => { - self.recurse_build(*e)? + ExprKind::Block { block } => { + if let thir::Block { stmts: box [], expr: Some(e), .. } = &self.body.blocks[*block] + { + self.recurse_build(*e)? + } else { + self.maybe_supported_error(GenericConstantTooComplexSub::BlockNotSupported( + node.span, + ))? + } } // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a // "coercion cast" i.e. using a coercion or is a no-op. @@ -325,7 +332,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let arg = self.recurse_build(source)?; self.nodes.push(Node::Cast(CastKind::As, arg, node.ty)) } - ExprKind::Borrow{ arg, ..} => { + ExprKind::Borrow { arg, .. } => { let arg_node = &self.body.exprs[*arg]; // Skip reborrows for now until we allow Deref/Borrow/AddressOf @@ -334,80 +341,69 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { if let ExprKind::Deref { arg } = arg_node.kind { self.recurse_build(arg)? } else { - self.maybe_supported_error( + self.maybe_supported_error(GenericConstantTooComplexSub::BorrowNotSupported( node.span, - "borrowing is not supported in generic constants", - )? + ))? } } // FIXME(generic_const_exprs): We may want to support these. - ExprKind::AddressOf { .. } | ExprKind::Deref {..}=> self.maybe_supported_error( - node.span, - "dereferencing or taking the address is not supported in generic constants", - )?, - ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error( - node.span, - "array construction is not supported in generic constants", + ExprKind::AddressOf { .. } | ExprKind::Deref { .. } => self.maybe_supported_error( + GenericConstantTooComplexSub::AddressAndDerefNotSupported(node.span), )?, - ExprKind::Block { .. } => self.maybe_supported_error( - node.span, - "blocks are not supported in generic constant", + ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error( + GenericConstantTooComplexSub::ArrayNotSupported(node.span), )?, ExprKind::NeverToAny { .. } => self.maybe_supported_error( - node.span, - "converting nevers to any is not supported in generic constant", + GenericConstantTooComplexSub::NeverToAnyNotSupported(node.span), )?, ExprKind::Tuple { .. } => self.maybe_supported_error( - node.span, - "tuple construction is not supported in generic constants", + GenericConstantTooComplexSub::TupleNotSupported(node.span), )?, ExprKind::Index { .. } => self.maybe_supported_error( - node.span, - "indexing is not supported in generic constant", + GenericConstantTooComplexSub::IndexNotSupported(node.span), )?, ExprKind::Field { .. } => self.maybe_supported_error( - node.span, - "field access is not supported in generic constant", + GenericConstantTooComplexSub::FieldNotSupported(node.span), )?, ExprKind::ConstBlock { .. } => self.maybe_supported_error( - node.span, - "const blocks are not supported in generic constant", - )?, - ExprKind::Adt(_) => self.maybe_supported_error( - node.span, - "struct/enum construction is not supported in generic constants", + GenericConstantTooComplexSub::ConstBlockNotSupported(node.span), )?, + ExprKind::Adt(_) => self + .maybe_supported_error(GenericConstantTooComplexSub::AdtNotSupported(node.span))?, // dont know if this is correct - ExprKind::Pointer { .. } => - self.error(node.span, "pointer casts are not allowed in generic constants")?, - ExprKind::Yield { .. } => - self.error(node.span, "generator control flow is not allowed in generic constants")?, - ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => self - .error( - node.span, - "loops and loop control flow are not supported in generic constants", - )?, - ExprKind::Box { .. } => - self.error(node.span, "allocations are not allowed in generic constants")?, + ExprKind::Pointer { .. } => { + self.error(GenericConstantTooComplexSub::PointerNotSupported(node.span))? + } + ExprKind::Yield { .. } => { + self.error(GenericConstantTooComplexSub::YieldNotSupported(node.span))? + } + ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => { + self.error(GenericConstantTooComplexSub::LoopNotSupported(node.span))? + } + ExprKind::Box { .. } => { + self.error(GenericConstantTooComplexSub::BoxNotSupported(node.span))? + } ExprKind::Unary { .. } => unreachable!(), // we handle valid unary/binary ops above - ExprKind::Binary { .. } => - self.error(node.span, "unsupported binary operation in generic constants")?, - ExprKind::LogicalOp { .. } => - self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?, + ExprKind::Binary { .. } => { + self.error(GenericConstantTooComplexSub::BinaryNotSupported(node.span))? + } + ExprKind::LogicalOp { .. } => { + self.error(GenericConstantTooComplexSub::LogicalOpNotSupported(node.span))? + } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - self.error(node.span, "assignment is not supported in generic constants")? + self.error(GenericConstantTooComplexSub::AssignNotSupported(node.span))? + } + ExprKind::Closure { .. } | ExprKind::Return { .. } => { + self.error(GenericConstantTooComplexSub::ClosureAndReturnNotSupported(node.span))? } - ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error( - node.span, - "closures and function keywords are not supported in generic constants", - )?, // let expressions imply control flow - ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } => - self.error(node.span, "control flow is not supported in generic constants")?, + ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } => { + self.error(GenericConstantTooComplexSub::ControlFlowNotSupported(node.span))? + } ExprKind::InlineAsm { .. } => { - self.error(node.span, "assembly is not supported in generic constants")? + self.error(GenericConstantTooComplexSub::InlineAsmNotSupported(node.span))? } // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen @@ -415,7 +411,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::UpvarRef { .. } | ExprKind::StaticRef { .. } | ExprKind::ThreadLocalRef(_) => { - self.error(node.span, "unsupported operation in generic constant")? + self.error(GenericConstantTooComplexSub::OperationNotSupported(node.span))? } }) } diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs new file mode 100644 index 00000000000..3a8ef96c991 --- /dev/null +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -0,0 +1,69 @@ +//! Errors emitted by ty_utils + +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_middle::ty::Ty; +use rustc_span::Span; + +#[derive(SessionDiagnostic)] +#[diag(ty_utils::needs_drop_overflow)] +pub struct NeedsDropOverflow<'tcx> { + pub query_ty: Ty<'tcx>, +} + +#[derive(SessionDiagnostic)] +#[diag(ty_utils::generic_constant_too_complex)] +#[help] +pub struct GenericConstantTooComplex { + #[primary_span] + pub span: Span, + #[note(ty_utils::maybe_supported)] + pub maybe_supported: Option<()>, + #[subdiagnostic] + pub sub: GenericConstantTooComplexSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum GenericConstantTooComplexSub { + #[label(ty_utils::borrow_not_supported)] + BorrowNotSupported(#[primary_span] Span), + #[label(ty_utils::address_and_deref_not_supported)] + AddressAndDerefNotSupported(#[primary_span] Span), + #[label(ty_utils::array_not_supported)] + ArrayNotSupported(#[primary_span] Span), + #[label(ty_utils::block_not_supported)] + BlockNotSupported(#[primary_span] Span), + #[label(ty_utils::never_to_any_not_supported)] + NeverToAnyNotSupported(#[primary_span] Span), + #[label(ty_utils::tuple_not_supported)] + TupleNotSupported(#[primary_span] Span), + #[label(ty_utils::index_not_supported)] + IndexNotSupported(#[primary_span] Span), + #[label(ty_utils::field_not_supported)] + FieldNotSupported(#[primary_span] Span), + #[label(ty_utils::const_block_not_supported)] + ConstBlockNotSupported(#[primary_span] Span), + #[label(ty_utils::adt_not_supported)] + AdtNotSupported(#[primary_span] Span), + #[label(ty_utils::pointer_not_supported)] + PointerNotSupported(#[primary_span] Span), + #[label(ty_utils::yield_not_supported)] + YieldNotSupported(#[primary_span] Span), + #[label(ty_utils::loop_not_supported)] + LoopNotSupported(#[primary_span] Span), + #[label(ty_utils::box_not_supported)] + BoxNotSupported(#[primary_span] Span), + #[label(ty_utils::binary_not_supported)] + BinaryNotSupported(#[primary_span] Span), + #[label(ty_utils::logical_op_not_supported)] + LogicalOpNotSupported(#[primary_span] Span), + #[label(ty_utils::assign_not_supported)] + AssignNotSupported(#[primary_span] Span), + #[label(ty_utils::closure_and_return_not_supported)] + ClosureAndReturnNotSupported(#[primary_span] Span), + #[label(ty_utils::control_flow_not_supported)] + ControlFlowNotSupported(#[primary_span] Span), + #[label(ty_utils::inline_asm_not_supported)] + InlineAsmNotSupported(#[primary_span] Span), + #[label(ty_utils::operation_not_supported)] + OperationNotSupported(#[primary_span] Span), +} diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 55d82693994..6931b15b1ba 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -10,6 +10,8 @@ #![feature(never_type)] #![feature(box_patterns)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; @@ -21,6 +23,7 @@ use rustc_middle::ty::query::Providers; mod assoc; mod common_traits; mod consts; +mod errors; mod implied_bounds; pub mod instance; mod needs_drop; diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 9ad44d14d61..ab5a3d8ae48 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -9,6 +9,8 @@ use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; use rustc_session::Limit; use rustc_span::{sym, DUMMY_SP}; +use crate::errors::NeedsDropOverflow; + type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>; fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { @@ -90,10 +92,7 @@ where if !self.recursion_limit.value_within_limit(level) { // Not having a `Span` isn't great. But there's hopefully some other // recursion limit error as well. - tcx.sess.span_err( - DUMMY_SP, - &format!("overflow while checking whether `{}` requires drop", self.query_ty), - ); + tcx.sess.emit_err(NeedsDropOverflow { query_ty: self.query_ty }); return Some(Err(AlwaysRequiresDrop)); } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 44c7c148c75..441a62256de 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1066,16 +1066,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // that had unsatisfied trait bounds if unsatisfied_predicates.is_empty() { let def_kind = lev_candidate.kind.as_def_kind(); - err.span_suggestion( - span, - &format!( - "there is {} {} with a similar name", - def_kind.article(), - def_kind.descr(lev_candidate.def_id), - ), - lev_candidate.name, - Applicability::MaybeIncorrect, - ); + // Methods are defined within the context of a struct and their first parameter is always self, + // which represents the instance of the struct the method is being called on + // Associated functions don’t take self as a parameter and + // they are not methods because they don’t have an instance of the struct to work with. + if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter { + err.span_suggestion( + span, + &format!("there is a method with a similar name",), + lev_candidate.name, + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion( + span, + &format!( + "there is {} {} with a similar name", + def_kind.article(), + def_kind.descr(lev_candidate.def_id), + ), + lev_candidate.name, + Applicability::MaybeIncorrect, + ); + } } } |
